(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
