Hi Petkan,
there are some races in the pegasus driver.
When you submit an URB please keep in mind that the
callback of the URB can be called earlier than
the URB-submition returns. In this case you wake up the
thread first and than put it to sleep.
This **really** happens on
a CPU time eating HC architecture.
The attached patch against kernel 2.4.2ac20 solves
this.
- Roman
--- linux-2.4.2ac20/drivers/usb/pegasus.c Tue Mar 13 12:18:21 2001
+++ usb/pegasus.c Tue Mar 13 12:23:09 2001
@@ -124,7 +124,8 @@
static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
{
int ret;
-
+ DECLARE_WAITQUEUE (wait, current);
+
while ( pegasus->flags & ETH_REGS_CHANGED ) {
pegasus->flags |= CTRL_URB_SLEEP;
interruptible_sleep_on( &pegasus->ctrl_wait );
@@ -140,13 +141,18 @@
usb_rcvctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
data, size, ctrl_callback, pegasus );
-
+
+ add_wait_queue (&pegasus->ctrl_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ pegasus->flags |= CTRL_URB_SLEEP;
+
if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRLs %d", ret);
goto out;
}
- pegasus->flags |= CTRL_URB_SLEEP;
- interruptible_sleep_on( &pegasus->ctrl_wait );
+
+ schedule();
+ remove_wait_queue (&pegasus->ctrl_wait, &wait);
out:
return ret;
}
@@ -155,7 +161,8 @@
static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
{
int ret;
-
+ DECLARE_WAITQUEUE (wait, current);
+
while ( pegasus->flags & ETH_REGS_CHANGED ) {
pegasus->flags |= CTRL_URB_SLEEP ;
interruptible_sleep_on( &pegasus->ctrl_wait );
@@ -171,14 +178,18 @@
usb_sndctrlpipe(pegasus->usb,0),
(char *)&pegasus->dr,
data, size, ctrl_callback, pegasus );
-
+
+ add_wait_queue (&pegasus->ctrl_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ pegasus->flags |= CTRL_URB_SLEEP;
+
if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRL %d", ret);
return ret;
}
- pegasus->flags |= CTRL_URB_SLEEP;
- interruptible_sleep_on( &pegasus->ctrl_wait );
-
+
+ schedule();
+ remove_wait_queue (&pegasus->ctrl_wait, &wait);
return ret;
}
@@ -187,7 +198,8 @@
{
int ret;
__u16 dat = data;
-
+ DECLARE_WAITQUEUE (wait, current);
+
while ( pegasus->flags & ETH_REGS_CHANGED ) {
pegasus->flags |= CTRL_URB_SLEEP;
interruptible_sleep_on( &pegasus->ctrl_wait );
@@ -204,13 +216,18 @@
(char *)&pegasus->dr,
&data, 1, ctrl_callback, pegasus );
+ add_wait_queue (&pegasus->ctrl_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ pegasus->flags |= CTRL_URB_SLEEP;
+
if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
err( __FUNCTION__ " BAD CTRL %d", ret);
return ret;
}
- pegasus->flags |= CTRL_URB_SLEEP;
- interruptible_sleep_on( &pegasus->ctrl_wait );
+ schedule();
+ remove_wait_queue (&pegasus->ctrl_wait, &wait);
+
return ret;
}