Merge ../linux-2.6-watchdog-mm
[pandora-kernel.git] / drivers / char / mxser_new.c
index 92ca016..1bb030b 100644 (file)
 #define        MXSERCUMAJOR     175
 
 #define        MXSER_EVENT_TXLOW       1
-#define        MXSER_EVENT_HANGUP      2
 
 #define MXSER_BOARDS           4       /* Max. boards */
-#define MXSER_PORTS            32      /* Max. ports */
 #define MXSER_PORTS_PER_BOARD  8       /* Max. ports per board */
+#define MXSER_PORTS            (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
 #define MXSER_ISR_PASS_LIMIT   99999L
 
 #define        MXSER_ERR_IOADDR        -1
@@ -66,9 +65,6 @@
 #define        MXSER_ERR_IRQ_CONFLIT   -3
 #define        MXSER_ERR_VECTOR        -4
 
-#define SERIAL_TYPE_NORMAL     1
-#define SERIAL_TYPE_CALLOUT    2
-
 #define WAKEUP_CHARS           256
 
 #define UART_MCR_AFE           0x20
 #define CI134_ASIC_ID  3
 #define CI104J_ASIC_ID  5
 
-enum {
-       MXSER_BOARD_C168_ISA = 1,
-       MXSER_BOARD_C104_ISA,
-       MXSER_BOARD_CI104J,
-       MXSER_BOARD_C168_PCI,
-       MXSER_BOARD_C104_PCI,
-       MXSER_BOARD_C102_ISA,
-       MXSER_BOARD_CI132,
-       MXSER_BOARD_CI134,
-       MXSER_BOARD_CP132,
-       MXSER_BOARD_CP114,
-       MXSER_BOARD_CT114,
-       MXSER_BOARD_CP102,
-       MXSER_BOARD_CP104U,
-       MXSER_BOARD_CP168U,
-       MXSER_BOARD_CP132U,
-       MXSER_BOARD_CP134U,
-       MXSER_BOARD_CP104JU,
-       MXSER_BOARD_RC7000,
-       MXSER_BOARD_CP118U,
-       MXSER_BOARD_CP102UL,
-       MXSER_BOARD_CP102U,
-       MXSER_BOARD_CP118EL,
-       MXSER_BOARD_CP168EL,
-       MXSER_BOARD_CP104EL
-};
-
-static char *mxser_brdname[] = {
-       "C168 series",
-       "C104 series",
-       "CI-104J series",
-       "C168H/PCI series",
-       "C104H/PCI series",
-       "C102 series",
-       "CI-132 series",
-       "CI-134 series",
-       "CP-132 series",
-       "CP-114 series",
-       "CT-114 series",
-       "CP-102 series",
-       "CP-104U series",
-       "CP-168U series",
-       "CP-132U series",
-       "CP-134U series",
-       "CP-104JU series",
-       "Moxa UC7000 Serial",
-       "CP-118U series",
-       "CP-102UL series",
-       "CP-102U series",
-       "CP-118EL series",
-       "CP-168EL series",
-       "CP-104EL series"
-};
-
-static int mxser_numports[] = {
-       8,                      /* C168-ISA */
-       4,                      /* C104-ISA */
-       4,                      /* CI104J */
-       8,                      /* C168-PCI */
-       4,                      /* C104-PCI */
-       2,                      /* C102-ISA */
-       2,                      /* CI132 */
-       4,                      /* CI134 */
-       2,                      /* CP132 */
-       4,                      /* CP114 */
-       4,                      /* CT114 */
-       2,                      /* CP102 */
-       4,                      /* CP104U */
-       8,                      /* CP168U */
-       2,                      /* CP132U */
-       4,                      /* CP134U */
-       4,                      /* CP104JU */
-       8,                      /* RC7000 */
-       8,                      /* CP118U */
-       2,                      /* CP102UL */
-       2,                      /* CP102U */
-       8,                      /* CP118EL */
-       8,                      /* CP168EL */
-       4                       /* CP104EL */
-};
-
-#define UART_TYPE_NUM  2
-
-static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
-       MOXA_MUST_MU150_HWID,
-       MOXA_MUST_MU860_HWID
-};
+#define MXSER_HIGHBAUD 1
+#define MXSER_HAS2     2
 
 /* This is only for PCI */
-#define UART_INFO_NUM  3
-struct mxpciuart_info {
+static const struct {
        int type;
        int tx_fifo;
        int rx_fifo;
@@ -183,51 +93,85 @@ struct mxpciuart_info {
        int rx_trigger;
        int rx_low_water;
        long max_baud;
-};
-
-static const struct mxpciuart_info Gpci_uart_info[UART_INFO_NUM] = {
+} Gpci_uart_info[] = {
        {MOXA_OTHER_UART, 16, 16, 16, 14, 14, 1, 921600L},
        {MOXA_MUST_MU150_HWID, 64, 64, 64, 48, 48, 16, 230400L},
        {MOXA_MUST_MU860_HWID, 128, 128, 128, 96, 96, 32, 921600L}
 };
+#define UART_INFO_NUM  ARRAY_SIZE(Gpci_uart_info)
+
+struct mxser_cardinfo {
+       unsigned int nports;
+       char *name;
+       unsigned int flags;
+};
 
+static const struct mxser_cardinfo mxser_cards[] = {
+       { 8, "C168 series", },                  /* C168-ISA */
+       { 4, "C104 series", },                  /* C104-ISA */
+       { 4, "CI-104J series", },               /* CI104J */
+       { 8, "C168H/PCI series", },             /* C168-PCI */
+       { 4, "C104H/PCI series", },             /* C104-PCI */
+       { 4, "C102 series", MXSER_HAS2 },       /* C102-ISA */
+       { 4, "CI-132 series", MXSER_HAS2 },     /* CI132 */
+       { 4, "CI-134 series", },                /* CI134 */
+       { 2, "CP-132 series", },                /* CP132 */
+       { 4, "CP-114 series", },                /* CP114 */
+       { 4, "CT-114 series", },                /* CT114 */
+       { 2, "CP-102 series", MXSER_HIGHBAUD }, /* CP102 */
+       { 4, "CP-104U series", },               /* CP104U */
+       { 8, "CP-168U series", },               /* CP168U */
+       { 2, "CP-132U series", },               /* CP132U */
+       { 4, "CP-134U series", },               /* CP134U */
+       { 4, "CP-104JU series", },              /* CP104JU */
+       { 8, "Moxa UC7000 Serial", },           /* RC7000 */
+       { 8, "CP-118U series", },               /* CP118U */
+       { 2, "CP-102UL series", },              /* CP102UL */
+       { 2, "CP-102U series", },               /* CP102U */
+       { 8, "CP-118EL series", },              /* CP118EL */
+       { 8, "CP-168EL series", },              /* CP168EL */
+       { 4, "CP-104EL series", }               /* CP104EL */
+};
+
+/* driver_data correspond to the lines in the structure above
+   see also ISA probe function before you change something */
 static struct pci_device_id mxser_pcibrds[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C168),
-               .driver_data = MXSER_BOARD_C168_PCI },
+               .driver_data = 3 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104),
-               .driver_data = MXSER_BOARD_C104_PCI },
+               .driver_data = 4 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132),
-               .driver_data = MXSER_BOARD_CP132 },
+               .driver_data = 8 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114),
-               .driver_data = MXSER_BOARD_CP114 },
+               .driver_data = 9 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114),
-               .driver_data = MXSER_BOARD_CT114 },
+               .driver_data = 10 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102),
-               .driver_data = MXSER_BOARD_CP102 },
+               .driver_data = 11 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U),
-               .driver_data = MXSER_BOARD_CP104U },
+               .driver_data = 12 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U),
-               .driver_data = MXSER_BOARD_CP168U },
+               .driver_data = 13 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U),
-               .driver_data = MXSER_BOARD_CP132U },
+               .driver_data = 14 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U),
-               .driver_data = MXSER_BOARD_CP134U },
+               .driver_data = 15 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU),
-               .driver_data = MXSER_BOARD_CP104JU },
+               .driver_data = 16 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000),
-               .driver_data = MXSER_BOARD_RC7000 },
+               .driver_data = 17 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U),
-               .driver_data = MXSER_BOARD_CP118U },
+               .driver_data = 18 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL),
-               .driver_data = MXSER_BOARD_CP102UL },
+               .driver_data = 19 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U),
-               .driver_data = MXSER_BOARD_CP102U },
+               .driver_data = 20 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL),
-               .driver_data = MXSER_BOARD_CP118EL },
+               .driver_data = 21 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL),
-               .driver_data = MXSER_BOARD_CP168EL },
+               .driver_data = 22 },
        { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL),
