(patch 4 of 13)

Hi,

Here's a patch for the usb-serial ftdi_sio driver against 2.2.20-pre2
that brings it up to the same logic level that is in 2.4.5.

thanks,

greg k-h
diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c     Tue Jun 12 22:34:40 2001
+++ b/drivers/usb/serial/ftdi_sio.c     Tue Jun 12 22:34:40 2001
@@ -14,7 +14,22 @@
  *
  * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info
  *     and extra documentation
+ * 
+ * (23/May/2001)   Bill Ryder
+ *     Added runtime debug patch (thanx Tyson D Sawyer).
+ *     Cleaned up comments for 8U232
+ *     Added parity, framing and overrun error handling
+ *     Added receive break handling.
+ * 
+ * (04/08/2001) gb
+ *     Identify version on module load.
  *       
+ * (18/March/2001) Bill Ryder
+ *     (Not released)
+ *     Added send break handling. (requires kernel patch too)
+ *     Fixed 8U232AM hardware RTS/CTS etc status reporting.
+ *     Added flipbuf fix copied from generic device
+ * 
  * (12/3/2000) Bill Ryder
  *     Added support for 8U232AM device.
  *     Moved PID and VIDs into header file only.
@@ -70,31 +85,35 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/usb.h>
 
 #ifdef CONFIG_USB_SERIAL_DEBUG
-       #define DEBUG
+       static int debug = 1;
 #else
-       #undef DEBUG
+       static int debug;
 #endif
-#include <linux/usb.h>
 
 #include "usb-serial.h"
-
 #include "ftdi_sio.h"
 
 
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.1.0"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>, Bill Ryder 
+<[EMAIL PROTECTED]>"
+#define DRIVER_DESC "USB FTDI RS232 Converters Driver"
+
 
 
 struct ftdi_private {
        ftdi_type_t ftdi_type;
-       char last_status_byte; /* device sends this every 40ms when open */
-       
-       
+       __u16 last_set_data_urb_value ; /* the last data state set - needed for doing 
+a break */
 };
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_startup           (struct usb_serial *serial);
@@ -107,6 +126,10 @@
 static void ftdi_sio_read_bulk_callback        (struct urb *urb);
 static void ftdi_sio_set_termios       (struct usb_serial_port *port, struct termios 
* old);
 static int  ftdi_sio_ioctl             (struct usb_serial_port *port, struct file * 
file, unsigned int cmd, unsigned long arg);
+static void ftdi_sio_break_ctl         (struct usb_serial_port *port, int break_state 
+);
+
+/* Should rename most ftdi_sio's to ftdi_ now since there are two devices 
+   which share common code */ 
 
 /* All of the device info needed for the FTDI SIO serial converter */
 static __u16   ftdi_vendor_id          = FTDI_VID;
@@ -130,6 +153,7 @@
        write_bulk_callback:    ftdi_sio_write_bulk_callback,
        ioctl:                  ftdi_sio_ioctl,
        set_termios:            ftdi_sio_set_termios,
+       break_ctl:              ftdi_sio_break_ctl,
        startup:                ftdi_sio_startup,
         shutdown:               ftdi_sio_shutdown,
 };
@@ -152,6 +176,7 @@
        write_bulk_callback:    ftdi_sio_write_bulk_callback,
        ioctl:                  ftdi_sio_ioctl,
        set_termios:            ftdi_sio_set_termios,
+       break_ctl:              ftdi_sio_break_ctl,
        startup:                ftdi_8U232AM_startup,
         shutdown:               ftdi_sio_shutdown,
 };
@@ -269,7 +294,8 @@
 
                spin_unlock_irqrestore (&port->port_lock, flags);
 
-               /* do not allow a task to be queued to deliver received data */
+               /* This will push the characters through immediately rather 
+                  than queue a task to deliver them */
                port->tty->low_latency = 1;
 
                /* No error checking for this (will get errors later anyway) */
@@ -498,9 +524,9 @@
 static void ftdi_sio_read_bulk_callback (struct urb *urb)
 { /* ftdi_sio_serial_buld_callback */
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-       struct ftdi_private *priv = (struct ftdi_private *)port->private;
        struct usb_serial *serial;
                struct tty_struct *tty = port->tty ;
+       char error_flag;
                unsigned char *data = urb->transfer_buffer;
 
        const int data_offset = 2;
@@ -527,23 +553,76 @@
        if (urb->actual_length > 2) {
                usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, 
data);
        } else {
-                dbg("Just status");
+                dbg("Just status 0o%03o0o%03o",data[0],data[1]);
         }
 
