patch-2.4.15 linux/drivers/usb/serial/ftdi_sio.c

Next file: linux/drivers/usb/serial/io_edgeport.c
Previous file: linux/drivers/usb/kaweth.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.14/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
@@ -12,9 +12,18 @@
  *
  * 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.
  *
@@ -97,7 +106,6 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
-
 #ifdef CONFIG_USB_SERIAL_DEBUG
 	static int debug = 1;
 #else
@@ -111,7 +119,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1.0"
+#define DRIVER_VERSION "v1.2.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>"
 #define DRIVER_DESC "USB FTDI RS232 Converters Driver"
 
@@ -146,6 +154,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);
@@ -154,6 +163,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);
@@ -176,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,
@@ -198,6 +209,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,
@@ -252,7 +264,6 @@
 {
 	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){
@@ -261,6 +272,7 @@
 	}
 
 	priv->ftdi_type = sio;
+	priv->write_offset = 1;
 	
 	return (0);
 }
@@ -270,7 +282,6 @@
 {
 	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){
@@ -279,6 +290,7 @@
 	}
 
 	priv->ftdi_type = F8U232AM;
+	priv->write_offset = 0;
 	
 	return (0);
 }
@@ -288,13 +300,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);
+	        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;
 	}
 }
 
@@ -361,7 +374,7 @@
 
 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];
 
@@ -393,6 +406,7 @@
 			} /* 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);
 		}
@@ -403,7 +417,6 @@
 		if (!(port->tty->termios->c_cflag & CLOCAL)){
 			tty_hangup(port->tty);
 		}
-		
 	}
 
 	up (&port->sem);
@@ -423,10 +436,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);
 
@@ -435,95 +447,70 @@
 		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)) {
-				set_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);
-
-		count += data_offset;
-		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-		if (count == 0) {
-			return 0;
-		}
+	if (port->write_urb->status == -EINPROGRESS) {
+		dbg (__FUNCTION__ " - already writing");
+		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) {
-			if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
-					   buf, count - data_offset ))
-				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) ; 
+	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");
 
 	if (port_paranoia_check (port, "ftdi_sio_write_bulk_callback")) {
 		return;
 	}
-
+	
 	serial = port->serial;
 	if (serial_paranoia_check (serial, "ftdi_sio_write_bulk_callback")) {
 		return;
@@ -533,16 +520,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;
@@ -555,7 +555,7 @@
 	int i;
 	int result;
 
-	dbg(__FUNCTION__);
+	dbg(__FUNCTION__ " - port %d", port->number);
 
 	if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
 		return;
@@ -647,12 +647,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);
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)