vserver 1.9.3
[linux-2.6.git] / drivers / char / mxser.c
index 65ff46a..147c1ba 100644 (file)
@@ -35,6 +35,8 @@
  *    Added support for: C102, CI-132, CI-134, CP-132, CP-114, CT-114 cards
  *                        by Damian Wrobel <dwrobel@ertel.com.pl>
  *
+ *    Added support for serial card CP104
+ *                       by James Nelson Provident Solutions <linux-info@provident-solutions.com>
  */
 
 #include <linux/config.h>
 
 #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
 
-#ifndef MIN
-#define MIN(a,b)       ((a) < (b) ? (a) : (b))
-#endif
-
 /*
  *    Define the Moxa PCI vendor and device IDs.
  */
 #ifndef PCI_DEVICE_ID_C104
 #define PCI_DEVICE_ID_C104     0x1040
 #endif
+#ifndef PCI_DEVICE_ID_CP104
+#define PCI_DEVICE_ID_CP104    0x1041
+#endif
 #ifndef PCI_DEVICE_ID_CP132
 #define PCI_DEVICE_ID_CP132    0x1320
 #endif
@@ -139,6 +140,7 @@ enum {
        MXSER_BOARD_CI104J,
        MXSER_BOARD_C168_PCI,
        MXSER_BOARD_C104_PCI,
+       MXSER_BOARD_CP104_PCI,
        MXSER_BOARD_C102_ISA,
        MXSER_BOARD_CI132,
        MXSER_BOARD_CI134,
@@ -154,6 +156,7 @@ static char *mxser_brdname[] =
        "CI-104J series",
        "C168H/PCI series",
        "C104H/PCI series",
+       "CP104/PCI series",
        "C102 series",
        "CI-132 series",
        "CI-134 series",
@@ -169,6 +172,7 @@ static int mxser_numports[] =
        4,
        8,
        4,
+       4,
        2,
        2,
        4,
@@ -190,11 +194,14 @@ static int mxser_numports[] =
 #define         MOXA_GET_CUMAJOR      (MOXA + 64)
 #define         MOXA_GETMSTATUS       (MOXA + 65)
 
+#ifdef CONFIG_PCI
 static struct pci_device_id mxser_pcibrds[] = {
        { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C168, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
          MXSER_BOARD_C168_PCI },
        { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
          MXSER_BOARD_C104_PCI },
+       { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
+         MXSER_BOARD_CP104_PCI },
        { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
          MXSER_BOARD_CP132_PCI },
        { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
@@ -204,6 +211,7 @@ static struct pci_device_id mxser_pcibrds[] = {
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
+#endif /* CONFIG_PCI */
 
 static int ioaddr[MXSER_BOARDS];
 static int ttymajor = MXSERMAJOR;
@@ -320,7 +328,6 @@ struct mxser_hwconf mxsercfg[MXSER_BOARDS];
 
 static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
 static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
-static int mxser_get_PCI_conf(struct pci_dev *, int, struct mxser_hwconf *);
 static void mxser_do_softint(void *);
 static int mxser_open(struct tty_struct *, struct file *);
 static void mxser_close(struct tty_struct *, struct file *);
@@ -338,17 +345,17 @@ static void mxser_set_termios(struct tty_struct *, struct termios *);
 static void mxser_stop(struct tty_struct *);
 static void mxser_start(struct tty_struct *);
 static void mxser_hangup(struct tty_struct *);
-static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);
 static inline void mxser_receive_chars(struct mxser_struct *, int *);
 static inline void mxser_transmit_chars(struct mxser_struct *);
 static inline void mxser_check_modem_status(struct mxser_struct *, int);
+static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);
 static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
 static int mxser_startup(struct mxser_struct *);
 static void mxser_shutdown(struct mxser_struct *);
 static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);
-static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *);
-static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *);
-static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *);
+static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *);
+static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *);
+static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *);
 static void mxser_send_break(struct mxser_struct *, int);
 static int mxser_tiocmget(struct tty_struct *, struct file *);
 static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);
@@ -451,6 +458,7 @@ static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
        mxsercfg[board] = *hwconf;
 }
 
+#ifdef CONFIG_PCI
 static int mxser_get_PCI_conf(struct pci_dev *pdev, int board_type, struct mxser_hwconf *hwconf)
 {
        int i;
@@ -475,6 +483,7 @@ static int mxser_get_PCI_conf(struct pci_dev *pdev, int board_type, struct mxser
        }
        return (0);
 }
