Hello, All:

This patch adds useful TIOCMIWAIT ioctl to the ftdi_sio driver.
It was generated against 2.4.18pre4, intended for 2.4 tree,
and can be added to 2.5 as well.



diff -Naur -X /home/dmitri/dontdiff 
linux-2.4.18pre4-official/drivers/usb/serial/ftdi_sio.c 
linux/drivers/usb/serial/ftdi_sio.c
--- linux-2.4.18pre4-official/drivers/usb/serial/ftdi_sio.c     Thu Jan 17 20:19:37 
2002
+++ linux/drivers/usb/serial/ftdi_sio.c Thu Jan 17 20:18:56 2002
@@ -155,7 +155,12 @@
        ftdi_type_t ftdi_type;
        __u16 last_set_data_urb_value ; /* the last data state set - needed for doing 
a break */
         int write_offset;
+       wait_queue_head_t delta_msr_wait;
+       char prev_status, diff_status;
 };
+#define FTDI_STATUS_B0_MASK    (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | 
+FTDI_RS0_RLSD)
+#define FTDI_STATUS_B1_MASK    (FTDI_RS_BI)
+
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_startup           (struct usb_serial *serial);
 static int  ftdi_8U232AM_startup       (struct usb_serial *serial);
@@ -273,6 +278,7 @@
 
        priv->ftdi_type = sio;
        priv->write_offset = 1;
+       priv->prev_status = priv->diff_status = 0;
        
        return (0);
 }
@@ -291,6 +297,7 @@
 
        priv->ftdi_type = F8U232AM;
        priv->write_offset = 0;
+       init_waitqueue_head(&priv->delta_msr_wait);
        
        return (0);
 }
@@ -548,6 +555,7 @@
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct usb_serial *serial;
                struct tty_struct *tty = port->tty ;
+       struct ftdi_private *priv = (struct ftdi_private *) port->private;
        char error_flag;
                unsigned char *data = urb->transfer_buffer;
 
@@ -584,6 +592,16 @@
        /* See acm.c - you do a tty_hangup  - eg tty_hangup(tty) */
        /* if CD is dropped and the line is not CLOCAL then we should hangup */
 
+       /* Compare new line status to the old one, signal if different */
+       if (priv != NULL) {
+               char new_status = data[0] & FTDI_STATUS_B0_MASK;
+               if (new_status != priv->prev_status) {
+                       priv->diff_status |= new_status ^ priv->prev_status;
+                       wake_up_interruptible(&priv->delta_msr_wait);
+                       priv->prev_status = new_status;
+               }
+       }
+
        /* Handle errors and break */
        error_flag = TTY_NORMAL;
         /* Although the device uses a bitmask and hence can have multiple */
@@ -970,6 +988,45 @@
                 *
                 */
 
+       /*
+        * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+        * - mask passed in arg for lines of interest
+        *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+        * Caller should use TIOCGICOUNT to see which one it was.
+        *
+        * This code is borrowed from linux/drivers/char/serial.c
+        */
+       case TIOCMIWAIT:
+               while (priv != NULL) {
+                       interruptible_sleep_on(&priv->delta_msr_wait);
+                       /* see if a signal did it */
+                       if (signal_pending(current))
+                               return -ERESTARTSYS;
+                       else {
+                               char diff = priv->diff_status;
+
+                               if (diff == 0) {
+                                       return -EIO; /* no change => error */
+                               }
+
+                               /* Consume all events */
+                               priv->diff_status = 0;
+
+                               /* Return 0 if caller wanted to know about these bits 
+*/
+                               if ( ((arg & TIOCM_RNG) && (diff & FTDI_RS0_RI)) ||
+                                    ((arg & TIOCM_DSR) && (diff & FTDI_RS0_DSR)) ||
+                                    ((arg & TIOCM_CD)  && (diff & FTDI_RS0_RLSD)) ||
+                                    ((arg & TIOCM_CTS) && (diff & FTDI_RS0_CTS)) ) {
+                                       return 0;
+                               }
+                               /*
+                                * Otherwise caller can't care less about what 
+happened,
+                                * and so we continue to wait for more events.
+                                */
+                       }
+               }
+               /* NOTREACHED */
+
        default:
          /* This is not an error - turns out the higher layers will do 
           *  some ioctls itself (see comment above)
diff -Naur -X /home/dmitri/dontdiff 
linux-2.4.18pre4-official/drivers/usb/serial/ftdi_sio.h 
linux/drivers/usb/serial/ftdi_sio.h
--- linux-2.4.18pre4-official/drivers/usb/serial/ftdi_sio.h     Thu Jan 17 20:19:37 
2002
+++ linux/drivers/usb/serial/ftdi_sio.h Thu Jan 17 20:18:56 2002
@@ -438,6 +438,11 @@
  * B7  Error in RCVR FIFO
  * 
  */
+#define FTDI_RS0_CTS   (1 << 4)
+#define FTDI_RS0_DSR   (1 << 5)
+#define FTDI_RS0_RI    (1 << 6)
+#define FTDI_RS0_RLSD  (1 << 7)
+
 #define FTDI_RS_DR  1
 #define FTDI_RS_OE (1<<1)
 #define FTDI_RS_PE (1<<2)

Attachment: msg04058/pgp00000.pgp
Description: PGP signature

Reply via email to