This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / drivers / serial / 8250.c
index 31dd922..2ade801 100644 (file)
  *  membase is an 'ioremapped' cookie.
  */
 #include <linux/config.h>
-
-#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/tty.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/console.h>
 #include <linux/sysrq.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/tty.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/serialP.h>
+#include <linux/delay.h>
+#include <linux/device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 
+#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
 #include "8250.h"
 
 /*
@@ -159,109 +157,23 @@ 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 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,
-       },
-       [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,
-       },
+static const struct serial8250_config uart_config[PORT_MAX_8250+1] = {
+       { "unknown",    1,      1,      0 },
+       { "8250",       1,      1,      0 },
+       { "16450",      1,      1,      0 },
+       { "16550",      1,      1,      0 },
+       { "16550A",     16,     16,     UART_CAP_FIFO },
+       { "Cirrus",     1,      1,      0 },
+       { "ST16650",    1,      1,      UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },
+       { "ST16650V2",  32,     16,     UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },
+       { "TI16750",    64,     64,     UART_CAP_FIFO | UART_CAP_SLEEP },
+       { "Startech",   1,      1,      0 },
+       { "16C950/954", 128,    128,    UART_CAP_FIFO },
+       { "ST16654",    64,     32,     UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },
+       { "XR16850",    128,    128,    UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_EFR },
+       { "RSA",        2048,   2048,   UART_CAP_FIFO },
+       { "NS16550A",   16,     16,     UART_CAP_FIFO | UART_NATSEMI },
+       { "XScale",     32,     32,     UART_CAP_FIFO },
 };
 
 static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
@@ -492,11 +404,6 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
 {
        unsigned char id1, id2, id3, rev, saved_dll, saved_dlm;
 
-       /*
-        * 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.
         *
@@ -607,7 +514,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
        unsigned char status1, status2;
 
        up->port.type = PORT_16550A;
-       up->capabilities |= UART_CAP_FIFO;
 
        /*
         * Check for presence of the EFR when DLAB is set.
@@ -619,7 +525,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
                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 ");
                }
@@ -672,7 +577,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 #endif
 
                        up->port.type = PORT_NS16550A;
-                       up->capabilities |= UART_NATSEMI;
                        return;
                }
        }
@@ -696,7 +600,6 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 
        if (status1 == 6 && status2 == 7) {
                up->port.type = PORT_16750;
-               up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP;
                return;
        }
 }
@@ -727,8 +630,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
        spin_lock_irqsave(&up->port.lock, flags);
 //     save_flags(flags); cli();
 
-       up->capabilities = 0;
-
        if (!(up->port.flags & UPF_BUGGY_UART)) {
                /*
                 * Do a simple existence test first; if we fail this,
@@ -839,13 +740,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
 #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",
-                       up->port.line, 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;
@@ -928,12 +822,6 @@ static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
                up->ier &= ~UART_IER_THRI;
                serial_out(up, UART_IER, up->ier);
        }
-
-       /*
-        * We only do this from uart_stop - if we run out of
-        * characters to send, we don't want to prevent the
-        * FIFO from emptying.
-        */
        if (up->port.type == PORT_16C950 && tty_stop) {
                up->acr |= UART_ACR_TXDIS;
                serial_icr_write(up, UART_ACR, up->acr);
@@ -978,40 +866,27 @@ static _INLINE_ void
 receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
 {
        struct tty_struct *tty = up->port.info->tty;
-       unsigned char ch, lsr = *status;
+       unsigned char ch;
        int max_count = 256;
-       char flag;
 
        do {
-               /* The following is not allowed by the tty layer and
-                  unsafe. It should be fixed ASAP */
                if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) {
-                       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 */
+                       tty->flip.work.func((void *)tty);
+                       if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                               return; // if TTY_DONT_FLIP is set
                }
                ch = serial_inp(up, UART_RX);
-               flag = TTY_NORMAL;
+               *tty->flip.char_buf_ptr = ch;
+               *tty->flip.flag_buf_ptr = TTY_NORMAL;
                up->port.icount.rx++;
 
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-               /*
-                * Recover the break flag from console xmit
-                */
-               if (up->port.line == up->port.cons->index) {
-                       lsr |= up->lsr_break_flag;
-                       up->lsr_break_flag = 0;
-               }
-#endif
-
-               if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
-                                   UART_LSR_FE | UART_LSR_OE))) {
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+                                      UART_LSR_FE | UART_LSR_OE))) {
                        /*
                         * For statistics only
                         */
-                       if (lsr & UART_LSR_BI) {
-                               lsr &= ~(UART_LSR_FE | UART_LSR_PE);
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
                                up->port.icount.brk++;
                                /*
                                 * We do the SysRQ and SAK checking
@@ -1021,45 +896,56 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
                                 */
                                if (uart_handle_break(&up->port))
                                        goto ignore_char;
-                       } else if (lsr & UART_LSR_PE)
+                       } else if (*status & UART_LSR_PE)
                                up->port.icount.parity++;