+#endif /* CONFIG_PCI */
 
 static struct tty_operations mxser_ops = {
        .open = mxser_open,
@@ -604,7 +613,6 @@ static int __init mxser_module_init(void)
        {
                struct pci_dev *pdev = NULL;
                int n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1;
-               int index = 0;
                for (b = 0; b < n; b++) {
                        while ((pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev)))
                        {
@@ -666,9 +674,7 @@ static void mxser_do_softint(void *private_)
        tty = info->tty;
        if (tty) {
                if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) {
-                       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                           tty->ldisc.write_wakeup)
-                               (tty->ldisc.write_wakeup) (tty);
+                       tty_wakeup(tty);
                        wake_up_interruptible(&tty->write_wait);
                }
                if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) {
@@ -805,11 +811,11 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
        mxser_shutdown(info);
        if (tty->driver->flush_buffer)
                tty->driver->flush_buffer(tty);
-       if (tty->ldisc.flush_buffer)
-               tty->ldisc.flush_buffer(tty);
+       tty_ldisc_flush(tty);
+
        tty->closing = 0;
        info->event = 0;
-       info->tty = 0;
+       info->tty = NULL;
        if (info->blocked_open) {
                if (info->close_delay) {
                        set_current_state(TASK_INTERRUPTIBLE);
@@ -837,7 +843,7 @@ static int mxser_write(struct tty_struct *tty, int from_user,
        if (from_user) {
                down(&mxvar_tmp_buf_sem);
                while (1) {
-                       c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                       c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                           SERIAL_XMIT_SIZE - info->xmit_head));
                        if (c <= 0)
                                break;
@@ -850,7 +856,7 @@ static int mxser_write(struct tty_struct *tty, int from_user,
                        }
 
                        cli();
-                       c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                       c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                       SERIAL_XMIT_SIZE - info->xmit_head));
                        memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c);
                        info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
@@ -865,7 +871,7 @@ static int mxser_write(struct tty_struct *tty, int from_user,
        } else {
                while (1) {
                        cli();
-                       c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                       c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                           SERIAL_XMIT_SIZE - info->xmit_head));
                        if (c <= 0) {
                                restore_flags(flags);
@@ -964,9 +970,7 @@ static void mxser_flush_buffer(struct tty_struct *tty)
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
        restore_flags(flags);
        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);
 }
 
 static int mxser_ioctl(struct tty_struct *tty, struct file *file,
@@ -976,8 +980,9 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
        struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
        int retval;
        struct async_icount cprev, cnow;        /* kernel counter temps */
-       struct serial_icounter_struct *p_cuser;         /* user space */
+       struct serial_icounter_struct __user *p_cuser;
        unsigned long templ;
+       void __user *argp = (void __user *)arg;
 
        if (PORTNO(tty) == MXSER_PORTS)
                return (mxser_ioctl_special(cmd, arg));
@@ -1003,20 +1008,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
                return (0);
        case TIOCGSOFTCAR:
-               return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+               return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
        case TIOCSSOFTCAR:
-               if(get_user(templ, (unsigned long *) arg))
+               if(get_user(templ, (unsigned long __user *) arg))
                        return -EFAULT;
                arg = templ;
                tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
                                         (arg ? CLOCAL : 0));
                return (0);
        case TIOCGSERIAL:
-               return (mxser_get_serial_info(info, (struct serial_struct *) arg));
+               return mxser_get_serial_info(info, argp);
        case TIOCSSERIAL:
-               return (mxser_set_serial_info(info, (struct serial_struct *) arg));
+               return mxser_set_serial_info(info, argp);
        case TIOCSERGETLSR:     /* Get line status register */
-               return (mxser_get_lsr_info(info, (unsigned int *) arg));
+               return mxser_get_lsr_info(info, argp);
                /*
                 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
                 * - mask passed in arg for lines of interest
@@ -1060,7 +1065,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                cli();
                cnow = info->icount;
                restore_flags(flags);
-               p_cuser = (struct serial_icounter_struct *) arg;
+               p_cuser = argp;
                if(put_user(cnow.cts, &p_cuser->cts))
                        return -EFAULT;
                if(put_user(cnow.dsr, &p_cuser->dsr))
@@ -1069,7 +1074,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
                        return -EFAULT;
                return put_user(cnow.dcd, &p_cuser->dcd);
        case MOXA_HighSpeedOn:
-               return put_user(info->baud_base != 115200 ? 1 : 0, (int *) arg);
+               return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
        default:
                return (-ENOIOCTLCMD);
        }
@@ -1079,21 +1084,22 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file,
 static int mxser_ioctl_special(unsigned int cmd, unsigned long arg)
 {
        int i, result, status;
+       void __user *argp = (void __user *)arg;
 
        switch (cmd) {
        case MOXA_GET_CONF:
-               if(copy_to_user((struct mxser_hwconf *) arg, mxsercfg,
+               if(copy_to_user(argp, mxsercfg,
                             sizeof(struct mxser_hwconf) * 4))
                                return -EFAULT;
                return 0;
        case MOXA_GET_MAJOR:
-               if(copy_to_user((int *) arg, &ttymajor, sizeof(int)))
+               if(copy_to_user(argp, &ttymajor, sizeof(int)))
                        return -EFAULT;
                return 0;
 
        case MOXA_GET_CUMAJOR:
                result = 0;
-               if(copy_to_user((int *) arg, &result, sizeof(int)))
+               if(copy_to_user(argp, &result, sizeof(int)))
                        return -EFAULT;
                return 0;
 
@@ -1103,9 +1109,9 @@ static int mxser_ioctl_special(unsigned int cmd, unsigned long arg)
                        if (mxvar_table[i].base)
                                result |= (1 << i);
                }
-               return put_user(result, (unsigned long *) arg);
+               return put_user(result, (unsigned long __user *) argp);
        case MOXA_GETDATACOUNT:
-               if(copy_to_user((struct mxser_log *) arg, &mxvar_log, sizeof(mxvar_log)))
+               if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
                        return -EFAULT;
                return (0);
        case MOXA_GETMSTATUS:
@@ -1139,7 +1145,7 @@ static int mxser_ioctl_special(unsigned int cmd, unsigned long arg)
                        else
                                GMStatus[i].cts = 0;
                }
-               if(copy_to_user((struct mxser_mstatus *) arg, GMStatus,
+               if(copy_to_user(argp, GMStatus,
                             sizeof(struct mxser_mstatus) * MXSER_PORTS))
                        return -EFAULT;
                return 0;
@@ -1289,73 +1295,10 @@ void mxser_hangup(struct tty_struct *tty)
        info->event = 0;
        info->count = 0;
        info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->tty = 0;
+       info->tty = NULL;
        wake_up_interruptible(&info->open_wait);
 }
 
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-       int status, i;
-       struct mxser_struct *info;
-       struct mxser_struct *port;
-       int max, irqbits, bits, msr;
-       int pass_counter = 0;
-       int handled = 0;
-
-       port = 0;
-       for (i = 0; i < MXSER_BOARDS; i++) {
-               if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
-                       port = dev_id;
-                       break;
-               }
-       }
-
-       if (i == MXSER_BOARDS)
-               return IRQ_NONE;
-       if (port == 0)
-               return IRQ_NONE;
-       max = mxser_numports[mxsercfg[i].board_type];
-
-       while (1) {
-               irqbits = inb(port->vector) & port->vectormask;
-               if (irqbits == port->vectormask)
-                       break;
-               handled = 1;
-               for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
-                       if (irqbits == port->vectormask)
-                               break;
-                       if (bits & irqbits)
-                               continue;
-                       info = port + i;
-                       if (!info->tty ||
-                         (inb(info->base + UART_IIR) & UART_IIR_NO_INT))
-                               continue;
-                       status = inb(info->base + UART_LSR) & info->read_status_mask;
-                       if (status & UART_LSR_DR)
-                               mxser_receive_chars(info, &status);
-                       msr = inb(info->base + UART_MSR);
-                       if (msr & UART_MSR_ANY_DELTA)
-                               mxser_check_modem_status(info, msr);
-                       if (status & UART_LSR_THRE) {
-/* 8-2-99 by William
-   if ( info->x_char || (info->xmit_cnt > 0) )
- */
-                               mxser_transmit_chars(info);
-                       }
-               }
-               if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {
-#if 0
-                       printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n");
-#endif
-                       break;  /* Prevent infinite loops */
-               }
-       }
-       return IRQ_RETVAL(handled);
-}
-
 static inline void mxser_receive_chars(struct mxser_struct *info,
                                         int *status)
 {
@@ -1476,6 +1419,69 @@ static inline void mxser_check_modem_status(struct mxser_struct *info,
        }
 }
 
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int status, i;
+       struct mxser_struct *info;
+       struct mxser_struct *port;
+       int max, irqbits, bits, msr;
+       int pass_counter = 0;
+       int handled = 0;
+
+       port = NULL;
+       for (i = 0; i < MXSER_BOARDS; i++) {
+               if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
+                       port = dev_id;
+                       break;
+               }
+       }
+
+       if (i == MXSER_BOARDS)
+               return IRQ_NONE;
+       if (port == 0)
+               return IRQ_NONE;
+       max = mxser_numports[mxsercfg[i].board_type];
+
+       while (1) {
+               irqbits = inb(port->vector) & port->vectormask;
+               if (irqbits == port->vectormask)
+                       break;
+               handled = 1;
+               for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+                       if (irqbits == port->vectormask)
+                               break;
+                       if (bits & irqbits)
+                               continue;
+                       info = port + i;
+                       if (!info->tty ||
+                         (inb(info->base + UART_IIR) & UART_IIR_NO_INT))
+                               continue;
+                       status = inb(info->base + UART_LSR) & info->read_status_mask;
+                       if (status & UART_LSR_DR)
+                               mxser_receive_chars(info, &status);
+                       msr = inb(info->base + UART_MSR);
+                       if (msr & UART_MSR_ANY_DELTA)
+                               mxser_check_modem_status(info, msr);
+                       if (status & UART_LSR_THRE) {
+/* 8-2-99 by William
+   if ( info->x_char || (info->xmit_cnt > 0) )
+ */
+                               mxser_transmit_chars(info);
+                       }
+               }
+               if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {
+#if 0
+                       printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n");
+#endif
+                       break;  /* Prevent infinite loops */
+               }
+       }
+       return IRQ_RETVAL(handled);
+}
+
 static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
                                 struct mxser_struct *info)
 {
@@ -1653,7 +1659,7 @@ static int mxser_startup(struct mxser_struct *info)
        /*
         * and set the speed of the serial port
         */
-       mxser_change_speed(info, 0);
+       mxser_change_speed(info, NULL);
 
        info->flags |= ASYNC_INITIALIZED;
        restore_flags(flags);
@@ -1685,7 +1691,7 @@ static void mxser_shutdown(struct mxser_struct *info)
         */
        if (info->xmit_buf) {
                free_page((unsigned long) info->xmit_buf);
-               info->xmit_buf = 0;
+               info->xmit_buf = NULL;
        }
        info->IER = 0;
        outb(0x00, info->base + UART_IER);      /* disable all intrs */
@@ -2036,7 +2042,7 @@ static int mxser_change_speed(struct mxser_struct *info,
  * ------------------------------------------------------------
  */
 static int mxser_get_serial_info(struct mxser_struct *info,
-                                struct serial_struct *retinfo)
+                                struct serial_struct __user *retinfo)
 {
        struct serial_struct tmp;
 
@@ -2057,7 +2063,7 @@ static int mxser_get_serial_info(struct mxser_struct *info,
 }
 
 static int mxser_set_serial_info(struct mxser_struct *info,
-                                struct serial_struct *new_info)
+                                struct serial_struct __user *new_info)
 {
        struct serial_struct new_serial;
        unsigned int flags;
@@ -2098,7 +2104,7 @@ static int mxser_set_serial_info(struct mxser_struct *info,
 
        if (info->flags & ASYNC_INITIALIZED) {
                if (flags != (info->flags & ASYNC_SPD_MASK)) {
-                       mxser_change_speed(info, 0);
+                       mxser_change_speed(info, NULL);
                }
        } else
                retval = mxser_startup(info);
@@ -2115,7 +2121,7 @@ static int mxser_set_serial_info(struct mxser_struct *info,
  *          transmit holding register is empty.  This functionality
  *          allows an RS485 driver to be written in user space.
  */
-static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int *value)
+static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int __user *value)
 {
        unsigned char status;
        unsigned int result;