[PATCH 1/1] mct_u232: IOCTL implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Vadim Tsozik <tsozik@xxxxxxxxx>

Added mct_u232_ioctl function and implemented TIOCMIWAIT and TIOCGICOUNT commands. MCT u232 p9 is one of a few usb to serail adapters which converts USB +/-5v voltage levels to COM +/-15 voltages. So it can also power COM interfaced devices. This makes it very usable for legacy COM interfaced data-acquisition hardware. I tested new implementation with AWARE Electronics RM-60 radiation meter, which sends pulse via RNG COM line whenever new particle is registered.

Patch below is based on linux-2.6.35.10-72.fc14.x86_64.

Signed-off-by: Vadim Tsozik <tsozik@xxxxxxxxx>

---
--- original/mct_u232.c 2010-12-25 21:31:13.744174626 -0500
+++ mct_u232.c  2010-12-25 21:44:57.714640343 -0500
@@ -24,6 +24,12 @@
  *   Basic tests have been performed with minicom/zmodem transfers and
  *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
  *
+ * 24-Apr-2010 Vadim Tsozik <tsozik@xxxxxxxxx>
+ *   - Added implementation of 'TIOCMIWAIT' and 'TIOCGICOUNT' ioctls.
+ *     This routines are necessary if you use mct u232 p9 as data
+ *     acquisition interface. These routines were tested with RM-60 AWARE
+ *     Electronics Radiation Monitor.
+ *
  * 04-Nov-2003 Bill Marr <marr at flex dot com>
  *   - Mimic Windows driver by sending 2 USB 'device request' messages
  *     following normal 'baud rate change' message.  This allows data to be
@@ -78,6 +84,8 @@
 #include <asm/unaligned.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
+#include <linux/serial.h>
+#include <linux/ioctl.h>
 #include "mct_u232.h"

 /*
@@ -104,6 +112,8 @@ static void mct_u232_break_ctl(struct tt
 static int  mct_u232_tiocmget(struct tty_struct *tty, struct file *file);
 static int  mct_u232_tiocmset(struct tty_struct *tty, struct file *file,
                        unsigned int set, unsigned int clear);
+static int  mct_u232_ioctl(struct tty_struct *tty, struct file *file,
+                        unsigned int cmd, unsigned long arg);
 static void mct_u232_throttle(struct tty_struct *tty);
 static void mct_u232_unthrottle(struct tty_struct *tty);

@@ -150,6 +160,7 @@ static struct usb_serial_driver mct_u232
        .tiocmset =          mct_u232_tiocmset,
        .attach =            mct_u232_startup,
        .release =           mct_u232_release,
+       .ioctl =             mct_u232_ioctl,
 };


@@ -160,6 +171,8 @@ struct mct_u232_private {
        unsigned char        last_lsr;      /* Line Status Register */
        unsigned char        last_msr;      /* Modem Status Register */
        unsigned int         rx_flags;      /* Throttling flags */
+        struct async_icount  icount;
+       wait_queue_head_t    msr_wait;      /* for handling sleeping while waiting for msr change to happen */
 };

 #define THROTTLED              0x01
@@ -386,27 +399,41 @@ static int mct_u232_get_modem_stat(struc
        return rc;
 } /* mct_u232_get_modem_stat */