-                       else if (lsr & UART_LSR_FE)
+                       else if (*status & UART_LSR_FE)
                                up->port.icount.frame++;
-                       if (lsr & UART_LSR_OE)
+                       if (*status & UART_LSR_OE)
                                up->port.icount.overrun++;
 
                        /*
                         * Mask off conditions which should be ingored.
                         */
-                       lsr &= up->port.read_status_mask;
+                       *status &= up->port.read_status_mask;
 
-                       if (lsr & UART_LSR_BI) {
+#ifdef CONFIG_SERIAL_8250_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) {
                                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;
+                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                       } else if (*status & UART_LSR_PE)
+                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               *tty->flip.flag_buf_ptr = TTY_FRAME;
                }
                if (uart_handle_sysrq_char(&up->port, ch, regs))
                        goto ignore_char;
-               if ((lsr & up->port.ignore_status_mask) == 0) {
-                       tty_insert_flip_char(tty, ch, flag);
+               if ((*status & up->port.ignore_status_mask) == 0) {
+                       tty->flip.flag_buf_ptr++;
+                       tty->flip.char_buf_ptr++;
+                       tty->flip.count++;
                }
-               if ((lsr & UART_LSR_OE) &&
+               if ((*status & UART_LSR_OE) &&
                    tty->flip.count < TTY_FLIPBUF_SIZE) {
                        /*
                         * Overrun is special, since it's reported
                         * immediately, and doesn't affect the current
                         * character.
                         */
-                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+                       *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+                       tty->flip.flag_buf_ptr++;
+                       tty->flip.char_buf_ptr++;
+                       tty->flip.count++;
                }
        ignore_char:
-               lsr = serial_inp(up, UART_LSR);
-       } while ((lsr & UART_LSR_DR) && (max_count-- > 0));
+               *status = serial_inp(up, UART_LSR);
+       } while ((*status & UART_LSR_DR) && (max_count-- > 0));
        tty_flip_buffer_push(tty);
-       *status = lsr;
 }
 
 static _INLINE_ void transmit_chars(struct uart_8250_port *up)
@@ -1152,7 +1038,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r
 {
        struct irq_info *i = dev_id;
        struct list_head *l, *end = NULL;
-       int pass_counter = 0, handled = 0;
+       int pass_counter = 0;
 
        DEBUG_INTR("serial8250_interrupt(%d)...", irq);
 
@@ -1171,8 +1057,6 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r
                        serial8250_handle_port(up, regs);
                        spin_unlock(&up->port.lock);
 
-                       handled = 1;
-
                        end = NULL;
                } else if (end == NULL)
                        end = l;
@@ -1190,8 +1074,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r
        spin_unlock(&i->lock);
 
        DEBUG_INTR("end.\n");
-
-       return IRQ_RETVAL(handled);
+       /* FIXME! Was it really ours? */
+       return IRQ_HANDLED;
 }
 
 /*
@@ -1609,22 +1493,25 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
        if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
                if (baud < 2400)
                        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_config[up->port.type].fcr;
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
        }
 
        /*
-        * 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.
+        * TI16C750: hardware flow control and 64 byte FIFOs. 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.
         */
