patch-2.4.0-test10 linux/drivers/usb/mdc800.c
Next file: linux/drivers/usb/net1080.c
Previous file: linux/drivers/usb/hub.c
Back to the patch index
Back to the overall index
- Lines: 396
- Date:
Tue Oct 31 12:24:04 2000
- Orig file:
v2.4.0-test9/linux/drivers/usb/mdc800.c
- Orig date:
Wed Jul 12 21:58:43 2000
diff -u --recursive --new-file v2.4.0-test9/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
@@ -22,7 +22,7 @@
* (c) 1999/2000 Henning Zabel <henning@uni-paderborn.de>
*
*
- * The driver brings the USB functions of the MDC800 to Linux.
+ * The driver brings the USB functions of the MDC800 to Linux.
* To use the Camera you must support the USB Protocoll of the camera
* to the Kernel Node.
* The Driver uses a misc device Node. Create it with :
@@ -30,6 +30,16 @@
*
* The driver supports only one camera.
*
+ * version 0.7.5
+ * Fixed potential SMP races with Spinlocks.
+ * Thanks to Oliver Neukum <oliver.neukum@lrz.uni-muenchen.de> who
+ * noticed the race conditions.
+ * (30/10/2000)
+ *
+ * Fixed: Setting urb->dev before submitting urb.
+ * by Greg KH <greg@kroah.com>
+ * (13/10/2000)
+ *
* version 0.7.3
* bugfix : The mdc800->state field gets set to READY after the
* the diconnect function sets it to NOT_CONNECTED. This makes the
@@ -61,7 +71,7 @@
* (09/11/1999)
*
* version 0.5.0:
- * first Version that gets a version number. Most of the needed
+ * first Version that gets a version number. Most of the needed
* functions work.
* (20/10/1999)
*/
@@ -80,8 +90,8 @@
#include <linux/usb.h>
-#define VERSION "0.7.3"
-#define RELEASE_DATE "(24/04/2000)"
+#define VERSION "0.7.5"
+#define RELEASE_DATE "(30/10/2000)"
/* Vendor and Product Information */
#define MDC800_VENDOR_ID 0x055f
@@ -123,7 +133,7 @@
int camera_busy; // is camera busy ?
int camera_request_ready; // Status to synchronize with irq
- char camera_response [8]; // last Bytes send after busy
+ char camera_response [8]; // last Bytes send after busy
purb_t write_urb;
char* write_urb_buffer;
@@ -138,16 +148,16 @@
/* Device Data */
char out [64]; // Answer Buffer
- int out_ptr; // Index to the first not readen byte
+ int out_ptr; // Index to the first not readen byte
int out_count; // Bytes in the buffer
- int open; // Camera device open ?
- int rw_lock; // Block read <-> write
+ int open; // Camera device open ?
+ spinlock_t io_lock; // IO -lock
- char in [8]; // Command Input Buffer
+ char in [8]; // Command Input Buffer
int in_count;
- int pic_index; // Cache for the Imagesize (-1 for nothing cached )
+ int pic_index; // Cache for the Imagesize (-1 for nothing cached )
int pic_len;
};
@@ -253,16 +263,16 @@
}
}
wake_up= ( mdc800->camera_request_ready > 0 )
- &&
- (
- ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy))
- ||
- ((mdc800->camera_request_ready == 2) && data_received)
- ||
- ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
- ||
- (urb->status < 0)
- );
+ &&
+ (
+ ((mdc800->camera_request_ready == 1) && (!mdc800->camera_busy))
+ ||
+ ((mdc800->camera_request_ready == 2) && data_received)
+ ||
+ ((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
+ ||
+ (urb->status < 0)
+ );
if (wake_up)
{
@@ -362,7 +372,7 @@
*/
static void* mdc800_usb_probe (struct usb_device *dev ,unsigned int ifnum )
{
- int i,j;
+ int i,j;
struct usb_interface_descriptor *intf_desc;
int irq_interval=0;
@@ -432,10 +442,10 @@
info ("Found Mustek MDC800 on USB.");
+ spin_lock (&mdc800->io_lock);
+
mdc800->dev=dev;
- mdc800->state=READY;
mdc800->open=0;
- mdc800->rw_lock=0;
/* Setup URB Structs */
FILL_INT_URB (
@@ -469,6 +479,10 @@
mdc800
);
+ mdc800->state=READY;
+
+ spin_unlock (&mdc800->io_lock);
+
return mdc800;
}
@@ -539,18 +553,21 @@
static int mdc800_device_open (struct inode* inode, struct file *file)
{
int retval=0;
+ int errn=0;
+
+ spin_lock (&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
{
- return -EBUSY;
+ errn=-EBUSY;
+ goto error_out;
}
-
if (mdc800->open)
{
- return -EBUSY;
+ errn=-EBUSY;
+ goto error_out;
}
- mdc800->rw_lock=0;
mdc800->in_count=0;
mdc800->out_count=0;
mdc800->out_ptr=0;
@@ -562,16 +579,20 @@
mdc800->camera_request_ready=0;
retval=0;
+ mdc800->irq_urb->dev = mdc800->dev;
if (usb_submit_urb (mdc800->irq_urb))
{
err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
- return -EIO;
+ errn = -EIO;
+ goto error_out;
}
mdc800->open=1;
-
dbg ("Mustek MDC800 device opened.");
- return 0;
+
+error_out:
+ spin_unlock (&mdc800->io_lock);
+ return errn;
}
@@ -583,7 +604,7 @@
int retval=0;
dbg ("Mustek MDC800 device closed.");
- lock_kernel();
+ spin_lock (&mdc800->io_lock);
if (mdc800->open && (mdc800->state != NOT_CONNECTED))
{
mdc800->open=0;
@@ -595,7 +616,7 @@
{
retval=-EIO;
}
- unlock_kernel();
+ spin_unlock (&mdc800->io_lock);
return retval;
}
@@ -609,23 +630,29 @@
int left=len, sts=len; /* single transfer size */
char* ptr=buf;
+ spin_lock (&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
+ {
+ spin_unlock (&mdc800->io_lock);
return -EBUSY;
-
+ }
if (mdc800->state == WORKING)
{
warn ("Illegal State \"working\" reached during read ?!");
+ spin_unlock (&mdc800->io_lock);
return -EBUSY;
}
-
- if (!mdc800->open || mdc800->rw_lock)
+ if (!mdc800->open)
+ {
+ spin_unlock (&mdc800->io_lock);
return -EBUSY;
- mdc800->rw_lock=1;
+ }
while (left)
{
- if (signal_pending (current)) {
- mdc800->rw_lock=0;
+ if (signal_pending (current))
+ {
+ spin_unlock (&mdc800->io_lock);
return -EINTR;
}
@@ -640,24 +667,25 @@
mdc800->out_ptr=0;
/* Download -> Request new bytes */
+ mdc800->download_urb->dev = mdc800->dev;
if (usb_submit_urb (mdc800->download_urb))
{
err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return len-left;
}
interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000);
if (mdc800->download_urb->status != 0)
{
err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return len-left;
}
}
else
{
/* No more bytes -> that's an error*/
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return -EIO;
}
}
@@ -671,7 +699,7 @@
}
}
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return len-left;
}
@@ -686,17 +714,23 @@
{
int i=0;
+ spin_lock (&mdc800->io_lock);
if (mdc800->state != READY)
+ {
+ spin_unlock (&mdc800->io_lock);
return -EBUSY;
-
- if (!mdc800->open || mdc800->rw_lock)
+ }
+ if (!mdc800->open )
+ {
+ spin_unlock (&mdc800->io_lock);
return -EBUSY;
- mdc800->rw_lock=1;
+ }
while (i<len)
{
- if (signal_pending (current)) {
- mdc800->rw_lock=0;
+ if (signal_pending (current))
+ {
+ spin_unlock (&mdc800->io_lock);
return -EINTR;
}
@@ -718,7 +752,7 @@
else
{
err ("Command is to long !\n");
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return -EIO;
}
@@ -730,7 +764,7 @@
if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
{
err ("Camera didn't get ready.\n");
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return -EIO;
}
@@ -738,17 +772,18 @@
mdc800->state=WORKING;
memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
+ mdc800->write_urb->dev = mdc800->dev;
if (usb_submit_urb (mdc800->write_urb))
{
err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return -EIO;
}
interruptible_sleep_on_timeout (&mdc800->write_wait, TO_WRITE_GET_READY*HZ/1000);
if (mdc800->state == WORKING)
{
usb_unlink_urb (mdc800->write_urb);
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return -EIO;
}
@@ -760,7 +795,7 @@
{
err ("call 0x07 before 0x05,0x3e");
mdc800->state=READY;
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return -EIO;
}
mdc800->pic_len=-1;
@@ -779,7 +814,7 @@
if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
{
err ("requesting answer from irq fails");
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return -EIO;
}
@@ -807,7 +842,7 @@
if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
{
err ("Command Timeout.");
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return -EIO;
}
}
@@ -817,7 +852,7 @@
}
i++;
}
- mdc800->rw_lock=0;
+ spin_unlock (&mdc800->io_lock);
return i;
}
@@ -866,10 +901,11 @@
/* Allocate Memory */
try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL));
+ memset(mdc800, 0, sizeof(struct mdc800_data));
mdc800->dev=0;
mdc800->open=0;
mdc800->state=NOT_CONNECTED;
- memset(mdc800, 0, sizeof(struct mdc800_data));
+ spin_lock_init (&mdc800->io_lock);
init_waitqueue_head (&mdc800->irq_wait);
init_waitqueue_head (&mdc800->write_wait);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)