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
- Lines: 280
- Date:
Sun Mar 25 11:37:37 2001
- Orig file:
v2.2.18/drivers/usb/rio500.c
- Orig date:
Sun Mar 25 11:28:32 2001
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)