-       if (up->capabilities & UART_CAP_AFE && up->port.fifosize >= 32) {
+       if (up->port.type == PORT_16750) {
                up->mcr &= ~UART_MCR_AFE;
                if (termios->c_cflag & CRTSCTS)
                        up->mcr |= UART_MCR_AFE;
+
+               fcr |= UART_FCR7_64BYTE;
        }
 
        /*
@@ -1678,17 +1565,9 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
        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, 0xBF);
-               serial_outp(up, UART_EFR, efr);
+               serial_outp(up, UART_EFR,
+                           termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0);
        }
 
        if (up->capabilities & UART_NATSEMI) {
@@ -1734,80 +1613,59 @@ serial8250_pm(struct uart_port *port, unsigned int state,
 }
 
 /*
- * Resource handling.
+ * 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 serial8250_request_std_resource(struct uart_8250_port *up)
+static int
+serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res)
 {
        unsigned int size = 8 << up->port.regshift;
        int ret = 0;
 
        switch (up->port.iotype) {
        case UPIO_MEM:
-               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(up->port.mapbase, size);
-                       if (!up->port.membase) {
-                               release_mem_region(up->port.mapbase, size);
-                               ret = -ENOMEM;
-                       }
+               if (up->port.mapbase) {
+                       *res = request_mem_region(up->port.mapbase, size, "serial");
+                       if (!*res)
+                               ret = -EBUSY;
                }
                break;
 
        case UPIO_HUB6:
        case UPIO_PORT:
-               if (!request_region(up->port.iobase, size, "serial"))
+               *res = request_region(up->port.iobase, size, "serial");
+               if (!*res)
                        ret = -EBUSY;
                break;
        }
        return ret;
 }
 
-static void serial8250_release_std_resource(struct uart_8250_port *up)
-{
-       unsigned int size = 8 << up->port.regshift;
-
-       switch (up->port.iotype) {
-       case UPIO_MEM:
-               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)
+static int
+serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res)
 {
-       unsigned long start = UART_RSA_BASE << up->port.regshift;
        unsigned int size = 8 << up->port.regshift;
+       unsigned long start;
        int ret = 0;
 
        switch (up->port.iotype) {
        case UPIO_MEM:
-               ret = -EINVAL;
+               if (up->port.mapbase) {
+                       start = up->port.mapbase;
+                       start += UART_RSA_BASE << up->port.regshift;
+                       *res = request_mem_region(start, size, "serial-rsa");
+                       if (!*res)
+                               ret = -EBUSY;
+               }
                break;
 
        case UPIO_HUB6:
        case UPIO_PORT:
-               start += up->port.iobase;
-               if (!request_region(start, size, "serial-rsa"))
+               start = up->port.iobase;
+               start += UART_RSA_BASE << up->port.regshift;
+               *res = request_region(start, size, "serial-rsa");
+               if (!*res)
                        ret = -EBUSY;
                break;
        }
@@ -1815,49 +1673,87 @@ static int serial8250_request_rsa_resource(struct uart_8250_port *up)
        return ret;
 }
 
-static void serial8250_release_rsa_resource(struct uart_8250_port *up)
+static void serial8250_release_port(struct uart_port *port)
 {
-       unsigned long offset = UART_RSA_BASE << up->port.regshift;
-       unsigned int size = 8 << up->port.regshift;
+       struct uart_8250_port *up = (struct uart_8250_port *)port;
+       unsigned long start, offset = 0, size = 0;
+
+       if (up->port.type == PORT_RSA) {
+               offset = UART_RSA_BASE << up->port.regshift;
+               size = 8;
+       }
+
+       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_HUB6:
        case UPIO_PORT:
-               release_region(up->port.iobase + offset, size);
-               break;
-       }
-}
+               start = up->port.iobase;
 
-static void serial8250_release_port(struct uart_port *port)
-{
-       struct uart_8250_port *up = (struct uart_8250_port *)port;
+               if (size)
+                       release_region(start + offset, size);
+               release_region(start + offset, 8 << up->port.regshift);
+               break;
 
-       serial8250_release_std_resource(up);
-       if (up->port.type == PORT_RSA)
-               serial8250_release_rsa_resource(up);
+       default:
+               break;
+       }
 }
 
 static int serial8250_request_port(struct uart_port *port)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
+       struct resource *res = NULL, *res_rsa = NULL;
        int ret = 0;
 
-       ret = serial8250_request_std_resource(up);
-       if (ret == 0 && up->port.type == PORT_RSA) {
-               ret = serial8250_request_rsa_resource(up);
+       if (up->port.type == PORT_RSA) {
+               ret = serial8250_request_rsa_resource(up, &res_rsa);
                if (ret < 0)
-                       serial8250_release_std_resource(up);
+                       return ret;
        }
 
+       ret = serial8250_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_rsa)
+                       release_resource(res_rsa);
+               if (res)
+                       release_resource(res);
+       }
        return ret;
 }
 
 static void serial8250_config_port(struct uart_port *port, int flags)
 {
        struct uart_8250_port *up = (struct uart_8250_port *)port;
+       struct resource *res_std = NULL, *res_rsa = NULL;
        int probeflags = PROBE_ANY;
        int ret;
 
@@ -1873,11 +1769,11 @@ static void serial8250_config_port(struct uart_port *port, int flags)
         * 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);
+       ret = serial8250_request_std_resource(up, &res_std);
        if (ret < 0)
                return;
 
-       ret = serial8250_request_rsa_resource(up);
+       ret = serial8250_request_rsa_resource(up, &res_rsa);
        if (ret < 0)
                probeflags &= ~PROBE_RSA;
 
@@ -1886,10 +1782,14 @@ static void serial8250_config_port(struct uart_port *port, int flags)
        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);
+       /*
+        * If the port wasn't an RSA port, release the resource.
+        */
+       if (up->port.type != PORT_RSA && res_rsa)
+               release_resource(res_rsa);
+
+       if (up->port.type == PORT_UNKNOWN && res_std)
+               release_resource(res_std);
 }
 
 static int
