patch-2.4.0-test10 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
- Lines: 278
- Date:
Tue Oct 31 12:24:04 2000
- Orig file:
v2.4.0-test9/linux/drivers/usb/rio500.c
- Orig date:
Tue Aug 29 14:09:15 2000
diff -u --recursive --new-file v2.4.0-test9/linux/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 ||
@@ -113,15 +121,22 @@
data = (void *) arg;
if (data == NULL)
break;
- if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand)))
- return -EFAULT;
- if (rio_cmd.length > PAGE_SIZE)
- return -EINVAL;
+ if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) {
+ retval = -EFAULT;
+ goto err_out;
+ }
+ if (rio_cmd.length > PAGE_SIZE) {
+ retval = -EINVAL;
+ goto err_out;
+ }
buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
if (buffer == NULL)
return -ENOMEM;
- if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length))
- return -EFAULT;
+ if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
+ retval = -EFAULT;
+ free_page((unsigned long) buffer);
+ goto err_out;
+ }
requesttype = rio_cmd.requesttype | USB_DIR_IN |
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
@@ -131,6 +146,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 +167,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 +184,7 @@
be swapped at the app level */
}
+ up(&(rio->lock));
free_page((unsigned long) buffer);
break;
@@ -178,8 +199,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 +211,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 +235,7 @@
}
}
+ up(&(rio->lock));
free_page((unsigned long) buffer);
break;
@@ -220,6 +245,9 @@
}
return 0;
+
+err_out:
+ return retval;
}
static ssize_t
@@ -234,6 +262,7 @@
int result = 0;
int maxretry;
+ int errn = 0;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
@@ -241,19 +270,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 +302,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 +315,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 +351,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 +376,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 +384,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 {
+ unlock_kernel();
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;
}
@@ -382,6 +437,8 @@
return NULL;
}
dbg("probe_rio: ibuf address:%p", rio->ibuf);
+
+ init_MUTEX(&(rio->lock));
return rio;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)