-       priv->last_status_byte = data[0]; /* this has modem control lines */
 
        /* TO DO -- check for hung up line and handle appropriately: */
        /*   send hangup  */
        /* 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 */
 
-
+       /* Handle errors and break */
+       error_flag = TTY_NORMAL;
+        /* Although the device uses a bitmask and hence can have multiple */
+        /* errors on a packet - the order here sets the priority the */
+        /* error is returned to the tty layer  */
+       
+       if ( data[1] & FTDI_RS_OE ) { 
+               error_flag = TTY_OVERRUN;
+                dbg("OVERRRUN error");
+       }
+       if ( data[1] & FTDI_RS_BI ) { 
+               error_flag = TTY_BREAK;
+                dbg("BREAK received");
+       }
+       if ( data[1] & FTDI_RS_PE ) { 
+               error_flag = TTY_PARITY;
+                dbg("PARITY error");
+       }
+       if ( data[1] & FTDI_RS_FE ) { 
+               error_flag = TTY_FRAME;
+                dbg("FRAMING error");
+       }
        if (urb->actual_length > data_offset) {
+
                for (i = data_offset ; i < urb->actual_length ; ++i) {
-                       tty_insert_flip_char(tty, data[i], 0);
-               }
+                       /* have to make sure we don't overflow the buffer
+                         with tty_insert_flip_char's */
+                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(tty);
+                       }
+                       /* Note that the error flag is duplicated for 
+                          every character received since we don't know
+                          which character it applied to */
+                       tty_insert_flip_char(tty, data[i], error_flag);
+               }
                tty_flip_buffer_push(tty);
+
+
+       } 
+
+#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
+       /* if a parity error is detected you get status packets forever
+          until a character is sent without a parity error.
+          This doesn't work well since the application receives a never
+          ending stream of bad data - even though new data hasn't been sent.
+          Therefore I (bill) have taken this out.
+          However - this might make sense for framing errors and so on 
+          so I am leaving the code in for now.
+       */
+      else {
+               if (error_flag != TTY_NORMAL){
+                       dbg("error_flag is not normal");
+                               /* In this case it is just status - if that is an 
+error send a bad character */
+                               if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                                       tty_flip_buffer_push(tty);
+                               }
+                               tty_insert_flip_char(tty, 0xff, error_flag);
+                               tty_flip_buffer_push(tty);
+               }
        }
+#endif
 
        /* Continue trying to always read  */
        FILL_BULK_URB(urb, serial->dev, 
@@ -605,6 +684,38 @@
        return(urb_value);
 }
 
+static void ftdi_sio_break_ctl( struct usb_serial_port *port, int break_state )
+{
+       struct usb_serial *serial = port->serial;
+       struct ftdi_private *priv = (struct ftdi_private *)port->private;
+       __u16 urb_value = 0; 
+       char buf[1];
+       
+       /* break_state = -1 to turn on break, and 0 to turn off break */
+       /* see drivers/char/tty_io.c to see it used */
+       /* last_set_data_urb_value NEVER has the break bit set in it */
+
+       if (break_state) {
+               urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;
+       } else {
+               urb_value = priv->last_set_data_urb_value; 
+       }
+
+       
+       if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+                           FTDI_SIO_SET_DATA_REQUEST, 
+                           FTDI_SIO_SET_DATA_REQUEST_TYPE,
+                           urb_value , 0,
+                           buf, 0, WDR_TIMEOUT) < 0) {
+               err(__FUNCTION__ " FAILED to enable/disable break state (state was 
+%d)",break_state);
+       }          
+
+       dbg(__FUNCTION__ " break state is %d - urb is %d",break_state, urb_value);
+       
+}
+
+
+
 /* As I understand this - old_termios contains the original termios settings */
 /*  and tty->termios contains the new setting to be used */
 /* */
@@ -648,6 +759,11 @@
                        err("CSIZE was set but not CS5-CS8");
                }
        }