@@ -1897,7 +1797,7 @@ 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_MAX_8250 || ser->type == PORT_CIRRUS ||
            ser->type == PORT_STARTECH)
                return -EINVAL;
        return 0;
@@ -1945,24 +1845,6 @@ static void __init serial8250_isa_init_ports(void)
                return;
        first = 0;
 
-       for (i = 0; i < UART_NR; 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;
-       }
-
        for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port);
             i++, up++) {
                up->port.iobase   = old_serial_port[i].port;
@@ -1973,13 +1855,13 @@ static void __init serial8250_isa_init_ports(void)
                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      = &serial8250_pops;
                if (share_irqs)
                        up->port.flags |= UPF_SHARE_IRQ;
        }
 }
 
-static void __init
-serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+static void __init serial8250_register_ports(struct uart_driver *drv)
 {
        int i;
 
@@ -1988,7 +1870,17 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
        for (i = 0; i < UART_NR; i++) {
                struct uart_8250_port *up = &serial8250_ports[i];
 
-               up->port.dev = dev;
+               up->port.line = i;
+               up->port.ops = &serial8250_pops;
+               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;
+
                uart_add_one_port(drv, &up->port);
        }
 }
@@ -2073,7 +1965,7 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
        serial_out(up, UART_IER, ier);
 }
 
-static int serial8250_console_setup(struct console *co, char *options)
+static int __init serial8250_console_setup(struct console *co, char *options)
 {
        struct uart_port *port;
        int baud = 9600;
@@ -2089,9 +1981,14 @@ static int serial8250_console_setup(struct console *co, char *options)
        if (co->index >= UART_NR)
                co->index = 0;
        port = &serial8250_ports[co->index].port;
-       if (!port->iobase && !port->membase)
+       if (!port->ops)
                return -ENODEV;
 
+       /*
+        * Temporary fix.
+        */
+       spin_lock_init(&port->lock);
+
        if (options)
                uart_parse_options(options, &baud, &parity, &bits, &flow);
 
@@ -2125,41 +2022,6 @@ static int __init serial8250_late_console_init(void)
 }
 late_initcall(serial8250_late_console_init);
 
