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;
 }
 

Reply via email to