patch-2.2.19 linux/drivers/usb/rio500.c

Next file: linux/drivers/usb/scanner.c
Previous file: linux/drivers/usb/printer.c
Back to the patch index
Back to the overall index

diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.18/drivers/usb/rio500.c linux/drivers/usb/rio500.c
@@ -36,6 +36,7 @@
 #include <linux/malloc.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
+#include <linux/smp_lock.h>
 
 #include "rio500_usb.h"
 
@@ -57,6 +58,7 @@
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
+	struct semaphore lock;          /* general race avoidance */
 };
 
 static struct rio_usb_data rio_instance;
@@ -65,7 +67,10 @@
 {
 	struct rio_usb_data *rio = &rio_instance;
 
+	lock_kernel();
+
 	if (rio->isopen || !rio->present) {
+		unlock_kernel();
 		return -EBUSY;
 	}
 	rio->isopen = 1;
@@ -74,6 +79,8 @@
 
 	MOD_INC_USE_COUNT;
 
+	unlock_kernel();
+
 	info("Rio opened.");
 
 	return 0;
@@ -101,6 +108,7 @@
 	unsigned char *buffer;
 	int result, requesttype;
 	int retries;
+	int retval;
 
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
@@ -120,8 +128,10 @@
 		buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
 		if (buffer == NULL)
 			return -ENOMEM;
-		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length))
+		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
+			free_page((unsigned long) buffer);
 			return -EFAULT;
+		}
 
 		requesttype = rio_cmd.requesttype | USB_DIR_IN |
 		    USB_TYPE_VENDOR | USB_RECIP_DEVICE;
@@ -131,6 +141,7 @@
 		     rio_cmd.index, rio_cmd.length);
 		/* Send rio control message */
 		retries = 3;
+		down(&(rio->lock));
 		while (retries) {
 			result = usb_control_msg(rio->rio_dev,
 						 usb_rcvctrlpipe(rio-> rio_dev, 0),
@@ -151,8 +162,12 @@
 				     le32_to_cpu(result),
 				     le32_to_cpu(*((long *) buffer)));
 				if (copy_to_user(rio_cmd.buffer, buffer,
-						 rio_cmd.length))
-					return -EFAULT;
+						 rio_cmd.length)) {
+					up(&(rio->lock));
+					free_page((unsigned long) buffer);
+					retval = -EFAULT;
+					goto err_out;
+				}
 				retries = 0;
 			}
 
@@ -164,6 +179,7 @@
 			   be swapped at the app level */
 
 		}
+		up(&(rio->lock));
 		free_page((unsigned long) buffer);
 		break;
 
@@ -178,8 +194,10 @@
 		buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
 		if (buffer == NULL)
 			return -ENOMEM;
-		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length))
+		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
+			free_page((unsigned long)buffer);
 			return -EFAULT;
+		}
 
 		requesttype = rio_cmd.requesttype | USB_DIR_OUT |
 		    USB_TYPE_VENDOR | USB_RECIP_DEVICE;
@@ -188,6 +206,7 @@
 		     rio_cmd.index, rio_cmd.length);
 		/* Send rio control message */
 		retries = 3;
+		down(&(rio->lock));
 		while (retries) {
 			result = usb_control_msg(rio->rio_dev,
 						 usb_sndctrlpipe(rio-> rio_dev, 0),
@@ -211,6 +230,7 @@
 			}
 
 		}
+		up(&(rio->lock));
 		free_page((unsigned long) buffer);
 		break;
 
@@ -220,6 +240,10 @@
 	}
 
 	return 0;
+
+err_out:
+	up(&(rio->lock));
+	return retval;
 }
 
 static ssize_t
@@ -234,6 +258,7 @@
 
 	int result = 0;
 	int maxretry;
+	int errn = 0;
 
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
@@ -241,19 +266,26 @@
              rio->rio_dev == NULL )
           return -1;
 