-static void mct_u232_msr_to_state(unsigned int *control_state,
-                                               unsigned char msr)
+static void mct_u232_msr_to_state(struct mct_u232_private *priv)
 {
-       /* Translate Control Line states */
-       if (msr & MCT_U232_MSR_DSR)
-               *control_state |=  TIOCM_DSR;
-       else
-               *control_state &= ~TIOCM_DSR;
-       if (msr & MCT_U232_MSR_CTS)
-               *control_state |=  TIOCM_CTS;
-       else
-               *control_state &= ~TIOCM_CTS;
-       if (msr & MCT_U232_MSR_RI)
-               *control_state |=  TIOCM_RI;
-       else
-               *control_state &= ~TIOCM_RI;
-       if (msr & MCT_U232_MSR_CD)
-               *control_state |=  TIOCM_CD;
-       else
-               *control_state &= ~TIOCM_CD;
-       dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
+        unsigned char msr = priv->last_msr;
+        unsigned int *control_state = &priv->control_state;
+        struct async_icount *icount = &priv->icount;
+
+        /* Translate Control Line states */
+        if (msr & MCT_U232_MSR_DSR) {
+         *control_state |=  TIOCM_DSR;
+         icount->dsr++;
+        } else {
+         *control_state &= ~TIOCM_DSR;
+        }
+        if (msr & MCT_U232_MSR_CTS) {
+         *control_state |=  TIOCM_CTS;
+         icount->cts++;
+        } else {
+         *control_state &= ~TIOCM_CTS;
+        }
+        if (msr & MCT_U232_MSR_RI) {
+         *control_state |=  TIOCM_RI;
+         icount->rng++;
+        } else {
+         *control_state &= ~TIOCM_RI;
+        }
+        if (msr & MCT_U232_MSR_CD) {
+         *control_state |=  TIOCM_CD;
+         icount->dcd++;
+        } else {
+         *control_state &= ~TIOCM_CD;
+        }
+
+        dbg("msr_to_state: msr=0x%x ==> state=0x%x", msr, *control_state);
+
+        wake_up_interruptible(&priv->msr_wait);
 } /* mct_u232_msr_to_state */

 /*
@@ -422,6 +449,7 @@ static int mct_u232_startup(struct usb_s
        if (!priv)
                return -ENOMEM;
        spin_lock_init(&priv->lock);
+       init_waitqueue_head(&priv->msr_wait);
        usb_set_serial_port_data(serial->port[0], priv);

        init_waitqueue_head(&serial->port[0]->write_wait);
@@ -498,7 +526,7 @@ static int  mct_u232_open(struct tty_str
        mct_u232_get_modem_stat(serial, &last_msr);
        spin_lock_irqsave(&priv->lock, flags);
        priv->last_msr = last_msr;
-       mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+       mct_u232_msr_to_state(priv);
        spin_unlock_irqrestore(&priv->lock, flags);

        port->read_urb->dev = port->serial->dev;
@@ -616,7 +644,7 @@ static void mct_u232_read_int_callback(s
        priv->last_msr = data[MCT_U232_MSR_INDEX];

        /* Record Control Line states */
-       mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+       mct_u232_msr_to_state(priv);

 #if 0
        /* Not yet handled. See belkin_sa.c for further information */
@@ -823,7 +851,6 @@ static void mct_u232_throttle(struct tty
        }
 }

-
 static void mct_u232_unthrottle(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
@@ -844,6 +871,57 @@ static void mct_u232_unthrottle(struct t
        }
 }

+static int  mct_u232_ioctl(struct tty_struct *tty, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       DEFINE_WAIT(wait);
+       struct usb_serial_port *port = tty->driver_data;
+       struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port);
+       struct async_icount cnow, cprev;
+
+       dbg("%s - port %d, cmd = 0x%x", __func__, port->number, cmd);
+
+       switch (cmd) {
+
+       case TIOCMIWAIT:
+
+               dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
+
+               cprev = mct_u232_port->icount;
+               for ( ; ; ) {
+                       prepare_to_wait(&mct_u232_port->msr_wait,
+                                               &wait, TASK_INTERRUPTIBLE);
+                       schedule();
+                       finish_wait(&mct_u232_port->msr_wait, &wait);
+                       /* see if a signal did it */
+                       if (signal_pending(current))
+                               return -ERESTARTSYS;
+                       cnow = mct_u232_port->icount;
+                       if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+                           cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+                               return -EIO; /* no change => error */
+                       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))) {
+                               return 0;
+                       }
+                       cprev = cnow;
+               }
+               /* NOTREACHED */
+               break;
+
+       case TIOCGICOUNT:
+                dbg("%s - (%d) TIOCGICOUNT RX=%d, TX=%d", __func__,
+                    port->number, mct_u232_port->icount.rx, mct_u232_port->icount.tx);
+                if (copy_to_user((void __user *)arg, &mct_u232_port->icount,
+                    sizeof(mct_u232_port->icount)))
+                        return -EFAULT;
+                return 0;
+       }
+       return -ENOIOCTLCMD;
+}
+
 static int __init mct_u232_init(void)
 {
        int retval;



      
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux