This patch updates the ftdi_sio driver.

diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
--- a/drivers/usb/serial/ftdi_sio.c     Thu Jan  3 21:41:54 2002
+++ b/drivers/usb/serial/ftdi_sio.c     Thu Jan  3 21:41:54 2002
@@ -1,7 +1,7 @@
 /*
  * USB FTDI SIO driver
  *
- *     Copyright (C) 1999, 2000
+ *     Copyright (C) 1999 - 2001
  *         Greg Kroah-Hartman ([EMAIL PROTECTED])
  *          Bill Ryder ([EMAIL PROTECTED])
  *
@@ -12,9 +12,21 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
- * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info
+ * See http://ftdi-usb-sio.sourceforge.net for upto date testing info
  *     and extra documentation
  * 
+ * (04/Nov/2001) Bill Ryder
+ *     Fixed bug in read_bulk_callback where incorrect urb buffer was used.
+ *     cleaned up write offset calculation
+ *     added write_room since default values can be incorrect for sio
+ *     changed write_bulk_callback to use same queue_task as other drivers
+ *       (the previous version caused panics)
+ *     Removed port iteration code since the device only has one I/O port and it 
+ *       was wrong anyway.
+ * 
+ * (31/May/2001) gkh
+ *     switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * (23/May/2001)   Bill Ryder
  *     Added runtime debug patch (thanx Tyson D Sawyer).
  *     Cleaned up comments for 8U232
@@ -91,7 +103,6 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
-
 #ifdef CONFIG_USB_SERIAL_DEBUG
        static int debug = 1;
 #else
@@ -105,7 +116,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1.0"
+#define DRIVER_VERSION "v1.2.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <[EMAIL PROTECTED]>, Bill Ryder 
<[EMAIL PROTECTED]>"
 #define DRIVER_DESC "USB FTDI RS232 Converters Driver"
 
@@ -114,6 +125,7 @@
 struct ftdi_private {
        ftdi_type_t ftdi_type;
        __u16 last_set_data_urb_value ; /* the last data state set - needed for doing 
a break */
+        int write_offset;
 };
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_startup           (struct usb_serial *serial);
@@ -122,6 +134,7 @@
 static int  ftdi_sio_open              (struct usb_serial_port *port, struct file 
*filp);
 static void ftdi_sio_close             (struct usb_serial_port *port, struct file 
*filp);
 static int  ftdi_sio_write             (struct usb_serial_port *port, int from_user, 
const unsigned char *buf, int count);
+static int  ftdi_sio_write_room                (struct usb_serial_port *port);
 static void ftdi_sio_write_bulk_callback (struct urb *urb);
 static void ftdi_sio_read_bulk_callback        (struct urb *urb);
 static void ftdi_sio_set_termios       (struct usb_serial_port *port, struct termios 
* old);
@@ -149,6 +162,7 @@
        open:                   ftdi_sio_open,
        close:                  ftdi_sio_close,
        write:                  ftdi_sio_write,
+       write_room:             ftdi_sio_write_room,
        read_bulk_callback:     ftdi_sio_read_bulk_callback,
        write_bulk_callback:    ftdi_sio_write_bulk_callback,
        ioctl:                  ftdi_sio_ioctl,
@@ -158,7 +172,7 @@
         shutdown:               ftdi_sio_shutdown,
 };
 
-struct usb_serial_device_type ftdi_8U232AM_device = {
+static struct usb_serial_device_type ftdi_8U232AM_device = {
        name:                   "FTDI 8U232AM",
        idVendor:               &ftdi_vendor_id,        /* the FTDI vendor ID */
        idProduct:              &ftdi_8U232AM_product_id,
@@ -172,6 +186,7 @@
        open:                   ftdi_sio_open,
        close:                  ftdi_sio_close,
        write:                  ftdi_sio_write,
+       write_room:             ftdi_sio_write_room,
        read_bulk_callback:     ftdi_sio_read_bulk_callback,
        write_bulk_callback:    ftdi_sio_write_bulk_callback,
        ioctl:                  ftdi_sio_ioctl,
@@ -226,15 +241,15 @@
 {
        struct ftdi_private *priv;
        
-       init_waitqueue_head(&serial->port[0].write_wait);
        
        priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), 
GFP_KERNEL);
        if (!priv){
-               err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
+               err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private));
                return -ENOMEM;
        }
 
        priv->ftdi_type = sio;
+       priv->write_offset = 1;
        
        return (0);
 }
@@ -244,15 +259,15 @@
 {
        struct ftdi_private *priv;
  
-       init_waitqueue_head(&serial->port[0].write_wait);
 
        priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), 
GFP_KERNEL);
        if (!priv){
-               err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
+               err(__FUNCTION__"- kmalloc(%Zd) failed.", sizeof(struct ftdi_private));
                return -ENOMEM;
        }
 
        priv->ftdi_type = F8U232AM;
+       priv->write_offset = 0;
        
        return (0);
 }
@@ -262,13 +277,14 @@
        
        dbg (__FUNCTION__);
 
-       /* Close ports if they are open */
+
+       /* stop reads and writes on all ports */
        while (serial->port[0].open_count > 0) {
                ftdi_sio_close (&serial->port[0], NULL);
        }
-       if (serial->port->private){
-               kfree(serial->port->private);
-               serial->port->private = NULL;
+       if (serial->port[0].private){
+               kfree(serial->port[0].private);
+               serial->port[0].private = NULL;
        }
 }
 
@@ -278,13 +294,12 @@
 { /* ftdi_sio_open */
        struct termios tmp_termios;
        struct usb_serial *serial = port->serial;
-       unsigned long flags;    /* Used for spinlock */
-       int result;
+       int result = 0;
        char buf[1]; /* Needed for the usb_control_msg I think */
 
        dbg(__FUNCTION__);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        
        MOD_INC_USE_COUNT;
        ++port->open_count;
@@ -292,8 +307,6 @@
        if (!port->active){
                port->active = 1;
 
-               spin_unlock_irqrestore (&port->port_lock, flags);
-
                /* This will push the characters through immediately rather 
                   than queue a task to deliver them */
                port->tty->low_latency = 1;
@@ -329,63 +342,61 @@
                result = usb_submit_urb(port->read_urb);
                if (result)
                        err(__FUNCTION__ " - failed submitting read urb, error %d", 
result);
-       } else { /* the port was already active - so no initialisation is done */
-               spin_unlock_irqrestore (&port->port_lock, flags);
        }
 
-       return (0);
+       up (&port->sem);
+       return result;
 } /* ftdi_sio_open */
 
 
 static void ftdi_sio_close (struct usb_serial_port *port, struct file *filp)
 { /* ftdi_sio_close */
-       struct usb_serial *serial = port->serial;
+       struct usb_serial *serial = port->serial; /* Checked in usbserial.c */
        unsigned int c_cflag = port->tty->termios->c_cflag;
        char buf[1];
-       unsigned long flags;
 
        dbg( __FUNCTION__);
 
-       spin_lock_irqsave (&port->port_lock, flags);
+       down (&port->sem);
        --port->open_count;
 
        if (port->open_count <= 0) {
-               spin_unlock_irqrestore (&port->port_lock, flags);
-               if (c_cflag & HUPCL){
-                       /* Disable flow control */
-                       if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 
0),
-                                           FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
-                                           FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                                           0, 0, 
-                                           buf, 0, WDR_TIMEOUT) < 0) {
-                               err("error from flowcontrol urb");
-                       }           
-
-                       /* drop DTR */
-                       if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) 
< 0){
-                               err("Error from DTR LOW urb");
-                       }
-                       /* drop RTS */
-                       if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) 
< 0) {
-                               err("Error from RTS LOW urb");
-                       }       
-               } /* Note change no line is hupcl is off */
-
-               /* shutdown our bulk reads and writes */
-               usb_unlink_urb (port->write_urb);
-               usb_unlink_urb (port->read_urb);
+               if (serial->dev) {
+                       if (c_cflag & HUPCL){
+                               /* Disable flow control */
+                               if (usb_control_msg(serial->dev, 
+                                                   usb_sndctrlpipe(serial->dev, 0),
+                                                   FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+                                                   
+FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+                                                   0, 0, buf, 0, WDR_TIMEOUT) < 0) {
+                                       err("error from flowcontrol urb");
+                               }           
+
+                               /* drop DTR */
+                               if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 
+0), LOW) < 0){
+                                       err("Error from DTR LOW urb");
+                               }
+                               /* drop RTS */
+                               if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 
+0),LOW) < 0) {
+                                       err("Error from RTS LOW urb");
+                               }       
+                       } /* Note change no line is hupcl is off */
+
+                       /* shutdown our bulk reads and writes */
+                       /* ***CHECK*** behaviour when there is nothing queued */
+                       usb_unlink_urb (port->write_urb);
+                       usb_unlink_urb (port->read_urb);
+               }
                port->active = 0;
                port->open_count = 0;
        } else {  
-               spin_unlock_irqrestore (&port->port_lock, flags);
-
                /* Send a HUP if necessary */
                if (!(port->tty->termios->c_cflag & CLOCAL)){
                        tty_hangup(port->tty);
                }
-               
        }
 
