Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[safe/jmp/linux-2.6] / drivers / char / mxser_new.c
index 4c80549..081c84c 100644 (file)
@@ -2,7 +2,7 @@
  *          mxser.c  -- MOXA Smartio/Industio family multiport serial driver.
  *
  *      Copyright (C) 1999-2006  Moxa Technologies (support@moxa.com.tw).
- *     Copyright (C) 2006       Jiri Slaby <jirislaby@gmail.com>
+ *     Copyright (C) 2006-2007  Jiri Slaby <jirislaby@gmail.com>
  *
  *      This code is loosely based on the 1.8 moxa driver which is based on
  *     Linux serial driver, written by Linus Torvalds, Theodore T'so and
 #include <linux/gfp.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <linux/bitops.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/bitops.h>
 #include <asm/uaccess.h>
 
 #include "mxser_new.h"
 
-#define        MXSER_VERSION   "2.0.1"         /* 1.9.15 */
+#define        MXSER_VERSION   "2.0.2"         /* 1.10 */
 #define        MXSERMAJOR       174
 #define        MXSERCUMAJOR     175
 
 #define UART_MCR_AFE           0x20
 #define UART_LSR_SPECIAL       0x1E
 
-#define RELEVANT_IFLAG(iflag)  (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
-                                         IXON|IXOFF))
+#define PCI_DEVICE_ID_CB108    0x1080
+#define PCI_DEVICE_ID_CB114    0x1142
+#define PCI_DEVICE_ID_CB134I   0x1341
+#define PCI_DEVICE_ID_CP138U   0x1380
+#define PCI_DEVICE_ID_POS104UL 0x1044
+
 
 #define C168_ASIC_ID    1
 #define C104_ASIC_ID    2
@@ -110,71 +113,63 @@ struct mxser_cardinfo {
 };
 
 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 */
+/* 0*/ { 8, "C168 series", },
+       { 4, "C104 series", },
+       { 4, "CI-104J series", },
+       { 8, "C168H/PCI series", },
+       { 4, "C104H/PCI series", },
+/* 5*/ { 4, "C102 series", MXSER_HAS2 },       /* C102-ISA */
+       { 4, "CI-132 series", MXSER_HAS2 },
+       { 4, "CI-134 series", },
+       { 2, "CP-132 series", },
+       { 4, "CP-114 series", },
+/*10*/ { 4, "CT-114 series", },
+       { 2, "CP-102 series", MXSER_HIGHBAUD },
+       { 4, "CP-104U series", },
+       { 8, "CP-168U series", },
+       { 2, "CP-132U series", },
+/*15*/ { 4, "CP-134U series", },
+       { 4, "CP-104JU series", },
        { 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 */
+       { 8, "CP-118U series", },
+       { 2, "CP-102UL series", },
+/*20*/ { 2, "CP-102U series", },
+       { 8, "CP-118EL series", },
+       { 8, "CP-168EL series", },
+       { 4, "CP-104EL series", },
+       { 8, "CB-108 series", },
+/*25*/ { 4, "CB-114 series", },
+       { 4, "CB-134I series", },
+       { 8, "CP-138U series", },
+       { 4, "POS-104UL series", }
 };
 
 /* 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 = 3 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C104),
-               .driver_data = 4 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132),
-               .driver_data = 8 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP114),
-               .driver_data = 9 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CT114),
-               .driver_data = 10 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102),
-               .driver_data = 11 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104U),
-               .driver_data = 12 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168U),
-               .driver_data = 13 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP132U),
-               .driver_data = 14 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP134U),
-               .driver_data = 15 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104JU),
-               .driver_data = 16 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_RC7000),
-               .driver_data = 17 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118U),
-               .driver_data = 18 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102UL),
-               .driver_data = 19 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP102U),
-               .driver_data = 20 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP118EL),
-               .driver_data = 21 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP168EL),
-               .driver_data = 22 },
-       { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_CP104EL),
-               .driver_data = 23 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168),   .driver_data = 3 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104),   .driver_data = 4 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132),  .driver_data = 8 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114),  .driver_data = 9 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114),  .driver_data = 10 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102),  .driver_data = 11 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 12 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 13 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 14 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 15 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 16 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 17 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 18 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 19 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 20 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 21 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 22 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 23 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108),       .driver_data = 24 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114),       .driver_data = 25 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I),      .driver_data = 26 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U),      .driver_data = 27 },
+       { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL),    .driver_data = 28 },
        { }
 };
 MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
@@ -853,9 +848,9 @@ static int mxser_startup(struct mxser_port *info)
         * and set the speed of the serial port
         */
        mxser_change_speed(info, NULL);
