Merge branch 'for-2.6.35' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[safe/jmp/linux-2.6] / drivers / char / mxser.c
index 57570f7..d2692d4 100644 (file)
@@ -14,7 +14,8 @@
  *      (at your option) any later version.
  *
  *     Fed through a cleanup, indent and remove of non 2.6 code by Alan Cox
- *     <alan@redhat.com>. The original 1.8 code is available on www.moxa.com.
+ *     <alan@lxorguk.ukuu.org.uk>. The original 1.8 code is available on
+ *     www.moxa.com.
  *     - Fixed x86_64 cleanness
  */
 
 #include <linux/string.h>
 #include <linux/fcntl.h>
 #include <linux/ptrace.h>
-#include <linux/gfp.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/bitops.h>
+#include <linux/slab.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -46,9 +47,8 @@
 
 #include "mxser.h"
 
-#define        MXSER_VERSION   "2.0.4"         /* 1.12 */
+#define        MXSER_VERSION   "2.0.5"         /* 1.14 */
 #define        MXSERMAJOR       174
-#define        MXSERCUMAJOR     175
 
 #define MXSER_BOARDS           4       /* Max. boards */
 #define MXSER_PORTS_PER_BOARD  8       /* Max. ports per board */
@@ -68,6 +68,7 @@
 #define PCI_DEVICE_ID_POS104UL 0x1044
 #define PCI_DEVICE_ID_CB108    0x1080
 #define PCI_DEVICE_ID_CP102UF  0x1023
+#define PCI_DEVICE_ID_CP112UL  0x1120
 #define PCI_DEVICE_ID_CB114    0x1142
 #define PCI_DEVICE_ID_CP114UL  0x1143
 #define PCI_DEVICE_ID_CB134I   0x1341
@@ -138,7 +139,8 @@ static const struct mxser_cardinfo mxser_cards[] = {
        { "CP-138U series",     8, },
        { "POS-104UL series",   4, },
        { "CP-114UL series",    4, },
-/*30*/ { "CP-102UF series",    2, }
+/*30*/ { "CP-102UF series",    2, },
+       { "CP-112UL series",    2, },
 };
 
 /* driver_data correspond to the lines in the structure above
@@ -169,18 +171,20 @@ static struct pci_device_id mxser_pcibrds[] = {
        { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL),    .driver_data = 28 },
        { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL),     .driver_data = 29 },
        { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF),     .driver_data = 30 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL),     .driver_data = 31 },
        { }
 };
 MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
 
-static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
+static unsigned long ioaddr[MXSER_BOARDS];
 static int ttymajor = MXSERMAJOR;
 
 /* Variables for insmod */
 
 MODULE_AUTHOR("Casper Yang");
 MODULE_DESCRIPTION("MOXA Smartio/Industio Family Multiport Board Device Driver");
-module_param_array(ioaddr, int, NULL, 0);
+module_param_array(ioaddr, ulong, NULL, 0);
+MODULE_PARM_DESC(ioaddr, "ISA io addresses to look for a moxa board");
 module_param(ttymajor, int, 0);
 MODULE_LICENSE("GPL");
 
@@ -190,7 +194,6 @@ struct mxser_log {
        unsigned long txcnt[MXSER_PORTS];
 };
 
-
 struct mxser_mon {
        unsigned long rxcnt;
        unsigned long txcnt;
@@ -257,7 +260,6 @@ struct mxser_port {
        struct mxser_mon mon_data;
 
        spinlock_t slock;
-       wait_queue_head_t delta_msr_wait;
 };
 
 struct mxser_board {
@@ -281,11 +283,6 @@ struct mxser_mstatus {
        int dcd;
 };
 
-static int mxserBoardCAP[MXSER_BOARDS] = {
-       0, 0, 0, 0
-       /*  0x180, 0x280, 0x200, 0x320 */
-};
-
 static struct mxser_board mxser_boards[MXSER_BOARDS];
 static struct tty_driver *mxvar_sdriver;
 static struct mxser_log mxvar_log;
@@ -546,85 +543,34 @@ static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
        return status;
 }
 
-static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
-               struct mxser_port *port)
+static int mxser_carrier_raised(struct tty_port *port)
 {
-       DECLARE_WAITQUEUE(wait, current);
-       int retval;
-       int do_clocal = 0;
-       unsigned long flags;
-
-       /*
-        * 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) ||
-                       test_bit(TTY_IO_ERROR, &tty->flags)) {
-               port->port.flags |= ASYNC_NORMAL_ACTIVE;
-               return 0;
-       }
+       struct mxser_port *mp = container_of(port, struct mxser_port, port);
+       return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
+}
 
-       if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
+static void mxser_dtr_rts(struct tty_port *port, int on)
+{
+       struct mxser_port *mp = container_of(port, struct mxser_port, port);
+       unsigned long flags;
 
-       /*
-        * Block waiting for the carrier detect and the line to become
-        * free (i.e., not in use by the callout).  While we are in
-        * this loop, port->port.count is dropped by one, so that
-        * mxser_close() knows when to free things.  We restore it upon
-        * exit, either normal or abnormal.
-        */
-       retval = 0;
-       add_wait_queue(&port->port.open_wait, &wait);
-
-       spin_lock_irqsave(&port->slock, flags);
-       if (!tty_hung_up_p(filp))
-               port->port.count--;
-       spin_unlock_irqrestore(&port->slock, flags);
-       port->port.blocked_open++;
-       while (1) {
-               spin_lock_irqsave(&port->slock, flags);
-               outb(inb(port->ioaddr + UART_MCR) |
-                       UART_MCR_DTR | UART_MCR_RTS, port->ioaddr + UART_MCR);
-               spin_unlock_irqrestore(&port->slock, flags);
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (tty_hung_up_p(filp) || !(port->port.flags & ASYNC_INITIALIZED)) {
-                       if (port->port.flags & ASYNC_HUP_NOTIFY)
-                               retval = -EAGAIN;
-                       else
-                               retval = -ERESTARTSYS;
-                       break;
-               }
-               if (!(port->port.flags & ASYNC_CLOSING) &&
-                               (do_clocal ||
-                               (inb(port->ioaddr + UART_MSR) & UART_MSR_DCD)))
-                       break;
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               }
-               schedule();
-       }
-       set_current_state(TASK_RUNNING);
-       remove_wait_queue(&port->port.open_wait, &wait);
-       if (!tty_hung_up_p(filp))
-               port->port.count++;
-       port->port.blocked_open--;
-       if (retval)
-               return retval;
-       port->port.flags |= ASYNC_NORMAL_ACTIVE;
-       return 0;
+       spin_lock_irqsave(&mp->slock, flags);
+       if (on)
+               outb(inb(mp->ioaddr + UART_MCR) |
+                       UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
+       else
+               outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS),
+                       mp->ioaddr + UART_MCR);
+       spin_unlock_irqrestore(&mp->slock, flags);
 }
 