-               .driver_data = MXSER_BOARD_CP104EL },
+               .driver_data = 23 },
        { }
 };
 MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
@@ -322,8 +266,8 @@ struct mxser_port {
        int xmit_tail;
        int xmit_cnt;
 
-       struct termios normal_termios;
-       struct termios callout_termios;
+       struct ktermios normal_termios;
+       struct ktermios callout_termios;
 
        struct mxser_mon mon_data;
 
@@ -335,11 +279,9 @@ struct mxser_port {
 };
 
 struct mxser_board {
-       struct pci_dev *pdev; /* temporary (until pci probing) */
-
+       unsigned int idx;
        int irq;
-       int board_type;
-       unsigned int nports;
+       const struct mxser_cardinfo *info;
        unsigned long vector;
        unsigned long vector_mask;
 
@@ -366,9 +308,6 @@ static int mxserBoardCAP[MXSER_BOARDS] = {
 
 static struct mxser_board mxser_boards[MXSER_BOARDS];
 static struct tty_driver *mxvar_sdriver;
-static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
-static struct termios *mxvar_termios[MXSER_PORTS + 1];
-static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];
 static struct mxser_log mxvar_log;
 static int mxvar_diagflag;
 static unsigned char mxser_msr[MXSER_PORTS + 1];
@@ -376,6 +315,7 @@ static struct mxser_mon_ext mon_data_ext;
 static int mxser_set_baud_method[MXSER_PORTS + 1];
 static spinlock_t gm_lock;
 
+#ifdef CONFIG_PCI
 static int CheckIsMoxaMust(int io)
 {
        u8 oldmcr, hwid;
@@ -392,14 +332,13 @@ static int CheckIsMoxaMust(int io)
        }
 
        GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
-       for (i = 0; i < UART_TYPE_NUM; i++) {
-               if (hwid == Gmoxa_uart_id[i])
+       for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
+               if (hwid == Gpci_uart_info[i].type)
                        return (int)hwid;
        }
        return MOXA_OTHER_UART;
 }
-
-/* above is modified by Victor Yu. 08-15-2002 */
+#endif
 
 static void process_txrx_fifo(struct mxser_port *info)
 {
@@ -421,17 +360,13 @@ static void process_txrx_fifo(struct mxser_port *info)
                        }
 }
 
-static void mxser_do_softint(void *private_)
+static void mxser_do_softint(struct work_struct *work)
 {
-       struct mxser_port *info = private_;
-       struct tty_struct *tty;
-
-       tty = info->tty;
+       struct mxser_port *info = container_of(work, struct mxser_port, tqueue);
+       struct tty_struct *tty = info->tty;
 
        if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event))
                tty_wakeup(tty);
-       if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event))
-               tty_hangup(tty);
 }
 
 static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
@@ -461,7 +396,8 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
         * If non-blocking mode is set, or the port is not enabled,
         * then make the check up front and then exit.
         */
-       if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
+       if ((filp->f_flags & O_NONBLOCK) ||
+                       test_bit(TTY_IO_ERROR, &tty->flags)) {
                port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
        }