-static int __init find_port(struct uart_port *p)
-{
-       int line;
-       struct uart_port *port;
-
-       for (line = 0; line < UART_NR; line++) {
-               port = &serial8250_ports[line].port;
-               if (p->iotype == port->iotype &&
-                   p->iobase == port->iobase &&
-                   p->membase == port->membase)
-                       return line;
-       }
-       return -ENODEV;
-}
-
-int __init serial8250_start_console(struct uart_port *port, char *options)
-{
-       int line;
-
-       line = find_port(port);
-       if (line < 0)
-               return -ENODEV;
-
-       add_preferred_console("ttyS", line, options);
-       printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",
-               line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
-               port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :
-                   (unsigned long) port->iobase, options);
-       if (!(serial8250_console.flags & CON_ENABLED)) {
-               serial8250_console.flags &= ~CON_PRINTBUFFER;
-               register_console(&serial8250_console);
-       }
-       return line;
-}
-
 #define SERIAL8250_CONSOLE     &serial8250_console
 #else
 #define SERIAL8250_CONSOLE     NULL
@@ -2176,267 +2038,120 @@ static struct uart_driver serial8250_reg = {
        .cons                   = SERIAL8250_CONSOLE,
 };
 
-int __init early_serial_setup(struct uart_port *port)
-{
-       if (port->line >= ARRAY_SIZE(serial8250_ports))
-               return -ENODEV;
-
-       serial8250_isa_init_ports();
-       serial8250_ports[port->line].port       = *port;
-       serial8250_ports[port->line].port.ops   = &serial8250_pops;
-       return 0;
-}
-
-/**
- *     serial8250_suspend_port - suspend one serial port
- *     @line:  serial line number
- *      @level: the level of port suspension, as per uart_suspend_port
- *
- *     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
- *      @level: the level of port resumption, as per uart_resume_port
- *
- *     Resume one serial port.
- */
-void serial8250_resume_port(int line)
-{
-       uart_resume_port(&serial8250_reg, &serial8250_ports[line].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.
+ * register_serial and unregister_serial allows for 16x50 serial ports to be
+ * configured at run-time, to support PCMCIA modems.
  */
-static int __devinit serial8250_probe(struct device *dev)
+
+static int __register_serial(struct serial_struct *req, int line)
 {
-       struct plat_serial8250_port *p = dev->platform_data;
        struct uart_port port;
 
-       memset(&port, 0, sizeof(struct uart_port));
-
-       for (; p && p->flags != 0; p++) {
-               port.iobase     = p->iobase;
-               port.membase    = p->membase;
-               port.irq        = p->irq;
-               port.uartclk    = p->uartclk;
-               port.regshift   = p->regshift;
-               port.iotype     = p->iotype;
-               port.flags      = p->flags;
-               port.mapbase    = p->mapbase;
-               port.dev        = dev;
-               if (share_irqs)
-                       port.flags |= UPF_SHARE_IRQ;
-               serial8250_register_port(&port);
-       }
-       return 0;
-}
+       port.iobase   = req->port;
+       port.membase  = req->iomem_base;
+       port.irq      = req->irq;
+       port.uartclk  = req->baud_base * 16;
+       port.fifosize = req->xmit_fifo_size;
+       port.regshift = req->iomem_reg_shift;
+       port.iotype   = req->io_type;
+       port.flags    = req->flags | UPF_BOOT_AUTOCONF;
+       port.mapbase  = req->iomap_base;
+       port.line     = line;
 
-/*
- * Remove serial ports registered against a platform device.
- */
-static int __devexit serial8250_remove(struct device *dev)
-{
-       int i;
+       if (share_irqs)
+               port.flags |= UPF_SHARE_IRQ;
 
-       for (i = 0; i < UART_NR; i++) {
-               struct uart_8250_port *up = &serial8250_ports[i];
+       if (HIGH_BITS_OFFSET)
+               port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
 
-               if (up->port.dev == dev)
-                       serial8250_unregister_port(i);
-       }
-       return 0;
+       /*
+        * If a clock rate wasn't specified by the low level
+        * driver, then default to the standard clock rate.
+        */
+       if (port.uartclk == 0)
+               port.uartclk = BASE_BAUD * 16;
+
+       return uart_register_port(&serial8250_reg, &port);
 }
 
-static int serial8250_suspend(struct device *dev, u32 state, u32 level)
+/**
+ *     register_serial - configure a 16x50 serial port at runtime
+ *     @req: request structure
+ *
+ *     Configure the serial port specified by the request. If the
+ *     port exists and is in use an error is returned. If the port
+ *     is not currently in the table it is added.
+ *
+ *     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 register_serial(struct serial_struct *req)
 {
-       int i;
-
-       if (level != SUSPEND_DISABLE)
-               return 0;
-
-       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)
-                       uart_suspend_port(&serial8250_reg, &up->port);
-       }
-
-       return 0;
+       return __register_serial(req, -1);
 }
 
-static int serial8250_resume(struct device *dev, u32 level)
+int __init early_serial_setup(struct uart_port *port)
 {
-       int i;
-
-       if (level != RESUME_ENABLE)
-               return 0;
-
-       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)
-                       uart_resume_port(&serial8250_reg, &up->port);
-       }
+       if (port->line >= ARRAY_SIZE(serial8250_ports))
+               return -ENODEV;
 
+       serial8250_isa_init_ports();
+       serial8250_ports[port->line].port       = *port;
+       serial8250_ports[port->line].port.ops   = &serial8250_pops;
        return 0;
 }
 
-static struct device_driver serial8250_isa_driver = {
-       .name           = "serial8250",
-       .bus            = &platform_bus_type,
-       .probe          = serial8250_probe,
-       .remove         = __devexit_p(serial8250_remove),
-       .suspend        = serial8250_suspend,
-       .resume         = serial8250_resume,
-};
-
-/*
- * 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 DECLARE_MUTEX(serial_sem);
-
-/*
- *     Are the two ports equivalent?
+/**
+ *     unregister_serial - remove a 16x50 serial port at runtime
+ *     @line: serial line number
+ *
+ *     Remove one serial port.  This may be called from interrupt
+ *     context.
  */
-static int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+void unregister_serial(int line)
 {
-       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:
-               return (port1->membase == port2->membase);
-       }
-       return 0;
+       uart_unregister_port(&serial8250_reg, line);
 }
 
-static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
+/*
+ * This is for ISAPNP only.
+ */
+void serial8250_get_irq_map(unsigned int *map)
 {
        int i;
 
-       /*
-        * First, find a port entry which matches.
-        */
-       for (i = 0; i < UART_NR; 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 < UART_NR; 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 < UART_NR; i++)
-               if (serial8250_ports[i].port.type == PORT_UNKNOWN)
-                       return &serial8250_ports[i];
-
-       return NULL;
+       for (i = 0; i < UART_NR; i++) {
+               if (serial8250_ports[i].port.type != PORT_UNKNOWN &&
+                   serial8250_ports[i].port.irq < 16)
+                       *map |= 1 << serial8250_ports[i].port.irq;
+       }
 }
 
 /**
- *     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.
+ *     serial8250_suspend_port - suspend one serial port
+ *     @line:  serial line number
+ *      @level: the level of port suspension, as per uart_suspend_port
  *
- *     On success the port is ready to use and the line number is returned.
+ *     Suspend one serial port.
  */
-int serial8250_register_port(struct uart_port *port)
+void serial8250_suspend_port(int line)
 {
-       struct uart_8250_port *uart;
-       int ret = -ENOSPC;
-
-       if (port->uartclk == 0)
-               return -EINVAL;
-
-       down(&serial_sem);
-
-       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.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;
-               if (port->dev)
-                       uart->port.dev = port->dev;
-
-               ret = uart_add_one_port(&serial8250_reg, &uart->port);
-               if (ret == 0)
-                       ret = uart->port.line;
-       }
-       up(&serial_sem);
-
-       return ret;
+       uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
 }