-static int mxser_set_baud(struct mxser_port *info, long newspd)
+static int mxser_set_baud(struct tty_struct *tty, long newspd)
 {
+       struct mxser_port *info = tty->driver_data;
        int quot = 0, baud;
        unsigned char cval;
 
-       if (!info->port.tty || !info->port.tty->termios)
-               return -1;
-
-       if (!(info->ioaddr))
+       if (!info->ioaddr)
                return -1;
 
        if (newspd > info->max_baud)
@@ -632,13 +578,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
 
        if (newspd == 134) {
                quot = 2 * info->baud_base / 269;
-               tty_encode_baud_rate(info->port.tty, 134, 134);
+               tty_encode_baud_rate(tty, 134, 134);
        } else if (newspd) {
                quot = info->baud_base / newspd;
                if (quot == 0)
                        quot = 1;
                baud = info->baud_base/quot;
-               tty_encode_baud_rate(info->port.tty, baud, baud);
+               tty_encode_baud_rate(tty, baud, baud);
        } else {
                quot = 0;
        }
@@ -664,7 +610,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
        outb(cval, info->ioaddr + UART_LCR);    /* reset DLAB */
 
 #ifdef BOTHER
-       if (C_BAUD(info->port.tty) == BOTHER) {
+       if (C_BAUD(tty) == BOTHER) {
                quot = info->baud_base % newspd;
                quot *= 8;
                if (quot % newspd > newspd / 2) {
@@ -685,21 +631,20 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
-static int mxser_change_speed(struct mxser_port *info,
-               struct ktermios *old_termios)
+static int mxser_change_speed(struct tty_struct *tty,
+                                       struct ktermios *old_termios)
 {
+       struct mxser_port *info = tty->driver_data;
        unsigned cflag, cval, fcr;
        int ret = 0;
        unsigned char status;
 
-       if (!info->port.tty || !info->port.tty->termios)
-               return ret;
-       cflag = info->port.tty->termios->c_cflag;
-       if (!(info->ioaddr))
+       cflag = tty->termios->c_cflag;
+       if (!info->ioaddr)
                return ret;
 
-       if (mxser_set_baud_method[info->port.tty->index] == 0)
-               mxser_set_baud(info, tty_get_baud_rate(info->port.tty));
+       if (mxser_set_baud_method[tty->index] == 0)
+               mxser_set_baud(tty, tty_get_baud_rate(tty));
 
        /* byte size and parity */
        switch (cflag & CSIZE) {
@@ -768,9 +713,9 @@ static int mxser_change_speed(struct mxser_port *info,
                        info->MCR |= UART_MCR_AFE;
                } else {
                        status = inb(info->ioaddr + UART_MSR);
-                       if (info->port.tty->hw_stopped) {
+                       if (tty->hw_stopped) {
                                if (status & UART_MSR_CTS) {
-                                       info->port.tty->hw_stopped = 0;
+                                       tty->hw_stopped = 0;
                                        if (info->type != PORT_16550A &&
                                                        !info->board->chip_flag) {
                                                outb(info->IER & ~UART_IER_THRI,
@@ -780,11 +725,11 @@ static int mxser_change_speed(struct mxser_port *info,
                                                outb(info->IER, info->ioaddr +
                                                                UART_IER);
                                        }
-                                       tty_wakeup(info->port.tty);
+                                       tty_wakeup(tty);
                                }
                        } else {
                                if (!(status & UART_MSR_CTS)) {
-                                       info->port.tty->hw_stopped = 1;
+                                       tty->hw_stopped = 1;
                                        if ((info->type != PORT_16550A) &&
                                                        (!info->board->chip_flag)) {
                                                info->IER &= ~UART_IER_THRI;
@@ -810,21 +755,21 @@ static int mxser_change_speed(struct mxser_port *info,
         * Set up parity check flag
         */
        info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
-       if (I_INPCK(info->port.tty))
+       if (I_INPCK(tty))
                info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
-       if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
+       if (I_BRKINT(tty) || I_PARMRK(tty))
                info->read_status_mask |= UART_LSR_BI;
 
        info->ignore_status_mask = 0;
 
-       if (I_IGNBRK(info->port.tty)) {
+       if (I_IGNBRK(tty)) {
                info->ignore_status_mask |= UART_LSR_BI;
                info->read_status_mask |= UART_LSR_BI;
                /*
                 * If we're ignore parity and break indicators, ignore
                 * overruns too.  (For real raw support).
                 */
-               if (I_IGNPAR(info->port.tty)) {
+               if (I_IGNPAR(tty)) {
                        info->ignore_status_mask |=
                                                UART_LSR_OE |
                                                UART_LSR_PE |
@@ -836,16 +781,16 @@ static int mxser_change_speed(struct mxser_port *info,
                }
        }
        if (info->board->chip_flag) {
-               mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty));
-               mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty));
-               if (I_IXON(info->port.tty)) {
+               mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty));
+               mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty));
+               if (I_IXON(tty)) {
                        mxser_enable_must_rx_software_flow_control(
                                        info->ioaddr);
                } else {
                        mxser_disable_must_rx_software_flow_control(
                                        info->ioaddr);
                }
-               if (I_IXOFF(info->port.tty)) {
+               if (I_IXOFF(tty)) {
                        mxser_enable_must_tx_software_flow_control(
                                        info->ioaddr);
                } else {
@@ -861,7 +806,8 @@ static int mxser_change_speed(struct mxser_port *info,
        return ret;
 }
 
-static void mxser_check_modem_status(struct mxser_port *port, int status)
+static void mxser_check_modem_status(struct tty_struct *tty,
+                               struct mxser_port *port, int status)
 {
        /* update input line counters */
        if (status & UART_MSR_TERI)
@@ -873,7 +819,7 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
        if (status & UART_MSR_DCTS)
                port->icount.cts++;
        port->mon_data.modem_status = status;
-       wake_up_interruptible(&port->delta_msr_wait);
+       wake_up_interruptible(&port->port.delta_msr_wait);
 
        if ((port->port.flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
                if (status & UART_MSR_DCD)
@@ -881,9 +827,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
        }
 
        if (port->port.flags & ASYNC_CTS_FLOW) {
-               if (port->port.tty->hw_stopped) {
+               if (tty->hw_stopped) {
                        if (status & UART_MSR_CTS) {
-                               port->port.tty->hw_stopped = 0;
+                               tty->hw_stopped = 0;
 
                                if ((port->type != PORT_16550A) &&
                                                (!port->board->chip_flag)) {
@@ -893,11 +839,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
                                        outb(port->IER, port->ioaddr +
                                                        UART_IER);
                                }
-                               tty_wakeup(port->port.tty);
+                               tty_wakeup(tty);
                        }
                } else {
                        if (!(status & UART_MSR_CTS)) {
-                               port->port.tty->hw_stopped = 1;
+                               tty->hw_stopped = 1;
                                if (port->type != PORT_16550A &&
                                                !port->board->chip_flag) {
                                        port->IER &= ~UART_IER_THRI;
@@ -909,8 +855,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status)
        }
 }
 
-static int mxser_startup(struct mxser_port *info)
+static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
 {
+       struct mxser_port *info = container_of(port, struct mxser_port, port);
        unsigned long page;
        unsigned long flags;
 
@@ -920,23 +867,13 @@ static int mxser_startup(struct mxser_port *info)
 
        spin_lock_irqsave(&info->slock, flags);
 
-       if (info->port.flags & ASYNC_INITIALIZED) {
-               free_page(page);
-               spin_unlock_irqrestore(&info->slock, flags);
-               return 0;
-       }
-
        if (!info->ioaddr || !info->type) {
-               if (info->port.tty)
-                       set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+               set_bit(TTY_IO_ERROR, &tty->flags);
                free_page(page);
                spin_unlock_irqrestore(&info->slock, flags);
                return 0;
        }
-       if (info->port.xmit_buf)
-               free_page(page);
-       else
-               info->port.xmit_buf = (unsigned char *) page;
+       info->port.xmit_buf = (unsigned char *) page;
 
        /*
         * Clear the FIFO buffers and disable them
@@ -958,8 +895,7 @@ static int mxser_startup(struct mxser_port *info)
        if (inb(info->ioaddr + UART_LSR) == 0xff) {
                spin_unlock_irqrestore(&info->slock, flags);
                if (capable(CAP_SYS_ADMIN)) {
-                       if (info->port.tty)
-                               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+                       set_bit(TTY_IO_ERROR, &tty->flags);
                        return 0;
                } else
                        return -ENODEV;
@@ -997,41 +933,36 @@ static int mxser_startup(struct mxser_port *info)
        (void) inb(info->ioaddr + UART_IIR);
        (void) inb(info->ioaddr + UART_MSR);
 
-       if (info->port.tty)
-               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
+       clear_bit(TTY_IO_ERROR, &tty->flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
        /*
         * and set the speed of the serial port
         */
-       mxser_change_speed(info, NULL);
-       info->port.flags |= ASYNC_INITIALIZED;
+       mxser_change_speed(tty, NULL);
        spin_unlock_irqrestore(&info->slock, flags);
 
        return 0;
 }
 
 /*
- * This routine will shutdown a serial port; interrupts maybe disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
+ * This routine will shutdown a serial port
  */
-static void mxser_shutdown(struct mxser_port *info)
+static void mxser_shutdown_port(struct tty_port *port)
 {
+       struct mxser_port *info = container_of(port, struct mxser_port, port);
        unsigned long flags;
 
-       if (!(info->port.flags & ASYNC_INITIALIZED))
-               return;
-
        spin_lock_irqsave(&info->slock, flags);
 
        /*
         * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
         * here so the queue might never be waken up
         */
-       wake_up_interruptible(&info->delta_msr_wait);
+       wake_up_interruptible(&info->port.delta_msr_wait);
 
        /*
-        * Free the IRQ, if necessary
+        * Free the xmit buffer, if necessary
         */
        if (info->port.xmit_buf) {
                free_page((unsigned long) info->port.xmit_buf);
@@ -1041,10 +972,6 @@ static void mxser_shutdown(struct mxser_port *info)
        info->IER = 0;
        outb(0x00, info->ioaddr + UART_IER);
 
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
-               info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
-       outb(info->MCR, info->ioaddr + UART_MCR);
-
        /* clear Rx/Tx FIFO's */
        if (info->board->chip_flag)
                outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
@@ -1057,10 +984,6 @@ static void mxser_shutdown(struct mxser_port *info)
        /* read data port to reset things */
        (void) inb(info->ioaddr + UART_RX);
 
-       if (info->port.tty)
-               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
-       info->port.flags &= ~ASYNC_INITIALIZED;
 
        if (info->board->chip_flag)
                SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
@@ -1077,8 +1000,7 @@ static void mxser_shutdown(struct mxser_port *info)
 static int mxser_open(struct tty_struct *tty, struct file *filp)
 {
        struct mxser_port *info;
-       unsigned long flags;
-       int retval, line;
+       int line;
 
        line = tty->index;
        if (line == MXSER_PORTS)
@@ -1090,24 +1012,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
                return -ENODEV;
 
        tty->driver_data = info;
-       info->port.tty = tty;
-       /*
-        * Start up serial port
-        */
-       spin_lock_irqsave(&info->slock, flags);
-       info->port.count++;
-       spin_unlock_irqrestore(&info->slock, flags);
-       retval = mxser_startup(info);
-       if (retval)
-               return retval;
-
-       retval = mxser_block_til_ready(tty, filp, info);
-       if (retval)
-               return retval;
-
-       /* unmark here for very high baud rate (ex. 921600 bps) used */
-       tty->low_latency = 1;
-       return 0;
+       return tty_port_open(&info->port, tty, filp);
 }
 
 static void mxser_flush_buffer(struct tty_struct *tty)
@@ -1131,66 +1036,10 @@ static void mxser_flush_buffer(struct tty_struct *tty)
 }
 
 
-/*
- * 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 mxser_close(struct tty_struct *tty, struct file *filp)
+static void mxser_close_port(struct tty_port *port)
 {
-       struct mxser_port *info = tty->driver_data;
-
+       struct mxser_port *info = container_of(port, struct mxser_port, port);
        unsigned long timeout;
-       unsigned long flags;
-
-       if (tty->index == MXSER_PORTS)
-               return;
-       if (!info)
-               return;
-
-       spin_lock_irqsave(&info->slock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&info->slock, flags);
-               return;
-       }
-       if ((tty->count == 1) && (info->port.count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  Info->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 "mxser_close: bad serial port count; "
-                       "tty->count is 1, info->port.count is %d\n", info->port.count);
-               info->port.count = 1;
-       }
-       if (--info->port.count < 0) {
-               printk(KERN_ERR "mxser_close: bad serial port count for "
-                       "ttys%d: %d\n", tty->index, info->port.count);
-               info->port.count = 0;
-       }
-       if (info->port.count) {
-               spin_unlock_irqrestore(&info->slock, flags);
-               return;
-       }
-       info->port.flags |= ASYNC_CLOSING;
-       spin_unlock_irqrestore(&info->slock, flags);
-       /*
-        * Save the termios structure, since this port may have
-        * separate termios for callout and dialin.
-        */
-       if (info->port.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->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent(tty, info->port.closing_wait);
        /*
         * At this point we stop accepting input.  To do this, we
         * disable the receive line status interrupts, and tell the
@@ -1201,34 +1050,45 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
        if (info->board->chip_flag)
                info->IER &= ~MOXA_MUST_RECV_ISR;
 
-       if (info->port.flags & ASYNC_INITIALIZED) {
-               outb(info->IER, info->ioaddr + UART_IER);
-               /*
-                * Before we drop DTR, make sure the UART transmitter
-                * has completely drained; this is especially
-                * important if there is a transmit FIFO!
-                */
-               timeout = jiffies + HZ;
-               while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
-                       schedule_timeout_interruptible(5);
-                       if (time_after(jiffies, timeout))
-                               break;
-               }
+       outb(info->IER, info->ioaddr + UART_IER);
+       /*
+        * Before we drop DTR, make sure the UART transmitter
+        * has completely drained; this is especially
+        * important if there is a transmit FIFO!
+        */
+       timeout = jiffies + HZ;
+       while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) {
+               schedule_timeout_interruptible(5);
+               if (time_after(jiffies, timeout))
+                       break;
        }
-       mxser_shutdown(info);
-
-       mxser_flush_buffer(tty);
-       tty_ldisc_flush(tty);
+}
 
-       tty->closing = 0;
-       info->port.tty = NULL;
-       if (info->port.blocked_open) {
-               if (info->port.close_delay)
-                       schedule_timeout_interruptible(info->port.close_delay);
-               wake_up_interruptible(&info->port.open_wait);
-       }
+/*
+ * 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 mxser_close(struct tty_struct *tty, struct file *filp)
+{
+       struct mxser_port *info = tty->driver_data;
+       struct tty_port *port = &info->port;
 
-       info->port.flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
+       if (tty->index == MXSER_PORTS || info == NULL)
+               return;
+       if (tty_port_close_start(port, tty, filp) == 0)
+               return;
+       mutex_lock(&port->mutex);
+       mxser_close_port(port);
+       mxser_flush_buffer(tty);
+       mxser_shutdown_port(port);
+       clear_bit(ASYNCB_INITIALIZED, &port->flags);
+       mutex_unlock(&port->mutex);
+       /* Right now the tty_port set is done outside of the close_end helper
+          as we don't yet have everyone using refcounts */     
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
 }
 
 static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1309,13 +1169,9 @@ static void mxser_flush_chars(struct tty_struct *tty)
        struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
-       if (info->xmit_cnt <= 0 ||
-                       tty->stopped ||
-                       !info->port.xmit_buf ||
-                       (tty->hw_stopped &&
-                        (info->type != PORT_16550A) &&
-                        (!info->board->chip_flag)
-                       ))
+       if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf ||
+                       (tty->hw_stopped && info->type != PORT_16550A &&
+                        !info->board->chip_flag))
                return;
 
        spin_lock_irqsave(&info->slock, flags);
@@ -1333,9 +1189,7 @@ static int mxser_write_room(struct tty_struct *tty)
        int ret;
 
        ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-       if (ret < 0)
-               ret = 0;
-       return ret;
+       return ret < 0 ? 0 : ret;
 }
 
 static int mxser_chars_in_buffer(struct tty_struct *tty)
@@ -1349,12 +1203,13 @@ static int mxser_chars_in_buffer(struct tty_struct *tty)
  * friends of mxser_ioctl()
  * ------------------------------------------------------------
  */
-static int mxser_get_serial_info(struct mxser_port *info,
+static int mxser_get_serial_info(struct tty_struct *tty,
                struct serial_struct __user *retinfo)
 {
+       struct mxser_port *info = tty->driver_data;
        struct serial_struct tmp = {
                .type = info->type,
-               .line = info->port.tty->index,
+               .line = tty->index,
                .port = info->ioaddr,
                .irq = info->board->irq,
                .flags = info->port.flags,
@@ -1369,9 +1224,11 @@ static int mxser_get_serial_info(struct mxser_port *info,
        return 0;
 }
 
-static int mxser_set_serial_info(struct mxser_port *info,
+static int mxser_set_serial_info(struct tty_struct *tty,
                struct serial_struct __user *new_info)
 {
+       struct mxser_port *info = tty->driver_data;
+       struct tty_port *port = &info->port;
        struct serial_struct new_serial;
        speed_t baud;
        unsigned long sl_flags;
@@ -1387,7 +1244,7 @@ static int mxser_set_serial_info(struct mxser_port *info,
                        new_serial.port != info->ioaddr)
                return -EINVAL;
 
-       flags = info->port.flags & ASYNC_SPD_MASK;
+       flags = port->flags & ASYNC_SPD_MASK;
 
        if (!capable(CAP_SYS_ADMIN)) {
                if ((new_serial.baud_base != info->baud_base) ||
@@ -1401,18 +1258,19 @@ static int mxser_set_serial_info(struct mxser_port *info,
                 * OK, past this point, all the error checking has been done.
                 * At this point, we start making changes.....
                 */
-               info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
+               port->flags = ((port->flags & ~ASYNC_FLAGS) |
                                (new_serial.flags & ASYNC_FLAGS));
-               info->port.close_delay = new_serial.close_delay * HZ / 100;
-               info->port.closing_wait = new_serial.closing_wait * HZ / 100;
-               info->port.tty->low_latency =
-                               (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-               if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
+               port->close_delay = new_serial.close_delay * HZ / 100;
+               port->closing_wait = new_serial.closing_wait * HZ / 100;
+               tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+               if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
                                (new_serial.baud_base != info->baud_base ||
                                new_serial.custom_divisor !=
                                info->custom_divisor)) {
+                       if (new_serial.custom_divisor == 0)
+                               return -EINVAL;
                        baud = new_serial.baud_base / new_serial.custom_divisor;
-                       tty_encode_baud_rate(info->port.tty, baud, baud);
+                       tty_encode_baud_rate(tty, baud, baud);
                }
        }
 
@@ -1420,15 +1278,17 @@ static int mxser_set_serial_info(struct mxser_port *info,
 
        process_txrx_fifo(info);
 
-       if (info->port.flags & ASYNC_INITIALIZED) {
-               if (flags != (info->port.flags & ASYNC_SPD_MASK)) {
+       if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+               if (flags != (port->flags & ASYNC_SPD_MASK)) {
                        spin_lock_irqsave(&info->slock, sl_flags);
-                       mxser_change_speed(info, NULL);
+                       mxser_change_speed(tty, NULL);
                        spin_unlock_irqrestore(&info->slock, sl_flags);
                }
-       } else
-               retval = mxser_startup(info);
-
+       } else {
+               retval = mxser_activate(port, tty);
+               if (retval == 0)
+                       set_bit(ASYNCB_INITIALIZED, &port->flags);
+       }
        return retval;
 }
 
@@ -1473,7 +1333,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
        spin_lock_irqsave(&info->slock, flags);
        status = inb(info->ioaddr + UART_MSR);
        if (status & UART_MSR_ANY_DELTA)
-               mxser_check_modem_status(info, status);
+               mxser_check_modem_status(tty, info, status);
        spin_unlock_irqrestore(&info->slock, flags);
        return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
                    ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
@@ -1617,49 +1477,56 @@ static int __init mxser_read_register(int port, unsigned short *regs)
 
 static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 {
-       struct mxser_port *port;
+       struct mxser_port *ip;
+       struct tty_port *port;
+       struct tty_struct *tty;
        int result, status;
        unsigned int i, j;
        int ret = 0;
 
        switch (cmd) {
        case MOXA_GET_MAJOR:
-               printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl %x, fix "
-                               "your userspace\n", current->comm, cmd);
+               if (printk_ratelimit())
+                       printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl "
+                                       "%x (GET_MAJOR), fix your userspace\n",
+                                       current->comm, cmd);
                return put_user(ttymajor, (int __user *)argp);
 
        case MOXA_CHKPORTENABLE:
                result = 0;
-               lock_kernel();
                for (i = 0; i < MXSER_BOARDS; i++)
                        for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
                                if (mxser_boards[i].ports[j].ioaddr)
                                        result |= (1 << i);
-               unlock_kernel();
                return put_user(result, (unsigned long __user *)argp);
        case MOXA_GETDATACOUNT:
-               lock_kernel();
+               /* The receive side is locked by port->slock but it isn't
+                  clear that an exact snapshot is worth copying here */
                if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
                        ret = -EFAULT;
-               unlock_kernel();
                return ret;
        case MOXA_GETMSTATUS: {
                struct mxser_mstatus ms, __user *msu = argp;
-               lock_kernel();
                for (i = 0; i < MXSER_BOARDS; i++)
                        for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
-                               port = &mxser_boards[i].ports[j];
+                               ip = &mxser_boards[i].ports[j];
+                               port = &ip->port;
                                memset(&ms, 0, sizeof(ms));
 
-                               if (!port->ioaddr)
+                               mutex_lock(&port->mutex);
+                               if (!ip->ioaddr)
                                        goto copy;
+                               
+                               tty = tty_port_tty_get(port);
 
-                               if (!port->port.tty || !port->port.tty->termios)
-                                       ms.cflag = port->normal_termios.c_cflag;
+                               if (!tty || !tty->termios)
+                                       ms.cflag = ip->normal_termios.c_cflag;
                                else
-                                       ms.cflag = port->port.tty->termios->c_cflag;
-
-                               status = inb(port->ioaddr + UART_MSR);
+                                       ms.cflag = tty->termios->c_cflag;
+                               tty_kref_put(tty);
+                               spin_lock_irq(&ip->slock);
+                               status = inb(ip->ioaddr + UART_MSR);
+                               spin_unlock_irq(&ip->slock);
                                if (status & UART_MSR_DCD)
                                        ms.dcd = 1;
                                if (status & UART_MSR_DSR)
@@ -1667,13 +1534,11 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                if (status & UART_MSR_CTS)
                                        ms.cts = 1;
                        copy:
-                               if (copy_to_user(msu, &ms, sizeof(ms))) {
-                                       unlock_kernel();
+                               mutex_unlock(&port->mutex);
+                               if (copy_to_user(msu, &ms, sizeof(ms)))
                                        return -EFAULT;
-                               }
                                msu++;
                        }
-               unlock_kernel();
                return 0;
        }
        case MOXA_ASPP_MON_EXT: {
@@ -1685,44 +1550,54 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                if (!me)
                        return -ENOMEM;
 
-               lock_kernel();
                for (i = 0, p = 0; i < MXSER_BOARDS; i++) {
                        for (j = 0; j < MXSER_PORTS_PER_BOARD; j++, p++) {
                                if (p >= ARRAY_SIZE(me->rx_cnt)) {
                                        i = MXSER_BOARDS;
                                        break;
                                }
-                               port = &mxser_boards[i].ports[j];
-                               if (!port->ioaddr)
+                               ip = &mxser_boards[i].ports[j];
+                               port = &ip->port;
+
+                               mutex_lock(&port->mutex);
+                               if (!ip->ioaddr) {
+                                       mutex_unlock(&port->mutex);
                                        continue;
+                               }
 
-                               status = mxser_get_msr(port->ioaddr, 0, p);
+                               spin_lock_irq(&ip->slock);
+                               status = mxser_get_msr(ip->ioaddr, 0, p);
 
                                if (status & UART_MSR_TERI)
-                                       port->icount.rng++;
+                                       ip->icount.rng++;
                                if (status & UART_MSR_DDSR)
-                                       port->icount.dsr++;
+                                       ip->icount.dsr++;
                                if (status & UART_MSR_DDCD)
-                                       port->icount.dcd++;
+                                       ip->icount.dcd++;
                                if (status & UART_MSR_DCTS)
-                                       port->icount.cts++;
+                                       ip->icount.cts++;
 
-                               port->mon_data.modem_status = status;
-                               me->rx_cnt[p] = port->mon_data.rxcnt;
-                               me->tx_cnt[p] = port->mon_data.txcnt;
-                               me->up_rxcnt[p] = port->mon_data.up_rxcnt;
-                               me->up_txcnt[p] = port->mon_data.up_txcnt;
+                               ip->mon_data.modem_status = status;
+                               me->rx_cnt[p] = ip->mon_data.rxcnt;
+                               me->tx_cnt[p] = ip->mon_data.txcnt;
+                               me->up_rxcnt[p] = ip->mon_data.up_rxcnt;
+                               me->up_txcnt[p] = ip->mon_data.up_txcnt;
                                me->modem_status[p] =
-                                       port->mon_data.modem_status;
-                               me->baudrate[p] = tty_get_baud_rate(port->port.tty);
+                                       ip->mon_data.modem_status;
+                               spin_unlock_irq(&ip->slock);
 
-                               if (!port->port.tty || !port->port.tty->termios) {
-                                       cflag = port->normal_termios.c_cflag;
-                                       iflag = port->normal_termios.c_iflag;
+                               tty = tty_port_tty_get(&ip->port);
+
+                               if (!tty || !tty->termios) {
+                                       cflag = ip->normal_termios.c_cflag;
+                                       iflag = ip->normal_termios.c_iflag;
+                                       me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
                                } else {
-                                       cflag = port->port.tty->termios->c_cflag;
-                                       iflag = port->port.tty->termios->c_iflag;
+                                       cflag = tty->termios->c_cflag;
+                                       iflag = tty->termios->c_iflag;
+                                       me->baudrate[p] = tty_get_baud_rate(tty);
                                }
+                               tty_kref_put(tty);
 
                                me->databits[p] = cflag & CSIZE;
                                me->stopbits[p] = cflag & CSTOPB;
@@ -1735,16 +1610,15 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                if (iflag & (IXON | IXOFF))
                                        me->flowctrl[p] |= 0x0C;
 
-                               if (port->type == PORT_16550A)
+                               if (ip->type == PORT_16550A)
                                        me->fifo[p] = 1;
 
-                               opmode = inb(port->opmode_ioaddr) >>
-                                               ((p % 4) * 2);
+                               opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
                                opmode &= OP_MODE_MASK;
                                me->iftype[p] = opmode;
+                               mutex_unlock(&port->mutex);
                        }
                }
-               unlock_kernel();
                if (copy_to_user(argp, me, sizeof(*me)))
                        ret = -EFAULT;
                kfree(me);
@@ -1781,6 +1655,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                unsigned int cmd, unsigned long arg)
 {
        struct mxser_port *info = tty->driver_data;
+       struct tty_port *port = &info->port;
        struct async_icount cnow;
        unsigned long flags;
        void __user *argp = (void __user *)arg;
@@ -1805,20 +1680,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                                        opmode != RS422_MODE &&
                                        opmode != RS485_4WIRE_MODE)
                                return -EFAULT;
-                       lock_kernel();
                        mask = ModeMask[p];
                        shiftbit = p * 2;
+                       spin_lock_irq(&info->slock);
                        val = inb(info->opmode_ioaddr);
                        val &= mask;
                        val |= (opmode << shiftbit);
                        outb(val, info->opmode_ioaddr);
-                       unlock_kernel();
+                       spin_unlock_irq(&info->slock);
                } else {
-                       lock_kernel();
                        shiftbit = p * 2;
+                       spin_lock_irq(&info->slock);
                        opmode = inb(info->opmode_ioaddr) >> shiftbit;
+                       spin_unlock_irq(&info->slock);
                        opmode &= OP_MODE_MASK;
-                       unlock_kernel();
                        if (put_user(opmode, (int __user *)argp))
                                return -EFAULT;
                }
@@ -1831,14 +1706,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 
        switch (cmd) {
        case TIOCGSERIAL:
-               lock_kernel();
-               retval = mxser_get_serial_info(info, argp);
-               unlock_kernel();
+               mutex_lock(&port->mutex);
+               retval = mxser_get_serial_info(tty, argp);
+               mutex_unlock(&port->mutex);
                return retval;
        case TIOCSSERIAL:
-               lock_kernel();
-               retval = mxser_set_serial_info(info, argp);
-               unlock_kernel();
+               mutex_lock(&port->mutex);
+               retval = mxser_set_serial_info(tty, argp);
+               mutex_unlock(&port->mutex);
                return retval;
        case TIOCSERGETLSR:     /* Get line status register */
                return  mxser_get_lsr_info(info, argp);
@@ -1853,7 +1728,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                cnow = info->icount;    /* note the counters on entry */
                spin_unlock_irqrestore(&info->slock, flags);
 
-               return wait_event_interruptible(info->delta_msr_wait,
+               return wait_event_interruptible(info->port.delta_msr_wait,
                                mxser_cflags_changed(info, arg, &cnow));
        /*
         * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
@@ -1884,31 +1759,33 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
        case MOXA_HighSpeedOn:
                return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
        case MOXA_SDS_RSTICOUNTER:
-               lock_kernel();
+               spin_lock_irq(&info->slock);
                info->mon_data.rxcnt = 0;
                info->mon_data.txcnt = 0;
-               unlock_kernel();
+               spin_unlock_irq(&info->slock);
                return 0;
 
        case MOXA_ASPP_OQUEUE:{
                int len, lsr;
 
-               lock_kernel();
                len = mxser_chars_in_buffer(tty);
-               lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
+               spin_lock_irq(&info->slock);
+               lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_THRE;
+               spin_unlock_irq(&info->slock);
                len += (lsr ? 0 : 1);
-               unlock_kernel();
 
                return put_user(len, (int __user *)argp);
        }
        case MOXA_ASPP_MON: {
                int mcr, status;
 
-               lock_kernel();
+               spin_lock_irq(&info->slock);
                status = mxser_get_msr(info->ioaddr, 1, tty->index);
-               mxser_check_modem_status(info, status);
+               mxser_check_modem_status(tty, info, status);
 
                mcr = inb(info->ioaddr + UART_MCR);
+               spin_unlock_irq(&info->slock);
+
                if (mcr & MOXA_MUST_MCR_XON_FLAG)
                        info->mon_data.hold_reason &= ~NPPI_NOTIFY_XOFFHOLD;
                else
@@ -1919,11 +1796,11 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                else
                        info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT;
 
-               if (info->port.tty->hw_stopped)
+               if (tty->hw_stopped)
                        info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
                else
                        info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-               unlock_kernel();
+
                if (copy_to_user(argp, &info->mon_data,
                                sizeof(struct mxser_mon)))
                        return -EFAULT;
@@ -1968,7 +1845,7 @@ static void mxser_stoprx(struct tty_struct *tty)
                }
        }
 
-       if (info->port.tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios->c_cflag & CRTSCTS) {
                info->MCR &= ~UART_MCR_RTS;
                outb(info->MCR, info->ioaddr + UART_MCR);
        }
@@ -2005,7 +1882,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
                }
        }
 
-       if (info->port.tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios->c_cflag & CRTSCTS) {
                info->MCR |= UART_MCR_RTS;
                outb(info->MCR, info->ioaddr + UART_MCR);
        }
@@ -2050,7 +1927,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
-       mxser_change_speed(info, old_termios);
+       mxser_change_speed(tty, old_termios);
        spin_unlock_irqrestore(&info->slock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
@@ -2082,6 +1959,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
 {
        struct mxser_port *info = tty->driver_data;
        unsigned long orig_jiffies, char_time;
+       unsigned long flags;
        int lsr;
 
        if (info->type == PORT_UNKNOWN)
@@ -2121,19 +1999,21 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
                timeout, char_time);
        printk("jiff=%lu...", jiffies);
 #endif
-       lock_kernel();
+       spin_lock_irqsave(&info->slock, flags);
        while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
                printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
+               spin_unlock_irqrestore(&info->slock, flags);
                schedule_timeout_interruptible(char_time);
+               spin_lock_irqsave(&info->slock, flags);
                if (signal_pending(current))
                        break;
                if (timeout && time_after(jiffies, orig_jiffies + timeout))
                        break;
        }
+       spin_unlock_irqrestore(&info->slock, flags);
        set_current_state(TASK_RUNNING);
-       unlock_kernel();
 
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
        printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
@@ -2148,11 +2028,7 @@ static void mxser_hangup(struct tty_struct *tty)
        struct mxser_port *info = tty->driver_data;
 
        mxser_flush_buffer(tty);
-       mxser_shutdown(info);
-       info->port.count = 0;
-       info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->port.tty = NULL;
-       wake_up_interruptible(&info->port.open_wait);
+       tty_port_hangup(&info->port);
 }
 
 /*
@@ -2174,9 +2050,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state)
        return 0;
 }
 
-static void mxser_receive_chars(struct mxser_port *port, int *status)
+static void mxser_receive_chars(struct tty_struct *tty,
+                               struct mxser_port *port, int *status)
 {
-       struct tty_struct *tty = port->port.tty;
        unsigned char ch, gdl;
        int ignored = 0;
        int cnt = 0;
@@ -2184,9 +2060,8 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
        int max = 256;
 
        recv_room = tty->receive_room;
-       if ((recv_room == 0) && (!port->ldisc_stop_rx))
+       if (recv_room == 0 && !port->ldisc_stop_rx)
                mxser_stoprx(tty);
-
        if (port->board->chip_flag != MOXA_OTHER_UART) {
 
                if (*status & UART_LSR_SPECIAL)
@@ -2263,7 +2138,7 @@ intr_old:
        } while (*status & UART_LSR_DR);
 
 end_intr:
-       mxvar_log.rxcnt[port->port.tty->index] += cnt;
+       mxvar_log.rxcnt[tty->index] += cnt;
        port->mon_data.rxcnt += cnt;
        port->mon_data.up_rxcnt += cnt;
 
@@ -2277,14 +2152,14 @@ end_intr:
        spin_lock(&port->slock);
 }
 
-static void mxser_transmit_chars(struct mxser_port *port)
+static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port)
 {
        int count, cnt;
 
        if (port->x_char) {
                outb(port->x_char, port->ioaddr + UART_TX);
                port->x_char = 0;
-               mxvar_log.txcnt[port->port.tty->index]++;
+               mxvar_log.txcnt[tty->index]++;
                port->mon_data.txcnt++;
                port->mon_data.up_txcnt++;
                port->icount.tx++;
@@ -2294,8 +2169,8 @@ static void mxser_transmit_chars(struct mxser_port *port)
        if (port->port.xmit_buf == NULL)
                return;
 
-       if ((port->xmit_cnt <= 0) || port->port.tty->stopped ||
-                       (port->port.tty->hw_stopped &&
+       if (port->xmit_cnt <= 0 || tty->stopped ||
+                       (tty->hw_stopped &&
                        (port->type != PORT_16550A) &&
                        (!port->board->chip_flag))) {
                port->IER &= ~UART_IER_THRI;
@@ -2312,14 +2187,14 @@ static void mxser_transmit_chars(struct mxser_port *port)
                if (--port->xmit_cnt <= 0)
                        break;
        } while (--count > 0);
-       mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt);
+       mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt);
 
        port->mon_data.txcnt += (cnt - port->xmit_cnt);
        port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
        port->icount.tx += (cnt - port->xmit_cnt);
 
-       if (port->xmit_cnt < WAKEUP_CHARS)
-               tty_wakeup(port->port.tty);
+       if (port->xmit_cnt < WAKEUP_CHARS && tty)
+               tty_wakeup(tty);
 
        if (port->xmit_cnt <= 0) {
                port->IER &= ~UART_IER_THRI;
@@ -2338,6 +2213,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
        int max, irqbits, bits, msr;
        unsigned int int_cnt, pass_counter = 0;
        int handled = IRQ_NONE;
+       struct tty_struct *tty;
 
        for (i = 0; i < MXSER_BOARDS; i++)
                if (dev_id == &mxser_boards[i]) {
@@ -2370,13 +2246,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
                                if (iir & UART_IIR_NO_INT)
                                        break;
                                iir &= MOXA_MUST_IIR_MASK;
-                               if (!port->port.tty ||
+                               tty = tty_port_tty_get(&port->port);
+                               if (!tty ||
                                                (port->port.flags & ASYNC_CLOSING) ||
                                                !(port->port.flags &
                                                        ASYNC_INITIALIZED)) {
                                        status = inb(port->ioaddr + UART_LSR);
                                        outb(0x27, port->ioaddr + UART_FCR);
                                        inb(port->ioaddr + UART_MSR);
+                                       tty_kref_put(tty);
                                        break;
                                }
 
@@ -2397,27 +2275,28 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id)
                                            iir == MOXA_MUST_IIR_RDA ||
                                            iir == MOXA_MUST_IIR_RTO ||
                                            iir == MOXA_MUST_IIR_LSR)
-                                               mxser_receive_chars(port,
+                                               mxser_receive_chars(tty, port,
                                                                &status);
 
                                } else {
                                        status &= port->read_status_mask;
                                        if (status & UART_LSR_DR)
-                                               mxser_receive_chars(port,
+                                               mxser_receive_chars(tty, port,
                                                                &status);
                                }
                                msr = inb(port->ioaddr + UART_MSR);
                                if (msr & UART_MSR_ANY_DELTA)
-                                       mxser_check_modem_status(port, msr);
+                                       mxser_check_modem_status(tty, port, msr);
 
                                if (port->board->chip_flag) {
                                        if (iir == 0x02 && (status &
                                                                UART_LSR_THRE))
-                                               mxser_transmit_chars(port);
+                                               mxser_transmit_chars(tty, port);
                                } else {
                                        if (status & UART_LSR_THRE)
-                                               mxser_transmit_chars(port);
+                                               mxser_transmit_chars(tty, port);
                                }
+                               tty_kref_put(tty);
                        } while (int_cnt++ < MXSER_ISR_PASS_LIMIT);
                        spin_unlock(&port->slock);
                }
@@ -2449,6 +2328,13 @@ static const struct tty_operations mxser_ops = {
        .tiocmset = mxser_tiocmset,
 };
 
+struct tty_port_operations mxser_port_ops = {
+       .carrier_raised = mxser_carrier_raised,
+       .dtr_rts = mxser_dtr_rts,
+       .activate = mxser_activate,
+       .shutdown = mxser_shutdown_port,
+};
+
 /*
  * The MOXA Smartio/Industio serial driver boot-time initialization code!
  */
@@ -2482,6 +2368,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
        for (i = 0; i < brd->info->nports; i++) {
                info = &brd->ports[i];
                tty_port_init(&info->port);
+               info->port.ops = &mxser_port_ops;
                info->board = brd;
                info->stop_rx = 0;
                info->ldisc_stop_rx = 0;
@@ -2499,7 +2386,6 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
                info->port.close_delay = 5 * HZ / 10;
                info->port.closing_wait = 30 * HZ;
                info->normal_termios = mxvar_sdriver->init_termios;
-               init_waitqueue_head(&info->delta_msr_wait);
                memset(&info->mon_data, 0, sizeof(struct mxser_mon));
                info->err_shadow = 0;
                spin_lock_init(&info->slock);
@@ -2763,11 +2649,8 @@ static struct pci_driver mxser_driver = {
 static int __init mxser_module_init(void)
 {
        struct mxser_board *brd;
-       unsigned long cap;
-       unsigned int i, m, isaloop;
-       int retval, b;
-
-       pr_debug("Loading module mxser ...\n");
+       unsigned int b, i, m;
+       int retval;
 
        mxvar_sdriver = alloc_tty_driver(MXSER_PORTS + 1);
        if (!mxvar_sdriver)
@@ -2797,41 +2680,33 @@ static int __init mxser_module_init(void)
                goto err_put;
        }
 
-       m = 0;
        /* Start finding ISA boards here */
-       for (isaloop = 0; isaloop < 2; isaloop++)
-               for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
-                       if (!isaloop)
-                               cap = mxserBoardCAP[b]; /* predefined */
-                       else
-                               cap = ioaddr[b]; /* module param */
-
-                       if (!cap)
-                               continue;
-
-                       brd = &mxser_boards[m];
-                       retval = mxser_get_ISA_conf(cap, brd);
-                       if (retval <= 0) {
-                               brd->info = NULL;
-                               continue;
-                       }
+       for (m = 0, b = 0; b < MXSER_BOARDS; b++) {
+               if (!ioaddr[b])
+                       continue;
+
+               brd = &mxser_boards[m];
+               retval = mxser_get_ISA_conf(ioaddr[b], brd);
+               if (retval <= 0) {
+                       brd->info = NULL;
+                       continue;
+               }
 
-                       printk(KERN_INFO "mxser: found MOXA %s board "
-                               "(CAP=0x%x)\n", brd->info->name, ioaddr[b]);
+               printk(KERN_INFO "mxser: found MOXA %s board (CAP=0x%lx)\n",
+                               brd->info->name, ioaddr[b]);
 
-                       /* mxser_initbrd will hook ISR. */
-                       if (mxser_initbrd(brd, NULL) < 0) {
-                               brd->info = NULL;
-                               continue;
-                       }
+               /* mxser_initbrd will hook ISR. */
+               if (mxser_initbrd(brd, NULL) < 0) {
+                       brd->info = NULL;
+                       continue;
+               }
 
-                       brd->idx = m * MXSER_PORTS_PER_BOARD;
-                       for (i = 0; i < brd->info->nports; i++)
-                               tty_register_device(mxvar_sdriver, brd->idx + i,
-                                               NULL);
+               brd->idx = m * MXSER_PORTS_PER_BOARD;
+               for (i = 0; i < brd->info->nports; i++)
+                       tty_register_device(mxvar_sdriver, brd->idx + i, NULL);
 
-                       m++;
-               }
+               m++;
+       }
 
        retval = pci_register_driver(&mxser_driver);
        if (retval) {
@@ -2842,8 +2717,6 @@ static int __init mxser_module_init(void)
                } /* else: we have some ISA cards under control */
        }
 
-       pr_debug("Done.\n");
-
        return 0;
 err_unr:
        tty_unregister_driver(mxvar_sdriver);
@@ -2856,8 +2729,6 @@ static void __exit mxser_module_exit(void)
 {
        unsigned int i, j;
 
-       pr_debug("Unloading module mxser ...\n");
-
        pci_unregister_driver(&mxser_driver);
 
        for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
@@ -2871,8 +2742,6 @@ static void __exit mxser_module_exit(void)
        for (i = 0; i < MXSER_BOARDS; i++)
                if (mxser_boards[i].info != NULL)
                        mxser_release_res(&mxser_boards[i], NULL, 1);
-
-       pr_debug("Done.\n");
 }
 
 module_init(mxser_module_init);