@@ -578,7 +514,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd)
  * the specified baud rate for a serial port.
  */
 static int mxser_change_speed(struct mxser_port *info,
-               struct termios *old_termios)
+               struct ktermios *old_termios)
 {
        unsigned cflag, cval, fcr;
        int ret = 0;
@@ -592,9 +528,6 @@ static int mxser_change_speed(struct mxser_port *info,
        if (!(info->ioaddr))
                return ret;
 
-#ifndef B921600
-#define B921600 (B460800 +1)
-#endif
        if (mxser_set_baud_method[info->tty->index] == 0) {
                baud = tty_get_baud_rate(info->tty);
                mxser_set_baud(info, baud);
@@ -636,12 +569,10 @@ static int mxser_change_speed(struct mxser_port *info,
                        fcr = 0;
        } else {
                fcr = UART_FCR_ENABLE_FIFO;
-               /* following add by Victor Yu. 08-30-2002 */
                if (info->board->chip_flag) {
                        fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
                        SET_MOXA_MUST_FIFO_VALUE(info);
                } else {
-                       /* above add by Victor Yu. 08-30-2002 */
                        switch (info->rx_trigger) {
                        case 1:
                                fcr |= UART_FCR_TRIGGER_1;
@@ -667,19 +598,8 @@ static int mxser_change_speed(struct mxser_port *info,
                info->IER |= UART_IER_MSI;
                if ((info->type == PORT_16550A) || (info->board->chip_flag)) {
                        info->MCR |= UART_MCR_AFE;
-/*                     status = mxser_get_msr(info->ioaddr, 0, info->port); */
-/*
-       save_flags(flags);
-       cli();
-       status = inb(baseaddr + UART_MSR);
-       restore_flags(flags);
-*/
-                       /* mxser_check_modem_status(info, status); */
                } else {
-/*                     status = mxser_get_msr(info->ioaddr, 0, info->port); */
-                       /* MX_LOCK(&info->slock); */
                        status = inb(info->ioaddr + UART_MSR);
-                       /* MX_UNLOCK(&info->slock); */
                        if (info->tty->hw_stopped) {
                                if (status & UART_MSR_CTS) {
                                        info->tty->hw_stopped = 0;
@@ -747,7 +667,6 @@ static int mxser_change_speed(struct mxser_port *info,
                                                UART_LSR_FE;
                }
        }
-       /* following add by Victor Yu. 09-02-2002 */
        if (info->board->chip_flag) {
                spin_lock_irqsave(&info->slock, flags);
                SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
@@ -762,18 +681,8 @@ static int mxser_change_speed(struct mxser_port *info,
                } else {
                        DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
                }
-               /*
-                  if ( I_IXANY(info->tty) ) {
-                  info->MCR |= MOXA_MUST_MCR_XON_ANY;
-                  ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->ioaddr);
-                  } else {
-                  info->MCR &= ~MOXA_MUST_MCR_XON_ANY;
-                  DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->ioaddr);
-                  }
-                */
                spin_unlock_irqrestore(&info->slock, flags);
        }
-       /* above add by Victor Yu. 09-02-2002 */
 
 
        outb(fcr, info->ioaddr + UART_FCR);     /* set fcr */
@@ -907,12 +816,9 @@ static int mxser_startup(struct mxser_port *info)
         * Finally, enable interrupts
         */
        info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-       /* info->IER = UART_IER_RLSI | UART_IER_RDI; */
 
-       /* following add by Victor Yu. 08-30-2002 */
        if (info->board->chip_flag)
                info->IER |= MOXA_MUST_IER_EGDAI;
-       /* above add by Victor Yu. 08-30-2002 */
        outb(info->IER, info->ioaddr + UART_IER);       /* enable interrupts */
 
        /*
@@ -972,13 +878,11 @@ static void mxser_shutdown(struct mxser_port *info)
        outb(info->MCR, info->ioaddr + UART_MCR);
 
        /* clear Rx/Tx FIFO's */
-       /* following add by Victor Yu. 08-30-2002 */
        if (info->board->chip_flag)
                outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
                                MOXA_MUST_FCR_GDA_MODE_ENABLE,
                                info->ioaddr + UART_FCR);
        else
-               /* above add by Victor Yu. 08-30-2002 */
                outb(UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT,
                        info->ioaddr + UART_FCR);
 
@@ -990,10 +894,8 @@ static void mxser_shutdown(struct mxser_port *info)
 
        info->flags &= ~ASYNC_INITIALIZED;
 
-       /* following add by Victor Yu. 09-23-2002 */
        if (info->board->chip_flag)
                SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->ioaddr);
-       /* above add by Victor Yu. 09-23-2002 */
 
        spin_unlock_irqrestore(&info->slock, flags);
 }
@@ -1046,12 +948,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
        info->session = process_session(current);
        info->pgrp = process_group(current);
 
-       /*
-       status = mxser_get_msr(info->base, 0, info->port);
-       mxser_check_modem_status(info, status);
-       */
-
-/* unmark here for very high baud rate (ex. 921600 bps) used */
+       /* unmark here for very high baud rate (ex. 921600 bps) used */
        tty->low_latency = 1;
        return 0;
 }
@@ -1068,7 +965,6 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
 
        unsigned long timeout;
        unsigned long flags;
-       struct tty_ldisc *ld;
 
        if (tty->index == MXSER_PORTS)
                return;
@@ -1126,9 +1022,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
        info->IER &= ~UART_IER_RLSI;
        if (info->board->chip_flag)
                info->IER &= ~MOXA_MUST_RECV_ISR;
-/* by William
-       info->read_status_mask &= ~UART_LSR_DR;
-*/
+
        if (info->flags & ASYNC_INITIALIZED) {
                outb(info->IER, info->ioaddr + UART_IER);
                /*
@@ -1148,12 +1042,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
        if (tty->driver->flush_buffer)
                tty->driver->flush_buffer(tty);
 
-       ld = tty_ldisc_ref(tty);
-       if (ld) {
-               if (ld->flush_buffer)
-                       ld->flush_buffer(tty);
-               tty_ldisc_deref(ld);
-       }
+       tty_ldisc_flush(tty);
 
        tty->closing = 0;
        info->event = 0;
@@ -1196,8 +1085,7 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
                total += c;
        }
 
-       if (info->xmit_cnt && !tty->stopped
-                       /*&& !(info->IER & UART_IER_THRI)*/) {
+       if (info->xmit_cnt && !tty->stopped) {
                if (!tty->hw_stopped ||
                                (info->type == PORT_16550A) ||
                                (info->board->chip_flag)) {
@@ -1228,7 +1116,7 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
        info->xmit_head &= SERIAL_XMIT_SIZE - 1;
        info->xmit_cnt++;
        spin_unlock_irqrestore(&info->slock, flags);
-       if (!tty->stopped /*&& !(info->IER & UART_IER_THRI)*/) {
+       if (!tty->stopped) {
                if (!tty->hw_stopped ||
                                (info->type == PORT_16550A) ||
                                info->board->chip_flag) {
@@ -1279,12 +1167,7 @@ static int mxser_write_room(struct tty_struct *tty)
 static int mxser_chars_in_buffer(struct tty_struct *tty)
 {
        struct mxser_port *info = tty->driver_data;
-       int len = info->xmit_cnt;
-
-       if (!(inb(info->ioaddr + UART_LSR) & UART_LSR_THRE))
-               len++;
-
-       return len;
+       return info->xmit_cnt;
 }
 
 static void mxser_flush_buffer(struct tty_struct *tty)
@@ -1297,18 +1180,14 @@ static void mxser_flush_buffer(struct tty_struct *tty)
        spin_lock_irqsave(&info->slock, flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
-       /* below added by shinhay */
        fcr = inb(info->ioaddr + UART_FCR);
        outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
                info->ioaddr + UART_FCR);
        outb(fcr, info->ioaddr + UART_FCR);
 
        spin_unlock_irqrestore(&info->slock, flags);
-       /* above added by shinhay */
 
-       wake_up_interruptible(&tty->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup) (tty);
+       tty_wakeup(tty);
 }
 
 /*
@@ -1377,10 +1256,9 @@ static int mxser_set_serial_info(struct mxser_port *info,
                info->closing_wait = new_serial.closing_wait * HZ / 100;
                info->tty->low_latency =
                                (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-               info->tty->low_latency = 0;     /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */
+               info->tty->low_latency = 0;
        }
 
-       /* added by casper, 3/17/2000, for mouse */
        info->type = new_serial.type;
 
        process_txrx_fifo(info);
@@ -1448,7 +1326,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
 
        if (tty->index == MXSER_PORTS)
                return -ENOIOCTLCMD;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (test_bit(TTY_IO_ERROR, &tty->flags))
                return -EIO;
 
        control = info->MCR;
@@ -1475,7 +1353,7 @@ static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
 
        if (tty->index == MXSER_PORTS)
                return -ENOIOCTLCMD;
-       if (tty->flags & (1 << TTY_IO_ERROR))
+       if (test_bit(TTY_IO_ERROR, &tty->flags))
                return -EIO;
 
        spin_lock_irqsave(&info->slock, flags);
@@ -1498,7 +1376,6 @@ static int mxser_tiocmset(struct tty_struct *tty, struct file *file,
 static int mxser_program_mode(int port)
 {
        int id, i, j, n;
-       /* unsigned long flags; */
 
        spin_lock(&gm_lock);
        outb(0, port);
@@ -1508,7 +1385,6 @@ static int mxser_program_mode(int port)
        (void)inb(port);
        outb(0, port);
        (void)inb(port);
-       /* restore_flags(flags); */
        spin_unlock(&gm_lock);
 
        id = inb(port + 1) & 0x1F;
@@ -1602,10 +1478,6 @@ static int mxser_read_register(int port, unsigned short *regs)
        return id;
 }
 
-#ifndef CMSPAR
-#define        CMSPAR 010000000000
-#endif
-
 static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 {
        struct mxser_port *port;
@@ -1695,7 +1567,6 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                        continue;
 
                                status = mxser_get_msr(port->ioaddr, 0, i);
-/*                             mxser_check_modem_status(port, status); */
 
                                if (status & UART_MSR_TERI)
                                        port->icount.rng++;
@@ -1779,7 +1650,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
        if (tty->index == MXSER_PORTS)
                return mxser_ioctl_special(cmd, argp);
 
-       /* following add by Victor Yu. 01-05-2004 */
        if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
                int p;
                unsigned long opmode;
@@ -1811,12 +1681,11 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                }
                return 0;
        }
-       /* above add by Victor Yu. 01-05-2004 */
 
-       if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
-               if (tty->flags & (1 << TTY_IO_ERROR))
-                       return -EIO;
-       }
+       if (cmd != TIOCGSERIAL && cmd != TIOCMIWAIT && cmd != TIOCGICOUNT &&
+                       test_bit(TTY_IO_ERROR, &tty->flags))
+               return -EIO;
+
        switch (cmd) {
        case TCSBRK:            /* SVID version: non-zero arg --> no break */
                retval = tty_check_change(tty);
@@ -1901,7 +1770,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                cnow = info->icount;
                spin_unlock_irqrestore(&info->slock, flags);
                p_cuser = argp;
-               /* modified by casper 1/11/2000 */
                if (put_user(cnow.frame, &p_cuser->frame))
                        return -EFAULT;
                if (put_user(cnow.brk, &p_cuser->brk))
@@ -1927,7 +1795,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                info->mon_data.rxcnt = 0;
                info->mon_data.txcnt = 0;
                return 0;
-/* (above) added by James. */
        case MOXA_ASPP_SETBAUD:{
                long baud;
                if (get_user(baud, (long __user *)argp))
@@ -1958,8 +1825,6 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
        case MOXA_ASPP_MON: {
                int mcr, status;
 
-               /* info->mon_data.ser_param = tty->termios->c_cflag; */
-
                status = mxser_get_msr(info->ioaddr, 1, tty->index);
                mxser_check_modem_status(info, status);
 
@@ -2016,11 +1881,10 @@ static void mxser_stoprx(struct tty_struct *tty)
 
        info->ldisc_stop_rx = 1;
        if (I_IXOFF(tty)) {
-               /* following add by Victor Yu. 09-02-2002 */
                if (info->board->chip_flag) {
                        info->IER &= ~MOXA_MUST_RECV_ISR;
                        outb(info->IER, info->ioaddr + UART_IER);
-               } else if (!(info->flags & ASYNC_CLOSING)) {
+               } else {
                        info->x_char = STOP_CHAR(tty);
                        outb(0, info->ioaddr + UART_IER);
                        info->IER |= UART_IER_THRI;
@@ -2053,11 +1917,10 @@ static void mxser_unthrottle(struct tty_struct *tty)
                if (info->x_char)
                        info->x_char = 0;
                else {
-                       /* following add by Victor Yu. 09-02-2002 */
                        if (info->board->chip_flag) {
                                info->IER |= MOXA_MUST_RECV_ISR;
                                outb(info->IER, info->ioaddr + UART_IER);
-                       } else if (!(info->flags & ASYNC_CLOSING)) {
+                       } else {
                                info->x_char = START_CHAR(tty);
                                outb(0, info->ioaddr + UART_IER);
                                info->IER |= UART_IER_THRI;
@@ -2097,8 +1960,7 @@ static void mxser_start(struct tty_struct *tty)
        unsigned long flags;
 
        spin_lock_irqsave(&info->slock, flags);
-       if (info->xmit_cnt && info->xmit_buf
-                       /* && !(info->IER & UART_IER_THRI) */) {
+       if (info->xmit_cnt && info->xmit_buf) {
                outb(info->IER & ~UART_IER_THRI, info->ioaddr + UART_IER);
                info->IER |= UART_IER_THRI;
                outb(info->IER, info->ioaddr + UART_IER);
@@ -2106,7 +1968,7 @@ static void mxser_start(struct tty_struct *tty)
        spin_unlock_irqrestore(&info->slock, flags);
 }
 
-static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
        struct mxser_port *info = tty->driver_data;
        unsigned long flags;
@@ -2123,18 +1985,16 @@ static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termio
                }
        }
 
-/* Handle sw stopped */
+       /* Handle sw stopped */
        if ((old_termios->c_iflag & IXON) &&
                        !(tty->termios->c_iflag & IXON)) {
                tty->stopped = 0;
 
-               /* following add by Victor Yu. 09-02-2002 */
                if (info->board->chip_flag) {
                        spin_lock_irqsave(&info->slock, flags);
                        DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
                        spin_unlock_irqrestore(&info->slock, flags);
                }
-               /* above add by Victor Yu. 09-02-2002 */
 
                mxser_start(tty);
        }
@@ -2203,7 +2063,6 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
 #endif
 }
 
-
 /*
  * This routine is called by tty_hangup() when a hangup is signaled.
  */
@@ -2220,8 +2079,6 @@ void mxser_hangup(struct tty_struct *tty)
        wake_up_interruptible(&info->open_wait);
 }
 
-
-/* added by James 03-12-2004. */
 /*
  * mxser_rs_break() --- routine which turns the break handling on or off
  */
@@ -2240,8 +2097,6 @@ static void mxser_rs_break(struct tty_struct *tty, int break_state)
        spin_unlock_irqrestore(&info->slock, flags);
 }
 
-/* (above) added by James. */
-
 static void mxser_receive_chars(struct mxser_port *port, int *status)
 {
        struct tty_struct *tty = port->tty;
@@ -2255,36 +2110,26 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
        spin_lock_irqsave(&port->slock, flags);
 
        recv_room = tty->receive_room;
-       if ((recv_room == 0) && (!port->ldisc_stop_rx)) {
-               /* mxser_throttle(tty); */
+       if ((recv_room == 0) && (!port->ldisc_stop_rx))
                mxser_stoprx(tty);
-               /* return; */
-       }
 
-       /* following add by Victor Yu. 09-02-2002 */
        if (port->board->chip_flag != MOXA_OTHER_UART) {
 
                if (*status & UART_LSR_SPECIAL)
                        goto intr_old;
-               /* following add by Victor Yu. 02-11-2004 */
                if (port->board->chip_flag == MOXA_MUST_MU860_HWID &&
                                (*status & MOXA_MUST_LSR_RERR))
                        goto intr_old;
-               /* above add by Victor Yu. 02-14-2004 */
                if (*status & MOXA_MUST_LSR_RERR)
                        goto intr_old;
 
                gdl = inb(port->ioaddr + MOXA_MUST_GDL_REGISTER);
 
-               /* add by Victor Yu. 02-11-2004 */
                if (port->board->chip_flag == MOXA_MUST_MU150_HWID)
                        gdl &= MOXA_MUST_GDL_MASK;
                if (gdl >= recv_room) {
-                       if (!port->ldisc_stop_rx) {
-                               /* mxser_throttle(tty); */
+                       if (!port->ldisc_stop_rx)
                                mxser_stoprx(tty);
-                       }
-                       /* return; */
                }
                while (gdl--) {
                        ch = inb(port->ioaddr + UART_RX);
@@ -2293,20 +2138,16 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
                }
                goto end_intr;
        }
- intr_old:
-       /* above add by Victor Yu. 09-02-2002 */
+intr_old:
 
        do {
                if (max-- < 0)
                        break;
 
                ch = inb(port->ioaddr + UART_RX);
-               /* following add by Victor Yu. 09-02-2002 */
-               if (port->board->chip_flag && (*status & UART_LSR_OE)
-                               /*&& !(*status&UART_LSR_DR) */)
+               if (port->board->chip_flag && (*status & UART_LSR_OE))
                        outb(0x23, port->ioaddr + UART_FCR);
                *status &= port->read_status_mask;
-               /* above add by Victor Yu. 09-02-2002 */
                if (*status & port->ignore_status_mask) {
                        if (++ignored > 100)
                                break;
@@ -2315,52 +2156,38 @@ static void mxser_receive_chars(struct mxser_port *port, int *status)
                        if (*status & UART_LSR_SPECIAL) {
                                if (*status & UART_LSR_BI) {
                                        flag = TTY_BREAK;
-/* added by casper 1/11/2000 */
                                        port->icount.brk++;
 
                                        if (port->flags & ASYNC_SAK)
                                                do_SAK(tty);
                                } else if (*status & UART_LSR_PE) {
                                        flag = TTY_PARITY;
-/* added by casper 1/11/2000 */
                                        port->icount.parity++;
                                } else if (*status & UART_LSR_FE) {
                                        flag = TTY_FRAME;
-/* added by casper 1/11/2000 */
                                        port->icount.frame++;
                                } else if (*status & UART_LSR_OE) {
                                        flag = TTY_OVERRUN;
-/* added by casper 1/11/2000 */
                                        port->icount.overrun++;
-                               } else
-                                       flags = TTY_BREAK;
-                       } else
-                               flags = 0;
+                               }
+                       }
                        tty_insert_flip_char(tty, ch, flag);
                        cnt++;
                        if (cnt >= recv_room) {
-                               if (!port->ldisc_stop_rx) {
-                                       /* mxser_throttle(tty); */
+                               if (!port->ldisc_stop_rx)
                                        mxser_stoprx(tty);
-                               }
                                break;
                        }
 
                }
 
-               /* following add by Victor Yu. 09-02-2002 */
                if (port->board->chip_flag)
                        break;
 
-               /* mask by Victor Yu. 09-02-2002
-                *status = inb(port->ioaddr + UART_LSR) & port->read_status_mask;
-                */
-               /* following add by Victor Yu. 09-02-2002 */
                *status = inb(port->ioaddr + UART_LSR);
-               /* above add by Victor Yu. 09-02-2002 */
        } while (*status & UART_LSR_DR);
 
-end_intr:              /* add by Victor Yu. 09-02-2002 */
+end_intr:
        mxvar_log.rxcnt[port->tty->index] += cnt;
        port->mon_data.rxcnt += cnt;
        port->mon_data.up_rxcnt += cnt;
@@ -2382,8 +2209,6 @@ static void mxser_transmit_chars(struct mxser_port *port)
                mxvar_log.txcnt[port->tty->index]++;
                port->mon_data.txcnt++;
                port->mon_data.up_txcnt++;
-
-/* added by casper 1/11/2000 */
                port->icount.tx++;
                goto unlock;
        }
@@ -2391,14 +2216,8 @@ static void mxser_transmit_chars(struct mxser_port *port)
        if (port->xmit_buf == 0)
                goto unlock;
 
-       if (port->xmit_cnt == 0) {
-               if (port->xmit_cnt < WAKEUP_CHARS) { /* XXX what's this for?? */
-                       set_bit(MXSER_EVENT_TXLOW, &port->event);
-                       schedule_work(&port->tqueue);
-               }
-               goto unlock;
-       }
-       if (port->tty->stopped || (port->tty->hw_stopped &&
+       if ((port->xmit_cnt <= 0) || port->tty->stopped ||
+                       (port->tty->hw_stopped &&
                        (port->type != PORT_16550A) &&
                        (!port->board->chip_flag))) {
                port->IER &= ~UART_IER_THRI;
@@ -2417,11 +2236,8 @@ static void mxser_transmit_chars(struct mxser_port *port)
        } while (--count > 0);
        mxvar_log.txcnt[port->tty->index] += (cnt - port->xmit_cnt);
 
-/* added by James 03-12-2004. */
        port->mon_data.txcnt += (cnt - port->xmit_cnt);
        port->mon_data.up_txcnt += (cnt - port->xmit_cnt);
-
-/* added by casper 1/11/2000 */
        port->icount.tx += (cnt - port->xmit_cnt);
 
        if (port->xmit_cnt < WAKEUP_CHARS) {
@@ -2439,7 +2255,7 @@ unlock:
 /*
  * This is the serial driver's generic interrupt routine
  */
-static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mxser_interrupt(int irq, void *dev_id)
 {
        int status, iir, i;
        struct mxser_board *brd = NULL;
@@ -2449,8 +2265,6 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        unsigned int int_cnt;
        int handled = IRQ_NONE;
 
-       /* spin_lock(&gm_lock); */
-
        for (i = 0; i < MXSER_BOARDS; i++)
                if (dev_id == &mxser_boards[i]) {
                        brd = dev_id;
@@ -2461,7 +2275,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                goto irq_stop;
        if (brd == NULL)
                goto irq_stop;
-       max = mxser_numports[brd->board_type - 1];
+       max = brd->info->nports;
        while (1) {
                irqbits = inb(brd->vector) & brd->vector_mask;
                if (irqbits == brd->vector_mask)
@@ -2477,7 +2291,6 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
                        int_cnt = 0;
                        do {
-                               /* following add by Victor Yu. 09-13-2002 */
                                iir = inb(port->ioaddr + UART_IIR);
                                if (iir & UART_IIR_NO_INT)
                                        break;
@@ -2488,9 +2301,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                        inb(port->ioaddr + UART_MSR);
                                        break;
                                }
-                               /* above add by Victor Yu. 09-13-2002 */
 
-                               /* following add by Victor Yu. 09-02-2002 */
                                status = inb(port->ioaddr + UART_LSR);
 
                                if (status & UART_LSR_PE)
@@ -2504,12 +2315,6 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                        port->err_shadow |= NPPI_NOTIFY_BREAK;
 
                                if (port->board->chip_flag) {
-                                       /*
-                                          if ( (status & 0x02) && !(status & 0x01) ) {
-                                          outb(port->ioaddr+UART_FCR,  0x23);
-                                          continue;
-                                          }
-                                        */
                                        if (iir == MOXA_MUST_IIR_GDA ||
                                            iir == MOXA_MUST_IIR_RDA ||
                                            iir == MOXA_MUST_IIR_RTO ||
@@ -2518,8 +2323,6 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                                                &status);
 
                                } else {
-                                       /* above add by Victor Yu. 09-02-2002 */
-
                                        status &= port->read_status_mask;
                                        if (status & UART_LSR_DR)
                                                mxser_receive_chars(port,
@@ -2529,14 +2332,11 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                if (msr & UART_MSR_ANY_DELTA)
                                        mxser_check_modem_status(port, msr);
 
-                               /* following add by Victor Yu. 09-13-2002 */
                                if (port->board->chip_flag) {
                                        if (iir == 0x02 && (status &
                                                                UART_LSR_THRE))
                                                mxser_transmit_chars(port);
                                } else {
-                                       /* above add by Victor Yu. 09-13-2002 */
-
                                        if (status & UART_LSR_THRE)
                                                mxser_transmit_chars(port);
                                }
@@ -2546,8 +2346,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        break;  /* Prevent infinite loops */
        }
 
-      irq_stop:
-       /* spin_unlock(&gm_lock); */
+irq_stop:
        return handled;
 }
 
@@ -2577,7 +2376,25 @@ static const struct tty_operations mxser_ops = {
  * The MOXA Smartio/Industio serial driver boot-time initialization code!
  */
 
-static int __devinit mxser_initbrd(struct mxser_board *brd)
+static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
+               unsigned int irq)
+{
+       if (irq)
+               free_irq(brd->irq, brd);
+       if (pdev != NULL) {     /* PCI */
+#ifdef CONFIG_PCI
+               pci_release_region(pdev, 2);
+               pci_release_region(pdev, 3);
+               pci_dev_put(pdev);
+#endif
+       } else {
+               release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
+               release_region(brd->vector, 1);
+       }
+}
+
+static int __devinit mxser_initbrd(struct mxser_board *brd,
+               struct pci_dev *pdev)
 {
        struct mxser_port *info;
        unsigned int i;
@@ -2585,7 +2402,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd)
 
        printk(KERN_INFO "max. baud rate = %d bps.\n", brd->ports[0].max_baud);
 
-       for (i = 0; i < brd->nports; i++) {
+       for (i = 0; i < brd->info->nports; i++) {
                info = &brd->ports[i];
                info->board = brd;
                info->stop_rx = 0;
@@ -2603,7 +2420,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd)
                info->custom_divisor = info->baud_base * 16;
                info->close_delay = 5 * HZ / 10;
                info->closing_wait = 30 * HZ;
-               INIT_WORK(&info->tqueue, mxser_do_softint, info);
+               INIT_WORK(&info->tqueue, mxser_do_softint);
                info->normal_termios = mxvar_sdriver->init_termios;
                init_waitqueue_head(&info->open_wait);
                init_waitqueue_head(&info->close_wait);
@@ -2626,7 +2443,9 @@ static int __devinit mxser_initbrd(struct mxser_board *brd)
        if (retval) {
                printk(KERN_ERR "Board %s: Request irq failed, IRQ (%d) may "
                        "conflict with another device.\n",
-                       mxser_brdname[brd->board_type - 1], brd->irq);
+                       brd->info->name, brd->irq);
+               /* We hold resources, we need to release them. */
+               mxser_release_res(brd, pdev, 0);
                return retval;
        }
        return 0;
@@ -2641,40 +2460,44 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
        brd->chip_flag = MOXA_OTHER_UART;
 
        id = mxser_read_register(cap, regs);
-       if (id == C168_ASIC_ID) {
-               brd->board_type = MXSER_BOARD_C168_ISA;
-               brd->nports = 8;
-       } else if (id == C104_ASIC_ID) {
-               brd->board_type = MXSER_BOARD_C104_ISA;
-               brd->nports = 4;
-       } else if (id == C102_ASIC_ID) {
-               brd->board_type = MXSER_BOARD_C102_ISA;
-               brd->nports = 2;
-       } else if (id == CI132_ASIC_ID) {
-               brd->board_type = MXSER_BOARD_CI132;
-               brd->nports = 2;
-       } else if (id == CI134_ASIC_ID) {
-               brd->board_type = MXSER_BOARD_CI134;
-               brd->nports = 4;
-       } else if (id == CI104J_ASIC_ID) {
-               brd->board_type = MXSER_BOARD_CI104J;
-               brd->nports = 4;
-       } else
+       switch (id) {
+       case C168_ASIC_ID:
+               brd->info = &mxser_cards[0];
+               break;
+       case C104_ASIC_ID:
+               brd->info = &mxser_cards[1];
+               break;
+       case CI104J_ASIC_ID:
+               brd->info = &mxser_cards[2];
+               break;
+       case C102_ASIC_ID:
+               brd->info = &mxser_cards[5];
+               break;
+       case CI132_ASIC_ID:
+               brd->info = &mxser_cards[6];
+               break;
+       case CI134_ASIC_ID:
+               brd->info = &mxser_cards[7];
+               break;
+       default:
                return 0;
+       }
 
        irq = 0;
-       if (brd->nports == 2) {
+       /* some ISA cards have 2 ports, but we want to see them as 4-port (why?)
+          Flag-hack checks if configuration should be read as 2-port here. */
+       if (brd->info->nports == 2 || (brd->info->flags & MXSER_HAS2)) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                if (irq != (regs[9] & 0xFF00))
                        return MXSER_ERR_IRQ_CONFLIT;
-       } else if (brd->nports == 4) {
+       } else if (brd->info->nports == 4) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                irq = irq | (irq >> 8);
                if (irq != regs[9])
                        return MXSER_ERR_IRQ_CONFLIT;
-       } else if (brd->nports == 8) {
+       } else if (brd->info->nports == 8) {
                irq = regs[9] & 0xF000;
                irq = irq | (irq >> 4);
                irq = irq | (irq >> 8);
@@ -2697,10 +2520,10 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
        for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
                if (regs[12] & bits) {
                        brd->ports[i].baud_base = 921600;
-                       brd->ports[i].max_baud = 921600;        /* add by Victor Yu. 09-04-2002 */
+                       brd->ports[i].max_baud = 921600;
                } else {
                        brd->ports[i].baud_base = 115200;
-                       brd->ports[i].max_baud = 115200;        /* add by Victor Yu. 09-04-2002 */
+                       brd->ports[i].max_baud = 115200;
                }
        }
        scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
@@ -2714,35 +2537,55 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
                brd->uart_type = PORT_16550A;
        else
                brd->uart_type = PORT_16450;
-       if (id == 1)
-               brd->nports = 8;
-       else
-               brd->nports = 4;
-       if (!request_region(brd->ports[0].ioaddr, 8 * brd->nports, "mxser(IO)"))
+       if (!request_region(brd->ports[0].ioaddr, 8 * brd->info->nports,
+                       "mxser(IO)"))
                return MXSER_ERR_IOADDR;
        if (!request_region(brd->vector, 1, "mxser(vector)")) {
-               release_region(brd->ports[0].ioaddr, 8 * brd->nports);
+               release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
                return MXSER_ERR_VECTOR;
        }
-       return brd->nports;
+       return brd->info->nports;
 }
 
-static int __init mxser_get_PCI_conf(int board_type, struct mxser_board *brd,
-               struct pci_dev *pdev)
+static int __devinit mxser_probe(struct pci_dev *pdev,
+               const struct pci_device_id *ent)
 {
+#ifdef CONFIG_PCI
+       struct mxser_board *brd;
        unsigned int i, j;
        unsigned long ioaddress;
-       int retval;
+       int retval = -EINVAL;
+
+       for (i = 0; i < MXSER_BOARDS; i++)
+               if (mxser_boards[i].info == NULL)
+                       break;
+
+       if (i >= MXSER_BOARDS) {
+               printk(KERN_ERR "Too many Smartio/Industio family boards found "
+                       "(maximum %d), board not configured\n", MXSER_BOARDS);
+               goto err;
+       }
+
+       brd = &mxser_boards[i];
+       brd->idx = i * MXSER_PORTS_PER_BOARD;
+       printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
+               mxser_cards[ent->driver_data].name,
+               pdev->bus->number, PCI_SLOT(pdev->devfn));
+
+       retval = pci_enable_device(pdev);
+       if (retval) {
+               printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+               goto err;
+       }
 
        /* io address */
-       brd->board_type = board_type;
-       brd->nports = mxser_numports[board_type - 1];
        ioaddress = pci_resource_start(pdev, 2);
        retval = pci_request_region(pdev, 2, "mxser(IO)");
        if (retval)
                goto err;
 
-       for (i = 0; i < brd->nports; i++)
+       brd->info = &mxser_cards[ent->driver_data];
+       for (i = 0; i < brd->info->nports; i++)
                brd->ports[i].ioaddr = ioaddress + 8 * i;
 
        /* vector */
@@ -2759,14 +2602,14 @@ static int __init mxser_get_PCI_conf(int board_type, struct mxser_board *brd,
        brd->uart_type = PORT_16550A;
        brd->vector_mask = 0;
 
-       for (i = 0; i < brd->nports; i++) {
+       for (i = 0; i < brd->info->nports; i++) {
                for (j = 0; j < UART_INFO_NUM; j++) {
                        if (Gpci_uart_info[j].type == brd->chip_flag) {
                                brd->ports[i].max_baud =
                                        Gpci_uart_info[j].max_baud;
 
                                /* exception....CP-102 */
-                               if (board_type == MXSER_BOARD_CP102)
+                               if (brd->info->flags & MXSER_HIGHBAUD)
                                        brd->ports[i].max_baud = 921600;
                                break;
                        }
@@ -2774,7 +2617,7 @@ static int __init mxser_get_PCI_conf(int board_type, struct mxser_board *brd,
        }
 
        if (brd->chip_flag == MOXA_MUST_MU860_HWID) {
-               for (i = 0; i < brd->nports; i++) {
+               for (i = 0; i < brd->info->nports; i++) {
                        if (i < 4)
                                brd->ports[i].opmode_ioaddr = ioaddress + 4;
                        else
@@ -2784,23 +2627,57 @@ static int __init mxser_get_PCI_conf(int board_type, struct mxser_board *brd,
                outb(0, ioaddress + 0x0c);      /* default set to RS232 mode */
        }
 
-       for (i = 0; i < brd->nports; i++) {
+       for (i = 0; i < brd->info->nports; i++) {
                brd->vector_mask |= (1 << i);
                brd->ports[i].baud_base = 921600;
        }
+
+       /* mxser_initbrd will hook ISR. */
+       if (mxser_initbrd(brd, pdev) < 0)
+               goto err_relvec;
+
+       for (i = 0; i < brd->info->nports; i++)
+               tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+
+       pci_set_drvdata(pdev, brd);
+
        return 0;
+err_relvec:
+       pci_release_region(pdev, 3);
 err_relio:
        pci_release_region(pdev, 2);
+       brd->info = NULL;
 err:
        return retval;
+#else
+       return -ENODEV;
+#endif
 }
 
+static void __devexit mxser_remove(struct pci_dev *pdev)
+{
+       struct mxser_board *brd = pci_get_drvdata(pdev);
+       unsigned int i;
+
+       for (i = 0; i < brd->info->nports; i++)
+               tty_unregister_device(mxvar_sdriver, brd->idx + i);
+
+       mxser_release_res(brd, pdev, 1);
+}
+
+static struct pci_driver mxser_driver = {
+       .name = "mxser",
+       .id_table = mxser_pcibrds,
+       .probe = mxser_probe,
+       .remove = __devexit_p(mxser_remove)
+};
+
 static int __init mxser_module_init(void)
 {
-       struct pci_dev *pdev = NULL;
        struct mxser_board *brd;
-       unsigned int i, m;
-       int retval, b, n;
+       unsigned long cap;
+       unsigned int i, m, isaloop;
+       int retval, b;
 
        pr_debug("Loading module mxser ...\n");
 
@@ -2809,15 +2686,13 @@ static int __init mxser_module_init(void)
                return -ENOMEM;
        spin_lock_init(&gm_lock);
 
-       for (i = 0; i < MXSER_BOARDS; i++)
-               mxser_boards[i].board_type = -1;
-
        printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
                MXSER_VERSION);
 
        /* Initialize the tty_driver structure */
+       mxvar_sdriver->owner = THIS_MODULE;
        mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
-       mxvar_sdriver->name = "ttyM";
+       mxvar_sdriver->name = "ttyMI";
        mxvar_sdriver->major = ttymajor;
        mxvar_sdriver->minor_start = 0;
        mxvar_sdriver->num = MXSER_PORTS + 1;
@@ -2825,204 +2700,112 @@ static int __init mxser_module_init(void)
        mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
        mxvar_sdriver->init_termios = tty_std_termios;
        mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
-       mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
+       mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(mxvar_sdriver, &mxser_ops);
-       mxvar_sdriver->ttys = mxvar_tty;
-       mxvar_sdriver->termios = mxvar_termios;
-       mxvar_sdriver->termios_locked = mxvar_termios_locked;
+
+       retval = tty_register_driver(mxvar_sdriver);
+       if (retval) {
+               printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family "
+                               "tty driver !\n");
+               goto err_put;
+       }
 
        mxvar_diagflag = 0;
 
        m = 0;
        /* Start finding ISA boards here */
-       for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
-               int cap;
-
-               if (!(cap = mxserBoardCAP[b]))
-                       continue;
-
-               brd = &mxser_boards[m];
-               retval = mxser_get_ISA_conf(cap, brd);
-
-               if (retval != 0)
-                       printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
-                               mxser_brdname[brd->board_type - 1], ioaddr[b]);
-
-               if (retval <= 0) {
-                       if (retval == MXSER_ERR_IRQ)
-                               printk(KERN_ERR "Invalid interrupt number, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                               printk(KERN_ERR "Invalid interrupt number, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_VECTOR)
-                               printk(KERN_ERR "Invalid interrupt vector, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_IOADDR)
-                               printk(KERN_ERR "Invalid I/O address, "
-                                       "board not configured\n");
-
-                       continue;
-               }
-
-               brd->pdev = NULL;
-
-               /* mxser_initbrd will hook ISR. */
-               if (mxser_initbrd(brd) < 0)
-                       continue;
-
-               m++;
-       }
-
-       /* Start finding ISA boards from module arg */
-       for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
-               unsigned long cap;
-
-               if (!(cap = ioaddr[b]))
-                       continue;
-
-               brd = &mxser_boards[m];
-               retval = mxser_get_ISA_conf(cap, &mxser_boards[m]);
-
-               if (retval != 0)
-                       printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
-                               mxser_brdname[brd->board_type - 1], ioaddr[b]);
-
-               if (retval <= 0) {
-                       if (retval == MXSER_ERR_IRQ)
-                               printk(KERN_ERR "Invalid interrupt number, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                               printk(KERN_ERR "Invalid interrupt number, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_VECTOR)
-                               printk(KERN_ERR "Invalid interrupt vector, "
-                                       "board not configured\n");
-                       else if (retval == MXSER_ERR_IOADDR)
-                               printk(KERN_ERR "Invalid I/O address, "
-                                       "board not configured\n");
+       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 */
 
-                       continue;
-               }
+                       if (!cap)
+                               continue;
 
-               brd->pdev = NULL;
-               /* mxser_initbrd will hook ISR. */
-               if (mxser_initbrd(brd) < 0)
-                       continue;
+                       brd = &mxser_boards[m];
+                       retval = mxser_get_ISA_conf(cap, brd);
 
-               m++;
-       }
+                       if (retval != 0)
+                               printk(KERN_INFO "Found MOXA %s board "
+                                       "(CAP=0x%x)\n",
+                                       brd->info->name, ioaddr[b]);
 
-       /* start finding PCI board here */
-       n = ARRAY_SIZE(mxser_pcibrds) - 1;
-       b = 0;
-       while (b < n) {
-               pdev = pci_get_device(mxser_pcibrds[b].vendor,
-                               mxser_pcibrds[b].device, pdev);
-               if (pdev == NULL) {
-                       b++;
-                       continue;
-               }
-               printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
-                       mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1],
-                       pdev->bus->number, PCI_SLOT(pdev->devfn));
-               if (m >= MXSER_BOARDS)
-                       printk(KERN_ERR
-                               "Too many Smartio/Industio family boards find "
-                               "(maximum %d), board not configured\n",
-                               MXSER_BOARDS);
-               else {
-                       if (pci_enable_device(pdev)) {
-                               printk(KERN_ERR "Moxa SmartI/O PCI enable "
-                                       "fail !\n");
-                               continue;
-                       }
-                       brd = &mxser_boards[m];
-                       brd->pdev = pdev;
-                       retval = mxser_get_PCI_conf(
-                                       (int)mxser_pcibrds[b].driver_data,
-                                       brd, pdev);
-                       if (retval < 0) {
+                       if (retval <= 0) {
                                if (retval == MXSER_ERR_IRQ)
-                                       printk(KERN_ERR
-                                               "Invalid interrupt number, "
-                                               "board not configured\n");
+                                       printk(KERN_ERR "Invalid interrupt "
+                                               "number, board not "
+                                               "configured\n");
                                else if (retval == MXSER_ERR_IRQ_CONFLIT)
-                                       printk(KERN_ERR
-                                               "Invalid interrupt number, "
-                                               "board not configured\n");
+                                       printk(KERN_ERR "Invalid interrupt "
+                                               "number, board not "
+                                               "configured\n");
                                else if (retval == MXSER_ERR_VECTOR)
-                                       printk(KERN_ERR
-                                               "Invalid interrupt vector, "
-                                               "board not configured\n");
+                                       printk(KERN_ERR "Invalid interrupt "
+                                               "vector, board not "
+                                               "configured\n");
                                else if (retval == MXSER_ERR_IOADDR)
-                                       printk(KERN_ERR
-                                               "Invalid I/O address, "
+                                       printk(KERN_ERR "Invalid I/O address, "
                                                "board not configured\n");
+
+                               brd->info = NULL;
                                continue;
                        }
+
                        /* mxser_initbrd will hook ISR. */
-                       if (mxser_initbrd(brd) < 0)
+                       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);
+
                        m++;
-                       /* Keep an extra reference if we succeeded. It will
-                          be returned at unload time */
-                       pci_dev_get(pdev);
                }
-       }
 
-       retval = tty_register_driver(mxvar_sdriver);
+       retval = pci_register_driver(&mxser_driver);
        if (retval) {
-               printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family"
-                               " driver !\n");
-               put_tty_driver(mxvar_sdriver);
-
-               for (i = 0; i < MXSER_BOARDS; i++) {
-                       if (mxser_boards[i].board_type == -1)
-                               continue;
-                       else {
-                               free_irq(mxser_boards[i].irq, &mxser_boards[i]);
-                               /* todo: release io, vector */
-                       }
-               }
-               return retval;
+               printk(KERN_ERR "Can't register pci driver\n");
+               if (!m) {
+                       retval = -ENODEV;
+                       goto err_unr;
+               } /* else: we have some ISA cards under control */
        }
 
        pr_debug("Done.\n");
 
+       return 0;
+err_unr:
+       tty_unregister_driver(mxvar_sdriver);
+err_put:
+       put_tty_driver(mxvar_sdriver);
        return retval;
 }
 
 static void __exit mxser_module_exit(void)
 {
-       int i, err;
+       unsigned int i, j;
 
        pr_debug("Unloading module mxser ...\n");
 
-       err = tty_unregister_driver(mxvar_sdriver);
-       if (!err)
-               put_tty_driver(mxvar_sdriver);
-       else
-               printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n");
+       pci_unregister_driver(&mxser_driver);
 
-       for (i = 0; i < MXSER_BOARDS; i++) {
-               struct pci_dev *pdev;
+       for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
+               if (mxser_boards[i].info != NULL)
+                       for (j = 0; j < mxser_boards[i].info->nports; j++)
+                               tty_unregister_device(mxvar_sdriver,
+                                               mxser_boards[i].idx + j);
+       tty_unregister_driver(mxvar_sdriver);
+       put_tty_driver(mxvar_sdriver);
+
+       for (i = 0; i < MXSER_BOARDS; i++)
+               if (mxser_boards[i].info != NULL)
+                       mxser_release_res(&mxser_boards[i], NULL, 1);
 
-               if (mxser_boards[i].board_type == -1)
-                       continue;
-               else {
-                       pdev = mxser_boards[i].pdev;
-                       free_irq(mxser_boards[i].irq, &mxser_boards[i]);
-                       if (pdev != NULL) {     /* PCI */
-                               pci_release_region(pdev, 2);
-                               pci_release_region(pdev, 3);
-                               pci_dev_put(pdev);
-                       } else {
-                               release_region(mxser_boards[i].ports[0].ioaddr, 8 * mxser_boards[i].nports);
-                               release_region(mxser_boards[i].vector, 1);
-                       }
-               }
-       }
        pr_debug("Done.\n");
 }