+       up (&port->sem);
        MOD_DEC_USE_COUNT;
 
 } /* ftdi_sio_close */
@@ -402,10 +413,9 @@
 { /* ftdi_sio_write */
        struct usb_serial *serial = port->serial;
        struct ftdi_private *priv = (struct ftdi_private *)port->private;
+       unsigned char *first_byte = port->write_urb->transfer_buffer;
        int data_offset ;
-       int rc; 
        int result;
-       DECLARE_WAITQUEUE(wait, current);
        
        dbg(__FUNCTION__ " port %d, %d bytes", port->number, count);
 
@@ -414,87 +424,63 @@
                return 0;
        }
        
-       if (priv->ftdi_type == sio){
-               data_offset = 1;
-       } else {
-               data_offset = 0;
-       }
+       data_offset = priv->write_offset;
         dbg("data_offset set to %d",data_offset);
 
-       /* only do something if we have a bulk out endpoint */
-       if (serial->num_bulk_out) {
-               unsigned char *first_byte = port->write_urb->transfer_buffer;
-
-               /* Was seeing a race here, got a read callback, then write callback 
before
-                  hitting interuptible_sleep_on  - so wrapping in a wait_queue */
-
-               add_wait_queue(&port->write_wait, &wait);
-               set_current_state (TASK_INTERRUPTIBLE);
-               while (port->write_urb->status == -EINPROGRESS) {
-                       dbg(__FUNCTION__ " write in progress - retrying");
-                       if (signal_pending(current)) {
-                               current->state = TASK_RUNNING;
-                               remove_wait_queue(&port->write_wait, &wait);
-                               rc = -ERESTARTSYS;
-                               goto err;
-                       }
-                       schedule();
-               }               
-               remove_wait_queue(&port->write_wait, &wait);
-               set_current_state(TASK_RUNNING);
+       if (port->write_urb->status == -EINPROGRESS) {
+               dbg (__FUNCTION__ " - already writing");
+               return (0);
+       }               
 
-               count += data_offset;
-               count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-               if (count == 0) {
-                       return 0;
-               }
+       down(&port->sem);
+
+       count += data_offset;
+       count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
                /* Copy in the data to send */
-               if (from_user) {
-                       copy_from_user(port->write_urb->transfer_buffer + data_offset 
, 
-                                      buf, count - data_offset );
-               }
-               else {
-                       memcpy(port->write_urb->transfer_buffer + data_offset,
-                              buf, count - data_offset );
-               }  
-
-               first_byte = port->write_urb->transfer_buffer;
-               if (data_offset > 0){
-                       /* Write the control byte at the front of the packet*/
-                       *first_byte = 1 | ((count-data_offset) << 2) ; 
+       if (from_user) {
+               if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
+                                  buf, count - data_offset )){
+                       up (&port->sem);
+                       return -EFAULT;
                }
+       } else {
+               memcpy(port->write_urb->transfer_buffer + data_offset,
+                      buf, count - data_offset );
+       }  
+
+       first_byte = port->write_urb->transfer_buffer;
+       if (data_offset > 0){
+               /* Write the control byte at the front of the packet*/
+               *first_byte = 1 | ((count-data_offset) << 2) ; 
+       }
 
-               dbg(__FUNCTION__ " Bytes: %d, First Byte: 0o%03o",count, 
first_byte[0]);
-               usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
+       dbg(__FUNCTION__ " Bytes: %d, First Byte: 0x%02x",count, first_byte[0]);
+       usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
                