-EXPORT_SYMBOL(serial8250_register_port);
 
 /**
- *     serial8250_unregister_port - remove a 16x50 serial port at runtime
- *     @line: serial line number
+ *     serial8250_resume_port - resume one serial port
+ *     @line:  serial line number
+ *      @level: the level of port resumption, as per uart_resume_port
  *
- *     Remove one serial port.  This may not be called from interrupt
- *     context.  We hand the port back to the our control.
+ *     Resume one serial port.
  */
-void serial8250_unregister_port(int line)
+void serial8250_resume_port(int line)
 {
-       struct uart_8250_port *uart = &serial8250_ports[line];
-
-       down(&serial_sem);
-       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;
-       }
-       up(&serial_sem);
+       uart_resume_port(&serial8250_reg, &serial8250_ports[line].port);
 }
-EXPORT_SYMBOL(serial8250_unregister_port);
 
 static int __init serial8250_init(void)
 {
@@ -2450,42 +2165,18 @@ static int __init serial8250_init(void)
                spin_lock_init(&irq_lists[i].lock);
 
        ret = uart_register_driver(&serial8250_reg);
-       if (ret)
-               goto out;
-
-       serial8250_isa_devs = platform_device_register_simple("serial8250",
-                                                             -1, NULL, 0);
-       if (IS_ERR(serial8250_isa_devs)) {
-               ret = PTR_ERR(serial8250_isa_devs);
-               goto unreg;
-       }
-
-       serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
-
-       ret = driver_register(&serial8250_isa_driver);
-       if (ret == 0)
-               goto out;
+       if (ret >= 0)
+               serial8250_register_ports(&serial8250_reg);
 
-       platform_device_unregister(serial8250_isa_devs);
- unreg:
-       uart_unregister_driver(&serial8250_reg);
- 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;
+       int i;
 
-       driver_unregister(&serial8250_isa_driver);
-       platform_device_unregister(isa_dev);
+       for (i = 0; i < UART_NR; i++)
+               uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port);
 
        uart_unregister_driver(&serial8250_reg);
 }
