Hi,
this patch fixes the oops which was detected by the poisoning in slab.c.
The bug was on of the usual "brown paper bag"-types ;-)

The rest of the patch allows the correct unlink of interrupt urbs when
done in the completion. Additionally, one-shot interrupts are
automatically unlinked after execution, thus it is also possible to stop an
periodic interrupt by setting urb->interval to zero.

Please apply to 2.3.99-pre7.
-- 
         Georg Acher, [EMAIL PROTECTED]         
         http://www.in.tum.de/~acher/
          "Oh no, not again !" The bowl of petunias          
diff -u linux/drivers/usb/usb-uhci.c linux.afs/drivers/usb/usb-uhci.c
--- linux/drivers/usb/usb-uhci.c        Sat Apr 29 07:53:10 2000
+++ linux.afs/drivers/usb/usb-uhci.c    Sat May 13 14:50:29 2000
@@ -12,7 +12,7 @@
  * (C) Copyright 1999 Johannes Erdfelt
  * (C) Copyright 1999 Randy Dunlap
  *
- * $Id: usb-uhci.c,v 1.228 2000/04/02 19:55:51 acher Exp $
+ * $Id: usb-uhci.c,v 1.230 2000/05/13 12:50:29 acher Exp $
  */
 
 #include <linux/config.h>
@@ -48,7 +48,7 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
-#define VERSTR "$Revision: 1.228 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.230 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
 #include "usb-uhci.h"
@@ -109,10 +109,10 @@
 
        while (q != &s->free_desc) {
                qh = list_entry (q, uhci_desc_t, horizontal);
+               q=qh->horizontal.prev;
+
                if ((qh->last_used!=now) || force)
                        delete_qh(s,qh);
-
-               q=qh->horizontal.prev;
        }
 }
 /*-------------------------------------------------------------------*/
@@ -1168,7 +1168,9 @@
        
        async_dbg("unlink_urb_async called %p",urb);
 
-       if (urb->status == -EINPROGRESS) {
+       if ((urb->status == -EINPROGRESS) ||
+           ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && 
+((urb_priv_t*)urb->hcpriv)->flags))
+       {
                ((urb_priv_t*)urb->hcpriv)->started = ~0;
 
                dequeue_urb (s, urb);
@@ -1560,7 +1562,7 @@
 
        urb->hcpriv = urb_priv;
        INIT_LIST_HEAD (&urb_priv->desc_list);
-       urb_priv->short_control_packet = 0;
+       urb_priv->flags = 0;
        dbg("submit_urb: scheduling %p", urb);
        urb_priv->next_queued_urb = NULL;
        urb_priv->prev_queued_urb = NULL;
@@ -2151,7 +2153,7 @@
           status stage is completed
         */
 
-       if (urb_priv->short_control_packet && 
+       if (urb_priv->flags && 
                ((qh->hw.qh.element == UHCI_PTR_TERM) ||(!(last_desc->hw.td.status & 
TD_CTRL_ACTIVE)))) 
                goto transfer_finished;
 
@@ -2199,7 +2201,7 @@
                                        dbg("short packet during control transfer, 
retrigger status stage @ %p",last_desc);
                                        //uhci_show_td (desc);
                                        //uhci_show_td (last_desc);
-                                       urb_priv->short_control_packet=1;
+                                       urb_priv->flags = 1; // mark as short control 
+packet
                                        return 0;
                                }
                        }
@@ -2280,35 +2282,43 @@
                if (urb->complete) {
                        //dbg("process_interrupt: calling completion, status 
%i",status);
                        urb->status = status;
-                       
+                       ((urb_priv_t*)urb->hcpriv)->flags=1; // if unlink_urb is 
+called during completion
+
                        spin_unlock(&s->urb_list_lock);
                        
                        urb->complete ((struct urb *) urb);
                        
                        spin_lock(&s->urb_list_lock);
-                       
-                       urb->status = -EINPROGRESS;
+
+                       ((urb_priv_t*)urb->hcpriv)->flags=0;                           
+         
                }
+               
+               if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) &&
+                           (urb->status != -ENOENT)) {
 
-               // Recycle INT-TD if interval!=0, else mark TD as one-shot
-               if (urb->interval) {
+                       urb->status = -EINPROGRESS;
 
-                       desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
-                       if (status==0) {
-                               ((urb_priv_t*)urb->hcpriv)->started=jiffies;
-                               desc->hw.td.info |= (usb_gettoggle (urb->dev, 
usb_pipeendpoint (urb->pipe),
-                                     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
-                               usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), 
usb_pipeout (urb->pipe));
-                       } else {
-                               desc->hw.td.info |= (!usb_gettoggle (urb->dev, 
usb_pipeendpoint (urb->pipe),
-                                     usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+                       // Recycle INT-TD if interval!=0, else mark TD as one-shot
+                       if (urb->interval) {
+                               
+                               desc->hw.td.info &= ~(1 << TD_TOKEN_TOGGLE);
+                               if (status==0) {
+                                       ((urb_priv_t*)urb->hcpriv)->started=jiffies;
+                                       desc->hw.td.info |= (usb_gettoggle (urb->dev, 
+usb_pipeendpoint (urb->pipe),
+                                                                           
+usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+                                       usb_dotoggle (urb->dev, usb_pipeendpoint 
+(urb->pipe), usb_pipeout (urb->pipe));
+                               } else {
+                                       desc->hw.td.info |= (!usb_gettoggle (urb->dev, 
+usb_pipeendpoint (urb->pipe),
+                                                                            
+usb_pipeout (urb->pipe)) << TD_TOKEN_TOGGLE);
+                               }
+                               desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | 
+TD_CTRL_ACTIVE | TD_CTRL_IOC |
+                                       (urb->transfer_flags & USB_DISABLE_SPD ? 0 : 
+TD_CTRL_SPD) | (3 << 27);
+                               mb();
+                       }
+                       else {
+                               uhci_unlink_urb_async(s, urb);
+                               desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
                        }
-                       desc->hw.td.status= (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE 
| TD_CTRL_IOC |
-                               (urb->transfer_flags & USB_DISABLE_SPD ? 0 : 
TD_CTRL_SPD) | (3 << 27);
-                       mb();
-               }
-               else {
-                       desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
                }
        }
 
@@ -2823,7 +2833,6 @@
                pci_read_config_byte (dev, PCI_CLASS_PROG, &type);
                if (type != 0)
                        continue;
-
 
                if (pci_enable_device (dev) < 0)
                        continue;
diff -u linux/drivers/usb/usb-uhci.h linux.afs/drivers/usb/usb-uhci.h
--- linux/drivers/usb/usb-uhci.h        Thu Apr  6 02:01:25 2000
+++ linux.afs/drivers/usb/usb-uhci.h    Sat May 13 14:50:30 2000
@@ -2,7 +2,7 @@
 #define __LINUX_UHCI_H
 
 /*
-   $Id: usb-uhci.h,v 1.54 2000/04/02 19:55:53 acher Exp $
+   $Id: usb-uhci.h,v 1.55 2000/05/13 12:50:30 acher Exp $
  */
 #define MODNAME "usb-uhci"
 #define UHCI_LATENCY_TIMER 0
@@ -160,7 +160,7 @@
        uhci_desc_t *bottom_qh;
        uhci_desc_t *next_qh;           // next helper QH
        char use_loop;
-       char short_control_packet;
+       char flags;
 } urb_priv_t, *purb_priv_t;
 
 struct virt_root_hub {

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to