patch-2.4.18 linux/drivers/usb/mdc800.c
Next file: linux/drivers/usb/ov511.c
Previous file: linux/drivers/usb/audio.c
Back to the patch index
Back to the overall index
- Lines: 360
- Date:
Wed Dec 26 14:28:36 2001
- Orig file:
linux.orig/drivers/usb/mdc800.c
- Orig date:
Mon Feb 18 20:18:40 2002
diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
@@ -30,8 +30,14 @@
*
* The driver supports only one camera.
*
- * (08/04/2001) gb
+ * Fix: mdc800 used sleep_on and slept with io_lock held.
+ * Converted sleep_on to waitqueues with schedule_timeout and made io_lock
+ * a semaphore from a spinlock.
+ * by Oliver Neukum <520047054719-0001@t-online.de>
+ * (02/12/2001)
+ *
* Identify version on module load.
+ * (08/04/2001) gb
*
* version 0.7.5
* Fixed potential SMP races with Spinlocks.
@@ -136,6 +142,7 @@
purb_t irq_urb;
wait_queue_head_t irq_wait;
+ int irq_woken;
char* irq_urb_buffer;
int camera_busy; // is camera busy ?
@@ -145,11 +152,13 @@
purb_t write_urb;
char* write_urb_buffer;
wait_queue_head_t write_wait;
+ int written;
purb_t download_urb;
char* download_urb_buffer;
wait_queue_head_t download_wait;
+ int downloaded;
int download_left; // Bytes left to download ?
@@ -159,7 +168,7 @@
int out_count; // Bytes in the buffer
int open; // Camera device open ?
- spinlock_t io_lock; // IO -lock
+ struct semaphore io_lock; // IO -lock
char in [8]; // Command Input Buffer
int in_count;
@@ -284,6 +293,7 @@
if (wake_up)
{
mdc800->camera_request_ready=0;
+ mdc800->irq_woken=1;
wake_up_interruptible (&mdc800->irq_wait);
}
}
@@ -300,9 +310,19 @@
*/
static int mdc800_usb_waitForIRQ (int mode, int msec)
{
+ DECLARE_WAITQUEUE(wait, current);
+
mdc800->camera_request_ready=1+mode;
- interruptible_sleep_on_timeout (&mdc800->irq_wait, msec*HZ/1000);
+ add_wait_queue(&mdc800->irq_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!mdc800->irq_woken)
+ {
+ schedule_timeout (msec*HZ/1000);
+ }
+ remove_wait_queue(&mdc800->irq_wait, &wait);
+ set_current_state(TASK_RUNNING);
+ mdc800->irq_woken = 0;
if (mdc800->camera_request_ready>0)
{
@@ -337,6 +357,7 @@
{
mdc800->state=READY;
}
+ mdc800->written = 1;
wake_up_interruptible (&mdc800->write_wait);
}
@@ -364,6 +385,7 @@
{
err ("request bytes fails (status:%i)", urb->status);
}
+ mdc800->downloaded = 1;
wake_up_interruptible (&mdc800->download_wait);
}
@@ -445,7 +467,7 @@
info ("Found Mustek MDC800 on USB.");
- spin_lock (&mdc800->io_lock);
+ down (&mdc800->io_lock);
mdc800->dev=dev;
mdc800->open=0;
@@ -484,7 +506,7 @@
mdc800->state=READY;
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return mdc800;
}
@@ -558,7 +580,7 @@
int retval=0;
int errn=0;
- spin_lock (&mdc800->io_lock);
+ down (&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
{
@@ -594,7 +616,7 @@
dbg ("Mustek MDC800 device opened.");
error_out:
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return errn;
}
@@ -607,10 +629,9 @@
int retval=0;
dbg ("Mustek MDC800 device closed.");
- spin_lock (&mdc800->io_lock);
+ down (&mdc800->io_lock);
if (mdc800->open && (mdc800->state != NOT_CONNECTED))
{
- spin_unlock(&mdc800->io_lock);
usb_unlink_urb (mdc800->irq_urb);
usb_unlink_urb (mdc800->write_urb);
usb_unlink_urb (mdc800->download_urb);
@@ -618,11 +639,10 @@
}
else
{
- spin_unlock (&mdc800->io_lock);
retval=-EIO;
}
-
+ up(&mdc800->io_lock);
return retval;
}
@@ -634,22 +654,23 @@
{
int left=len, sts=len; /* single transfer size */
char* ptr=buf;
+ DECLARE_WAITQUEUE(wait, current);
- spin_lock (&mdc800->io_lock);
+ down (&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
{
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EBUSY;
}
if (mdc800->state == WORKING)
{
warn ("Illegal State \"working\" reached during read ?!");
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EBUSY;
}
if (!mdc800->open)
{
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EBUSY;
}
@@ -657,7 +678,7 @@
{
if (signal_pending (current))
{
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EINTR;
}
@@ -676,21 +697,29 @@
if (usb_submit_urb (mdc800->download_urb))
{
err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return len-left;
}
- interruptible_sleep_on_timeout (&mdc800->download_wait, TO_DOWNLOAD_GET_READY*HZ/1000);
+ add_wait_queue(&mdc800->download_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!mdc800->downloaded)
+ {
+ schedule_timeout (TO_DOWNLOAD_GET_READY*HZ/1000);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&mdc800->download_wait, &wait);
+ mdc800->downloaded = 0;
if (mdc800->download_urb->status != 0)
{
err ("request download-bytes fails (status=%i)",mdc800->download_urb->status);
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return len-left;
}
}
else
{
/* No more bytes -> that's an error*/
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EIO;
}
}
@@ -704,7 +733,7 @@
}
}
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return len-left;
}
@@ -718,16 +747,17 @@
static ssize_t mdc800_device_write (struct file *file, const char *buf, size_t len, loff_t *pos)
{
int i=0;
+ DECLARE_WAITQUEUE(wait, current);
- spin_lock (&mdc800->io_lock);
+ down (&mdc800->io_lock);
if (mdc800->state != READY)
{
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EBUSY;
}
if (!mdc800->open )
{
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EBUSY;
}
@@ -735,7 +765,7 @@
{
if (signal_pending (current))
{
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EINTR;
}
@@ -757,7 +787,7 @@
else
{
err ("Command is to long !\n");
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EIO;
}
@@ -769,7 +799,7 @@
if (mdc800_usb_waitForIRQ (0,TO_GET_READY))
{
err ("Camera didn't get ready.\n");
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EIO;
}
@@ -781,14 +811,22 @@
if (usb_submit_urb (mdc800->write_urb))
{
err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EIO;
}
- interruptible_sleep_on_timeout (&mdc800->write_wait, TO_WRITE_GET_READY*HZ/1000);
+ add_wait_queue(&mdc800->write_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!mdc800->written)
+ {
+ schedule_timeout (TO_WRITE_GET_READY*HZ/1000);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&mdc800->write_wait, &wait);
+ mdc800->written = 0;
if (mdc800->state == WORKING)
{
usb_unlink_urb (mdc800->write_urb);
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EIO;
}
@@ -800,7 +838,7 @@
{
err ("call 0x07 before 0x05,0x3e");
mdc800->state=READY;
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EIO;
}
mdc800->pic_len=-1;
@@ -819,7 +857,7 @@
if (mdc800_usb_waitForIRQ (1,TO_READ_FROM_IRQ))
{
err ("requesting answer from irq fails");
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EIO;
}
@@ -847,7 +885,7 @@
if (mdc800_usb_waitForIRQ (0,TO_DEFAULT_COMMAND))
{
err ("Command Timeout.");
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return -EIO;
}
}
@@ -857,7 +895,7 @@
}
i++;
}
- spin_unlock (&mdc800->io_lock);
+ up (&mdc800->io_lock);
return i;
}
@@ -916,11 +954,15 @@
mdc800->dev=0;
mdc800->open=0;
mdc800->state=NOT_CONNECTED;
- spin_lock_init (&mdc800->io_lock);
+ init_MUTEX (&mdc800->io_lock);
init_waitqueue_head (&mdc800->irq_wait);
init_waitqueue_head (&mdc800->write_wait);
init_waitqueue_head (&mdc800->download_wait);
+
+ mdc800->irq_woken = 0;
+ mdc800->downloaded = 0;
+ mdc800->written = 0;
try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL));
try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL));
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)