@@ -2493,6 +2184,9 @@ static void __exit serial8250_exit(void)
 module_init(serial8250_init);
 module_exit(serial8250_exit);
 
+EXPORT_SYMBOL(register_serial);
+EXPORT_SYMBOL(unregister_serial);
+EXPORT_SYMBOL(serial8250_get_irq_map);
 EXPORT_SYMBOL(serial8250_suspend_port);
 EXPORT_SYMBOL(serial8250_resume_port);
 
@@ -2504,80 +2198,7 @@ MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
        " (unsafe)");
 
 #ifdef CONFIG_SERIAL_8250_RSA
-module_param_array(probe_rsa, ulong, &probe_rsa_count, 0444);
+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);
-
-/**
- *     register_serial - configure a 16x50 serial port at runtime
- *     @req: request structure
- *
- *     Configure the serial port specified by the request. If the
- *     port exists and is in use an error is returned. If the port
- *     is not currently in the table it is added.
- *
- *     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 register_serial(struct serial_struct *req)
-{
-       struct uart_port port;
-
-       port.iobase   = req->port;
-       port.membase  = req->iomem_base;
-       port.irq      = req->irq;
-       port.uartclk  = req->baud_base * 16;
-       port.fifosize = req->xmit_fifo_size;
-       port.regshift = req->iomem_reg_shift;
-       port.iotype   = req->io_type;
-       port.flags    = req->flags | UPF_BOOT_AUTOCONF;
-       port.mapbase  = req->iomap_base;
-       port.dev      = NULL;
-
-       if (share_irqs)
-               port.flags |= UPF_SHARE_IRQ;
-
-       if (HIGH_BITS_OFFSET)
-               port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
-
-       /*
-        * If a clock rate wasn't specified by the low level driver, then
-        * default to the standard clock rate.  This should be 115200 (*16)
-        * and should not depend on the architecture's BASE_BAUD definition.
-        * However, since this API will be deprecated, it's probably a
-        * better idea to convert the drivers to use the new API
-        * (serial8250_register_port and serial8250_unregister_port).
-        */
-       if (port.uartclk == 0) {
-               printk(KERN_WARNING
-                      "Serial: registering port at [%08x,%08lx,%p] irq %d with zero baud_base\n",
-                      port.iobase, port.mapbase, port.membase, port.irq);
-               printk(KERN_WARNING "Serial: see %s:%d for more information\n",
-                      __FILE__, __LINE__);
-               dump_stack();
-
-               /*
-                * Fix it up for now, but this is only a temporary measure.
-                */
-               port.uartclk = BASE_BAUD * 16;
-       }
-
-       return serial8250_register_port(&port);
-}
-EXPORT_SYMBOL(register_serial);
-
-/**
- *     unregister_serial - 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 our local PM control.
- */
-void unregister_serial(int line)
-{
-       serial8250_unregister_port(line);
-}
-EXPORT_SYMBOL(unregister_serial);