Subject: [PATCH 02 of 15] USB Serial Belkin driver updated
From: Greg KH <[email-masked]>
To: Alan Cox <[email-masked]>
Cc: [email-masked]

This patch updates the belkin_sa driver.

diff -Nru a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
--- a/drivers/usb/serial/belkin_sa.c	Thu Jan  3 21:41:53 2002
+++ b/drivers/usb/serial/belkin_sa.c	Thu Jan  3 21:41:53 2002
@@ -23,7 +23,10 @@
  *    framework in, but haven't analyzed the "tty_flip" interface yet.
  * -- Add support for flush commands
  * -- Add everything that is missing :)
- * 
+ *
+ * 30-May-2001 gkh
+ *	switched from using spinlock to a semaphore, which fixes lots of problems.
+ *
  * 08-Apr-2001 gb
  *	- Identify version on module load.
  *
@@ -85,7 +88,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "William Greathouse <[email-masked]>"
 #define DRIVER_DESC "USB Belkin Serial converter driver"
 
@@ -99,6 +102,30 @@
 static int  belkin_sa_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 static void belkin_sa_break_ctl		(struct usb_serial_port *port, int break_state );
 
+/* All of the device info needed for the Belkin dockstation serial converter */
+static __u16	belkin_dockstation_vendor_id	= BELKIN_DOCKSTATION_VID;
+static __u16	belkin_dockstation_product_id	= BELKIN_DOCKSTATION_PID;
+struct usb_serial_device_type belkin_dockstation_device = {
+	name:			"Belkin F5U120-PC USB Serial Adapter",
+	idVendor:		&belkin_dockstation_vendor_id,
+	idProduct:		&belkin_dockstation_product_id,
+	needs_interrupt_in:	MUST_HAVE,			/* this device must have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,			/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,			/* this device must have a bulk out endpoint */
+	num_interrupt_in:	1,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			belkin_sa_open,
+	close:			belkin_sa_close,
+	read_int_callback:	belkin_sa_read_int_callback,	/* How we get the status info */
+	ioctl:			belkin_sa_ioctl,
+	set_termios:		belkin_sa_set_termios,
+	break_ctl:		belkin_sa_break_ctl,
+	startup:		belkin_sa_startup,
+	shutdown:		belkin_sa_shutdown,
+};
+
 /* All of the device info needed for the Belkin serial converter */
 static __u16	belkin_sa_vendor_id	= BELKIN_SA_VID;
 static __u16	belkin_sa_product_id	= BELKIN_SA_PID;
@@ -263,11 +290,11 @@
 
 static int  belkin_sa_open (struct usb_serial_port *port, struct file *filp)
 {
-	unsigned long flags;
+	int retval = 0;
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	spin_lock_irqsave (&port->port_lock, flags);
+	down (&port->sem);
 	
 	++port->open_count;
 	MOD_INC_USE_COUNT;
@@ -280,47 +307,61 @@
 		 *       enhance buffering.  Win trace shows 16 initial read URBs.
 		 */
 		port->read_urb->dev = port->serial->dev;
-		if (usb_submit_urb(port->read_urb))
+		retval = usb_submit_urb(port->read_urb);
+		if (retval) {
 			err("usb_submit_urb(read bulk) failed");
+			goto exit;
+		}
 
 		port->interrupt_in_urb->dev = port->serial->dev;
-		if (usb_submit_urb(port->interrupt_in_urb))
+		retval = usb_submit_urb(port->interrupt_in_urb);
+		if (retval)
 			err(" usb_submit_urb(read int) failed");
 	}
 	
-	spin_unlock_irqrestore (&port->port_lock, flags);
+exit:
+	up (&port->sem);
 
-	return 0;
+	return retval;
 } /* belkin_sa_open */

 static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
 {
-	unsigned long flags;
+	struct usb_serial *serial;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
 
 	dbg(__FUNCTION__" port %d", port->number);
 
-	spin_lock_irqsave (&port->port_lock, flags);
+	down (&port->sem);
 
 	--port->open_count;
-	MOD_DEC_USE_COUNT;
 
 	if (port->open_count <= 0) {
-		/* shutdown our bulk reads and writes */
-		usb_unlink_urb (port->write_urb);
-		usb_unlink_urb (port->read_urb);
-		usb_unlink_urb (port->interrupt_in_urb);	/* wgg - do I need this? I think so. */
+		if (serial->dev) {
+			/* shutdown our bulk reads and writes */
+			usb_unlink_urb (port->write_urb);
+			usb_unlink_urb (port->read_urb);
+			usb_unlink_urb (port->interrupt_in_urb);
+		}
 		port->active = 0;
 	}
 	
-	spin_unlock_irqrestore (&port->port_lock, flags);
+	up (&port->sem);
+	MOD_DEC_USE_COUNT;
 } /* belkin_sa_close */

 static void belkin_sa_read_int_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private;
+	struct belkin_sa_private *priv;
 	struct usb_serial *serial;
 	unsigned char *data = urb->transfer_buffer;
 
@@ -328,16 +369,17 @@
 	if (urb->status)
 		return;
 	
-	if (port_paranoia_check (port, "belkin_sa_read_interrupt")) return;
+	if (port_paranoia_check (port, __FUNCTION__)) return;
 
 	serial = port->serial;
-	if (serial_paranoia_check (serial, "belkin_sa_read_interrupt")) return;
+	if (serial_paranoia_check (serial, __FUNCTION__)) return;
 	
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
 	/* Handle known interrupt data */
 	/* ignore data[0] and data[1] */
 
+	priv = (struct belkin_sa_private *)port->private;
 	priv->last_msr = data[BELKIN_SA_MSR_INDEX];
 	
 	/* Record Control Line states */
@@ -526,7 +568,8 @@
 	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
 	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
 	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
-		if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+		if (get_user(mask, (unsigned long *) arg))
+			return -EFAULT;
 
 		if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
 			/* RTS needs set */
@@ -577,17 +620,19 @@
 
 static int __init belkin_sa_init (void)
 {
+	usb_serial_register (&belkin_dockstation_device);
 	usb_serial_register (&belkin_sa_device);
 	usb_serial_register (&belkin_old_device);
 	usb_serial_register (&peracom_device);
 	usb_serial_register (&gocom232_device);
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
 }

 static void __exit belkin_sa_exit (void)
 {
+	usb_serial_deregister (&belkin_dockstation_device);
 	usb_serial_deregister (&belkin_sa_device);
 	usb_serial_deregister (&belkin_old_device);
 	usb_serial_deregister (&peracom_device);
diff -Nru a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h
--- a/drivers/usb/serial/belkin_sa.h	Thu Jan  3 21:41:53 2002
+++ b/drivers/usb/serial/belkin_sa.h	Thu Jan  3 21:41:53 2002
@@ -33,6 +33,9 @@
 #ifndef __LINUX_USB_SERIAL_BSA_H
 #define __LINUX_USB_SERIAL_BSA_H
 
+#define BELKIN_DOCKSTATION_VID	0x050d	/* Vendor Id */
+#define BELKIN_DOCKSTATION_PID	0x1203	/* Product Id */
+
 #define BELKIN_SA_VID	0x050d	/* Vendor Id */
 #define BELKIN_SA_PID	0x0103	/* Product Id */