Johannes, 

These are patches to the FTDI device against 2.4.5-pre5

Please send these to linux.

The main changes are:

Added proper reporting of Parity, Overrun, and Framing errors.
Added break recieved handling.
Added flip-buffer overflow check
Corrected 8U232AM status (CTS/CD etc) reporting
Updated version to 1.1.0



--
Bill Ryder               SGI New Zealand
Systems Engineer                                 Ph: (+64 4) 494 6326
[EMAIL PROTECTED]          icq: 16285091        Mobile: (+64 21 67 9507)
 
DISCLAIMER: Unless explicitly stated all opinions are mine not SGI's
diff -rua linux/drivers/usb/serial/ftdi_sio.c bryder/drivers/usb/serial/ftdi_sio.c
--- linux/drivers/usb/serial/ftdi_sio.c Thu May 24 18:26:54 2001
+++ bryder/drivers/usb/serial/ftdi_sio.c        Thu May 24 19:12:18 2001
@@ -15,9 +15,21 @@
  * 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.
@@ -96,7 +108,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#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"
 
@@ -105,9 +117,12 @@
        { }                                             /* Terminating entry */
 };
 
-/* THe 8U232AM has the same API as the sio - but it can support MUCH 
-   higher baudrates (921600 at 48MHz/230400 at 12MHz 
-   so .. it's baudrate setting codes are different */
+/* THe 8U232AM has the same API as the sio except for:
+   - it can support MUCH higher baudrates (921600 at 48MHz/230400 
+     at 12MHz so .. it's baudrate setting codes are different 
+   - it has a two byte status code.
+   - it returns characters very 16ms (the FTDI does it every 40ms)
+  */
 
    
 static __devinitdata struct usb_device_id id_table_8U232AM [] = {
@@ -127,9 +142,7 @@
 
 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);
@@ -142,6 +155,7 @@
 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 */ 
@@ -163,6 +177,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,
 };
@@ -184,6 +199,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,
 };
@@ -237,7 +253,7 @@
        
        priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), 
GFP_KERNEL);
        if (!priv){
-               err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private));
+               err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
                return -ENOMEM;
        }
 
@@ -255,7 +271,7 @@
 
        priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), 
GFP_KERNEL);
        if (!priv){
-               err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private));
+               err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
                return -ENOMEM;
        }
 
@@ -301,7 +317,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) */
@@ -432,7 +449,7 @@
                unsigned char *first_byte = port->write_urb->transfer_buffer;
 
                /* Was seeing a race here, got a read callback, then write callback 
before
-                  hitting interruptible_sleep_on  - so wrapping in a wait_queue */
+                  hitting interuptible_sleep_on  - so wrapping in a wait_queue */
 
                add_wait_queue(&port->write_wait, &wait);
                set_current_state (TASK_INTERRUPTIBLE);
@@ -530,9 +547,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;
@@ -559,23 +576,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, 
@@ -637,6 +707,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 */
 /* */
@@ -680,6 +782,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,
@@ -753,7 +860,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);
@@ -763,12 +870,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),
@@ -781,8 +883,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) |
diff -rua linux/drivers/usb/serial/ftdi_sio.h bryder/drivers/usb/serial/ftdi_sio.h
--- linux/drivers/usb/serial/ftdi_sio.h Wed Dec  6 20:15:12 2000
+++ bryder/drivers/usb/serial/ftdi_sio.h        Tue May 22 22:59:34 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