-               /* send the data out the bulk port */
-               FILL_BULK_URB(port->write_urb, serial->dev, 
-                             usb_sndbulkpipe(serial->dev, 
port->bulk_out_endpointAddress),
-                             port->write_urb->transfer_buffer, count,
-                             ftdi_sio_write_bulk_callback, port);
+       /* send the data out the bulk port */
+       FILL_BULK_URB(port->write_urb, serial->dev, 
+                     usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+                     port->write_urb->transfer_buffer, count,
+                     ftdi_sio_write_bulk_callback, port);
                
-               result = usb_submit_urb(port->write_urb);
-               if (result) {
-                       err(__FUNCTION__ " - failed submitting write urb, error %d", 
result);
-                       return 0;
-               }
-
-               dbg(__FUNCTION__ " write returning: %d", count - data_offset);
-               return (count - data_offset);
+       result = usb_submit_urb(port->write_urb);
+       if (result) {
+               err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+               up (&port->sem);
+               return 0;
        }
-       
-       /* no bulk out, so return 0 bytes written */
-       return 0;
- err: /* error exit */
-       return(rc);
+       up (&port->sem);
+
+       dbg(__FUNCTION__ " write returning: %d", count - data_offset);
+       return (count - data_offset);
+
 } /* ftdi_sio_write */
 
 static void ftdi_sio_write_bulk_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
        struct usb_serial *serial;
-               struct tty_struct *tty = port->tty;
 
        dbg("ftdi_sio_write_bulk_callback");
 
@@ -511,16 +497,29 @@
                dbg("nonzero write bulk status received: %d", urb->status);
                return;
        }
+       queue_task(&port->tqueue, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
 
-       wake_up_interruptible(&port->write_wait);
-       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
-               (tty->ldisc.write_wakeup)(tty);
-
-       wake_up_interruptible(&tty->write_wait);
-       
        return;
 } /* ftdi_sio_write_bulk_callback */
 
+
+static int ftdi_sio_write_room( struct usb_serial_port *port )
+{
+       struct ftdi_private *priv = (struct ftdi_private *)port->private;
+       int room;
+       if ( port->write_urb->status == -EINPROGRESS) {
+               /* There is a race here with the _write routines but it won't hurt */
+               room = 0;
+       } else { 
+               room = port->bulk_out_size - priv->write_offset;
+       }
+       return(room);
+
+
+} /* ftdi_sio_write_room */
+
+
 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;
@@ -533,7 +532,7 @@
        int i;
        int result;
 
-       dbg(__FUNCTION__);
+       dbg(__FUNCTION__ " - port %d", port->number);
 
        if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
                return;
@@ -625,12 +624,12 @@
 #endif
 
        /* Continue trying to always read  */
-       FILL_BULK_URB(urb, serial->dev, 
+       FILL_BULK_URB(port->read_urb, serial->dev, 
                      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
-                     urb->transfer_buffer, urb->transfer_buffer_length,
+                     port->read_urb->transfer_buffer, 
+port->read_urb->transfer_buffer_length,
                      ftdi_sio_read_bulk_callback, port);
 
-       result = usb_submit_urb(urb);
+       result = usb_submit_urb(port->read_urb);
        if (result)
                err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 
@@ -638,7 +637,7 @@
 } /* ftdi_sio_serial_read_bulk_callback */
 
 
-__u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
+static __u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
 { /* translate_baudrate_to_ftdi */
        
        __u16 urb_value = ftdi_sio_b9600;
@@ -883,7 +882,8 @@
 
        case TIOCMSET: /* Turns on and off the lines as specified by the mask */
                dbg(__FUNCTION__ " TIOCMSET");
-               if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+               if (get_user(mask, (unsigned long *) arg))
+                       return -EFAULT;
                urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
                if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 
0){
                        err("Error from DTR set urb (TIOCMSET)");
@@ -896,7 +896,8 @@
                                        
        case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
                dbg(__FUNCTION__ " TIOCMBIS");
-               if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+               if (get_user(mask, (unsigned long *) arg))
+                       return -EFAULT;
                if (mask & TIOCM_DTR){
                        if ((ret = set_dtr(serial->dev, 
                                           usb_sndctrlpipe(serial->dev, 0),
@@ -917,7 +918,8 @@
 
        case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
                dbg(__FUNCTION__ " TIOCMBIC");
-               if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+               if (get_user(mask, (unsigned long *) arg))
+                       return -EFAULT;
                if (mask & TIOCM_DTR){
                        if ((ret = set_dtr(serial->dev, 
                                           usb_sndctrlpipe(serial->dev, 0),


_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to