+
+       /* This is needed by the break command since it uses the same command - but is
+        *  or'ed with this value  */
+       priv->last_set_data_urb_value = urb_value;
+       
        if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                            FTDI_SIO_SET_DATA_REQUEST, 
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
@@ -721,7 +837,7 @@
        struct usb_serial *serial = port->serial;
        struct ftdi_private *priv = (struct ftdi_private *)port->private;
        __u16 urb_value=0; /* Will hold the new flags */
-       char buf[1];
+       char buf[2];
        int  ret, mask;
        
        dbg(__FUNCTION__ " cmd 0x%04x", cmd);
@@ -731,12 +847,7 @@
 
        case TIOCMGET:
                dbg(__FUNCTION__ " TIOCMGET");
-               /* The MODEM_STATUS_REQUEST works for the sio but not the 232 */
                if (priv->ftdi_type == sio){
-                       /* TO DECIDE - use the 40ms status packets or not? */
-                       /*   PRO: No need to send urb */
-                       /*   CON: Could be 40ms out of date */
-
                        /* Request the status from the device */
                        if ((ret = usb_control_msg(serial->dev, 
                                                   usb_rcvctrlpipe(serial->dev, 0),
@@ -749,8 +860,18 @@
                                return(ret);
                        }
                } else {
-                       /* This gets updated every 40ms - so just copy it in */
-                       buf[0] = priv->last_status_byte;
+                       /* the 8U232AM returns a two byte value (the sio is a 1 byte 
+value) - in the same 
+                          format as the data returned from the in point */
+                       if ((ret = usb_control_msg(serial->dev, 
+                                                  usb_rcvctrlpipe(serial->dev, 0),
+                                                  FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+                                                  
+FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+                                                  0, 0, 
+                                                  buf, 2, WDR_TIMEOUT)) < 0 ) {
+                               err(__FUNCTION__ " Could not get modem status of 
+device - err: %d",
+                                   ret);
+                               return(ret);
+                       }
                }
 
                return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
@@ -841,6 +962,8 @@
        dbg(__FUNCTION__);
        usb_serial_register (&ftdi_sio_device);
        usb_serial_register (&ftdi_8U232AM_device);
+       info(DRIVER_VERSION " " DRIVER_AUTHOR);
+       info(DRIVER_DESC);
        return 0;
 }
 
@@ -856,5 +979,9 @@
 module_init(ftdi_sio_init);
 module_exit(ftdi_sio_exit);
 
-MODULE_AUTHOR("Greg Kroah-Hartman <[EMAIL PROTECTED]>, Bill Ryder <[EMAIL PROTECTED]>");
-MODULE_DESCRIPTION("USB FTDI RS232 converters driver");
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff -Nru a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
--- a/drivers/usb/serial/ftdi_sio.h     Tue Jun 12 22:34:40 2001
+++ b/drivers/usb/serial/ftdi_sio.h     Tue Jun 12 22:34:40 2001
@@ -146,7 +146,7 @@
 #define FTDI_SIO_SET_DATA_STOP_BITS_1 (0x0 << 11 )
 #define FTDI_SIO_SET_DATA_STOP_BITS_15 (0x1 << 11 )
 #define FTDI_SIO_SET_DATA_STOP_BITS_2 (0x2 << 11 )
-
+#define FTDI_SIO_SET_BREAK (0x1 << 14)
 /* FTDI_SIO_SET_DATA */
 
 /*
@@ -170,7 +170,10 @@
  *           0 = 1
  *           1 = 1.5
  *           2 = 2
- *   B14..15 Reserved
+ *   B14
+ *           1 = TX ON (break)
+ *           0 = TX OFF (normal state)
+ *   B15 Reserved
  *
  */
 
@@ -434,6 +437,17 @@
  * B6  Transmitter Empty (TEMT)
  * B7  Error in RCVR FIFO
  * 
+ */
+#define FTDI_RS_DR  1
+#define FTDI_RS_OE (1<<1)
+#define FTDI_RS_PE (1<<2)
+#define FTDI_RS_FE (1<<3)
+#define FTDI_RS_BI (1<<4)
+#define FTDI_RS_THRE (1<<5)
+#define FTDI_RS_TEMT (1<<6)
+#define FTDI_RS_FIFO  (1<<7)
+
+/*
  * OUT Endpoint
  * 
  * This device reserves the first bytes of data on this endpoint contain the length

Reply via email to