+       info->flags |= ASYNC_INITIALIZED;
        spin_unlock_irqrestore(&info->slock, flags);
 
-       info->flags |= ASYNC_INITIALIZED;
        return 0;
 }
 
@@ -925,11 +920,9 @@ 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;
 
-       /* initialize driver_data in case something fails */
-       tty->driver_data = NULL;
-
        line = tty->index;
        if (line == MXSER_PORTS)
                return 0;
@@ -944,7 +937,9 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
        /*
         * Start up serial port
         */
+       spin_lock_irqsave(&info->slock, flags);
        info->count++;
+       spin_unlock_irqrestore(&info->slock, flags);
        retval = mxser_startup(info);
        if (retval)
                return retval;
@@ -1561,7 +1556,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                        return -EFAULT;
                return 0;
        case MOXA_ASPP_MON_EXT: {
-               int status, p, shiftbit;
+               int p, shiftbit;
                unsigned long opmode;
                unsigned cflag, iflag;
 
@@ -1708,7 +1703,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 
                info->speed = speed;
                spin_lock_irqsave(&info->slock, flags);
-               mxser_change_speed(info, 0);
+               mxser_change_speed(info, NULL);
                spin_unlock_irqrestore(&info->slock, flags);
 
                return 0;
@@ -1758,43 +1753,23 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
                 * Caller should use TIOCGICOUNT to see which one it was
                 */
-       case TIOCMIWAIT: {
-               DECLARE_WAITQUEUE(wait, current);
-               int ret;
+       case TIOCMIWAIT:
                spin_lock_irqsave(&info->slock, flags);
-               cprev = info->icount;   /* note the counters on entry */
+               cnow = info->icount;    /* note the counters on entry */
                spin_unlock_irqrestore(&info->slock, flags);
 
-               add_wait_queue(&info->delta_msr_wait, &wait);
-               while (1) {
+               wait_event_interruptible(info->delta_msr_wait, ({
+                       cprev = cnow;
                        spin_lock_irqsave(&info->slock, flags);
                        cnow = info->icount;    /* atomic copy */
                        spin_unlock_irqrestore(&info->slock, flags);
 
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       if (((arg & TIOCM_RNG) &&
-                                       (cnow.rng != cprev.rng)) ||
-                                       ((arg & TIOCM_DSR) &&
-                                       (cnow.dsr != cprev.dsr)) ||
-                                       ((arg & TIOCM_CD) &&
-                                       (cnow.dcd != cprev.dcd)) ||
-                                       ((arg & TIOCM_CTS) &&
-                                       (cnow.cts != cprev.cts))) {
-                               ret = 0;
-                               break;
-                       }
-                       /* see if a signal did it */
-                       if (signal_pending(current)) {
-                               ret = -ERESTARTSYS;
-                               break;
-                       }
-                       cprev = cnow;
-               }
-               current->state = TASK_RUNNING;
-               remove_wait_queue(&info->delta_msr_wait, &wait);
+                       ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+                       ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+                       ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+                       ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
+               }));
                break;
-       }
-       /* NOTREACHED */
        /*
         * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
         * Return: write counters to the user passed counter struct
@@ -2011,18 +1986,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
        struct mxser_port *info = tty->driver_data;
        unsigned long flags;
 
-       if ((tty->termios->c_cflag != old_termios->c_cflag) ||
-                       (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
-
-               spin_lock_irqsave(&info->slock, flags);
-               mxser_change_speed(info, old_termios);
-               spin_unlock_irqrestore(&info->slock, flags);
+       spin_lock_irqsave(&info->slock, flags);
+       mxser_change_speed(info, old_termios);
+       spin_unlock_irqrestore(&info->slock, flags);
 
-               if ((old_termios->c_cflag & CRTSCTS) &&
-                               !(tty->termios->c_cflag & CRTSCTS)) {
-                       tty->hw_stopped = 0;
-                       mxser_start(tty);
-               }
+       if ((old_termios->c_cflag & CRTSCTS) &&
+                       !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               mxser_start(tty);
        }
 
        /* Handle sw stopped */
@@ -2230,7 +2201,14 @@ end_intr:
        port->mon_data.rxcnt += cnt;
        port->mon_data.up_rxcnt += cnt;
 
+       /*
+        * We are called from an interrupt context with &port->slock
+        * being held. Drop it temporarily in order to prevent
+        * recursive locking.
+        */
+       spin_unlock(&port->slock);
        tty_flip_buffer_push(tty);
+       spin_lock(&port->slock);
 }
 
 static void mxser_transmit_chars(struct mxser_port *port)