patch-2.4.0-test8 linux/drivers/usb/serial/visor.c

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

diff -u --recursive --new-file v2.4.0-test7/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
@@ -11,6 +11,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (08/28/2000) gkh
+ *	Added locks for SMP safeness.
+ *
  * (08/08/2000) gkh
  *	Fixed endian problem in visor_startup.
  *	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more 
@@ -109,21 +112,23 @@
 
 
 #define NUM_URBS	24
-static struct urb *write_urb_pool[NUM_URBS];
-
+static struct urb	*write_urb_pool[NUM_URBS];
+static spinlock_t	write_urb_pool_lock;
 
 /******************************************************************************
  * Handspring Visor specific driver functions
  ******************************************************************************/
 static int visor_open (struct usb_serial_port *port, struct file *filp)
 {
-	dbg(__FUNCTION__ " - port %d", port->number);
+	unsigned long flags;
 
-	if (port->active) {
-		dbg (__FUNCTION__ " - device already open");
-		return -EINVAL;
-	}
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+	
+	dbg(__FUNCTION__ " - port %d", port->number);
 
+	spin_lock_irqsave (&port->port_lock, flags);
+	
 	++port->open_count;
 	MOD_INC_USE_COUNT;
 	
@@ -135,21 +140,34 @@
 			dbg(__FUNCTION__  " - usb_submit_urb(read bulk) failed");
 	}
 	
+	spin_unlock_irqrestore (&port->port_lock, flags);
+	
 	return 0;
 }
 
 
 static void visor_close (struct usb_serial_port *port, struct file * filp)
 {
-	struct usb_serial *serial = port->serial;
-	unsigned char *transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+	struct usb_serial *serial;
+	unsigned char *transfer_buffer;
+	unsigned long flags;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
 	
 	dbg(__FUNCTION__ " - port %d", port->number);
 			 
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
+	
+	spin_lock_irqsave (&port->port_lock, flags);
+
 	--port->open_count;
 	MOD_DEC_USE_COUNT;
 
 	if (port->open_count <= 0) {
+		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
 		if (!transfer_buffer) {
 			err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
 		} else {
@@ -164,6 +182,8 @@
 		port->active = 0;
 		port->open_count = 0;
 	}
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
 }
 
 
@@ -174,6 +194,7 @@
 	unsigned char *buffer = NULL;
 	int status;
 	int i;
+	unsigned long flags;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
@@ -183,12 +204,14 @@
 	}
 
 	/* try to find a free urb in our list of them */
+	spin_lock_irqsave (&write_urb_pool_lock, flags);
 	for (i = 0; i < NUM_URBS; ++i) {
 		if (write_urb_pool[i]->status != -EINPROGRESS) {
 			urb = write_urb_pool[i];
 			break;
 		}
 	}
+	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 	if (urb == NULL) {
 		dbg (__FUNCTION__ " - no free urbs");
 		return 0;
@@ -256,21 +279,33 @@
 
 static void visor_throttle (struct usb_serial_port *port)
 {
+	unsigned long flags;
+
 	dbg(__FUNCTION__ " - port %d", port->number);
 
+	spin_lock_irqsave (&port->port_lock, flags);
+
 	usb_unlink_urb (port->read_urb);
 
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
 	return;
 }
 
 
 static void visor_unthrottle (struct usb_serial_port *port)
 {
+	unsigned long flags;
+
 	dbg(__FUNCTION__ " - port %d", port->number);
 
+	spin_lock_irqsave (&port->port_lock, flags);
+
 	if (usb_submit_urb (port->read_urb))
 		dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
 
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
 	return;
 }
 
@@ -429,13 +464,14 @@
 }
 
 
-int visor_init (void)
+static int __init visor_init (void)
 {
 	int i;
 
 	usb_serial_register (&handspring_device);
 	
 	/* create our write urb pool */ 
+	spin_lock_init (&write_urb_pool_lock);
 	for (i = 0; i < NUM_URBS; ++i) {
 		struct urb  *urb = usb_alloc_urb(0);
 		if (urb == NULL) {
@@ -450,18 +486,23 @@
 }
 
 
-void visor_exit (void)
+static void __exit visor_exit (void)
 {
 	int i;
+	unsigned long flags;
 
 	usb_serial_deregister (&handspring_device);
-	
+
+	spin_lock_irqsave (&write_urb_pool_lock, flags);
+
 	for (i = 0; i < NUM_URBS; ++i) {
 		usb_unlink_urb(write_urb_pool[i]);
 		if (write_urb_pool[i]->transfer_buffer)
 			kfree(write_urb_pool[i]->transfer_buffer);
 		usb_free_urb (write_urb_pool[i]);
 	}
+
+	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
 }
 
 

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