+	down(&(rio->lock));
+
 	do {
 		unsigned long thistime;
 		char *obuf = rio->obuf;
 
 		thistime = copy_size =
 		    (count >= OBUF_SIZE) ? OBUF_SIZE : count;
-		if (copy_from_user(rio->obuf, buffer, copy_size))
-			return -EFAULT;
+		if (copy_from_user(rio->obuf, buffer, copy_size)) {
+			errn = -EFAULT;
+			goto error;
+		}
 		maxretry = 5;
 		while (thistime) {
-			if (!rio->rio_dev)
-				return -ENODEV;
+			if (!rio->rio_dev) {
+				errn = -ENODEV;
+				goto error;
+			}
 			if (signal_pending(current)) {
+				up(&(rio->lock));
 				return bytes_written ? bytes_written : -EINTR;
 			}
 
@@ -266,7 +298,8 @@
 
 			if (result == USB_ST_TIMEOUT) {	/* NAK - so hold for a while */
 				if (!maxretry--) {
-					return -ETIME;
+					errn = -ETIME;
+					goto error;
 				}
 				interruptible_sleep_on_timeout(&rio-> wait_q, NAK_TIMEOUT);
 				continue;
@@ -278,14 +311,21 @@
 		};
 		if (result) {
 			err("Write Whoops - %x", result);
-			return -EIO;
+			errn = -EIO;
+			goto error;
 		}
 		bytes_written += copy_size;
 		count -= copy_size;
 		buffer += copy_size;
 	} while (count > 0);
 
+	up(&(rio->lock));
+
 	return bytes_written ? bytes_written : -EIO;
+
+error:
+	up(&(rio->lock));
+	return errn;
 }
 
 static ssize_t
@@ -307,12 +347,17 @@
 
 	read_count = 0;
 
+	down(&(rio->lock));
+
 	while (count > 0) {
 		if (signal_pending(current)) {
+			up(&(rio->lock));
 			return read_count ? read_count : -EINTR;
 		}
-		if (!rio->rio_dev)
+		if (!rio->rio_dev) {
+			up(&(rio->lock));
 			return -ENODEV;
+		}
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
 
 		result = usb_bulk_msg(rio->rio_dev,
@@ -327,6 +372,7 @@
 			count = this_read = partial;
 		} else if (result == USB_ST_TIMEOUT || result == 15) {	/* FIXME: 15 ??? */
 			if (!maxretry--) {
+				up(&(rio->lock));
 				err("read_rio: maxretry timeout");
 				return -ETIME;
 			}
@@ -334,21 +380,26 @@
 						       NAK_TIMEOUT);
 			continue;
 		} else if (result != USB_ST_DATAUNDERRUN) {
+			up(&(rio->lock));
 			err("Read Whoops - result:%u partial:%u this_read:%u",
 			     result, partial, this_read);
 			return -EIO;
 		} else {
+			up(&(rio->lock));
 			return (0);
 		}
 
 		if (this_read) {
-			if (copy_to_user(buffer, ibuf, this_read))
+			if (copy_to_user(buffer, ibuf, this_read)) {
+				up(&(rio->lock));
 				return -EFAULT;
+			}
 			count -= this_read;
 			read_count += this_read;
 			buffer += this_read;
 		}
 	}
+	up(&(rio->lock));
 	return read_count;
 }
 
@@ -383,6 +434,8 @@
 	}
 	dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
+	init_MUTEX(&(rio->lock));
+
 	return rio;
 }
 
@@ -415,12 +468,11 @@
 
 static struct
 usb_driver rio_driver = {
-	"rio500",
-	probe_rio,
-	disconnect_rio,
-	{NULL, NULL},
-	&usb_rio_fops,
-	RIO_MINOR
+	name:		"rio500",
+	probe:		probe_rio,
+	disconnect:	disconnect_rio,
+	fops:		&usb_rio_fops,
+	minor:		RIO_MINOR,
 };
 
 int usb_rio_init(void)

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