On 11/17/2004 21:41, Gilles Espinasse wrote:

>Well 
>thank to inform usb.
>
>It is closed for you but not for us.
>Did you have a link for your patch
>  
>
I thought it would be appropriate to send the patch to usb-users list. 
However, it seems my mail didn't come through so I posted it there once 
more. Hopefully it will show up in archives shortly.

I guess it won't hurt to post the patch here as well, so here it goes 
(seet attachment). The patch was made against the version of uhci-hcd 
driver found in 2.6.9 kernel.

Andrej

P.S. Because I'm not sure how this mailing list handles attachments, the 
copy of patch is also pasted below.

PIIX3-bugfix.patch
<--------cut-here-------->
diff -Naur linux-2.6.9/drivers/usb/host/uhci-hcd.c 
linux-2.6.9-mod/drivers/usb/host/uhci-hcd.c
--- linux-2.6.9/drivers/usb/host/uhci-hcd.c 2004-10-18 
23:55:07.000000000 +0200
+++ linux-2.6.9-mod/drivers/usb/host/uhci-hcd.c 2004-11-17 
19:11:05.000000000 +0100
@@ -27,6 +27,8 @@
 *  - working around the horridness of the rest
 */

+#define PIIX3_BUGFIX
+
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
@@ -604,6 +606,9 @@
   urbp->inserttime = jiffies;
   urbp->fsbrtime = jiffies;
   urbp->urb = urb;
+#ifdef PIIX3_BUGFIX
+   urbp->last_element = NULL;
+#endif
     INIT_LIST_HEAD(&urbp->td_list);
   INIT_LIST_HEAD(&urbp->queue_list);
@@ -1473,6 +1478,73 @@
   spin_unlock(&urb->lock);
}

+#ifdef PIIX3_BUGFIX
+/* Checks whether URB's qh->element points to an active td and fixes it
+ * when necessary. Gives HC a chance to correct this state by ignoring
+ * it for the first time
+ *
+ * Note: URB lock has to be locked before passing URB to this function
+ */
+static void uhci_check_qh_element(struct uhci_hcd *hcd, struct urb* urb) {
+   struct urb_priv *urbp;
+   struct uhci_td *td;
+   struct uhci_td *element_td;
+   dma_addr_t dma_handle;
+   struct list_head *head;
+   __le32 element;
+  +   if (urb->status != -EINPROGRESS)    /* URB dequeued, we've got 
nothing to do */
+       return;
+  +   urbp = (struct urb_priv *)urb->hcpriv;
+   element = urbp->qh->element;
+  +   if (element & UHCI_PTR_TERM)
+       return;
+      +   /* CHECK ME: what can we do when element points to QH? I 
guess that nothing. */
+   if (element & UHCI_PTR_QH)
+       return;
+      +   /* convert dma_handle to td's addresss */
+   /* CHECK ME: this is awkward way to do this, anything simpler? */
+   dma_handle = le32_to_cpu(element & ~ UHCI_PTR_BITS);
+
+   element_td = NULL;
+   head = &urbp->td_list;
+   list_for_each_entry(td, head, list) {
+       if (td->dma_handle == dma_handle) {
+           element_td = td;
+           break;
+       }
+   }
+  +   /* reverse mapping failed, bail out */
+   if (element_td == NULL)
+       return;
+      +   /* check qh->element's state */
+   if (!(td_status(element_td) & TD_CTRL_ACTIVE)) {
+           /* this is first time we observed this state, we give HC a 
time to take care of it */
+       if (urbp->last_element != element_td) {
+           urbp->last_element = element_td;
+       /* HC haven't fixed the intermediate state since last check, 
we'll help it */
+       } else  {  +           /* set qh->element to next linked td */
+           if (debug > 2)
+               dev_dbg(uhci_dev(hcd), "Setting qh->element to td=%x 
(was %x) for URB %p\n",element_td->link,element,urb);
+          +           urbp->qh->element = element_td->link;
+           urbp->last_element = NULL;
+       }  +   } else {
+       urbp->last_element = NULL;
+   }
+
+        return;
+}
+#endif
+
static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
{
   struct list_head *head, *tmp;
@@ -1629,6 +1701,13 @@
       tmp = tmp->next;

       spin_lock(&u->lock);
+      +#ifdef PIIX3_BUGFIX
+       /* Check if the URB's qh->element points to an active td
+        * and fix it if necessary
+        */
+       uhci_check_qh_element(uhci, u);
+#endif   
       /* Check if the FSBR timed out */
       if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, 
up->fsbrtime + IDLE_TIMEOUT))
diff -Naur linux-2.6.9/drivers/usb/host/uhci-hcd.h 
linux-2.6.9-mod/drivers/usb/host/uhci-hcd.h
--- linux-2.6.9/drivers/usb/host/uhci-hcd.h 2004-10-18 
23:54:55.000000000 +0200
+++ linux-2.6.9-mod/drivers/usb/host/uhci-hcd.h 2004-11-17 
12:51:54.000000000 +0100
@@ -394,6 +394,11 @@

   unsigned long inserttime;   /* In jiffies */
   unsigned long fsbrtime;     /* In jiffies */
+  +#ifdef PIIX3_BUGFIX   +   struct uhci_td *last_element;   /* Set to 
the last observed inactive qh->element
+                    * or to NULL if qh->element was active */
+#endif

   struct list_head queue_list;    /* P: uhci->frame_list_lock */
};
<--------cut-here-------->



-- Attached file included as plaintext by Listar --
-- File: PIIX3-bugfix.patch

diff -Naur linux-2.6.9/drivers/usb/host/uhci-hcd.c 
linux-2.6.9-mod/drivers/usb/host/uhci-hcd.c
--- linux-2.6.9/drivers/usb/host/uhci-hcd.c     2004-10-18 23:55:07.000000000 
+0200
+++ linux-2.6.9-mod/drivers/usb/host/uhci-hcd.c 2004-11-17 19:11:05.000000000 
+0100
@@ -27,6 +27,8 @@
  *  - working around the horridness of the rest
  */
 
+#define PIIX3_BUGFIX
+
 #include <linux/config.h>
 #ifdef CONFIG_USB_DEBUG
 #define DEBUG
@@ -604,6 +606,9 @@
        urbp->inserttime = jiffies;
        urbp->fsbrtime = jiffies;
        urbp->urb = urb;
+#ifdef PIIX3_BUGFIX
+       urbp->last_element = NULL;
+#endif 
        
        INIT_LIST_HEAD(&urbp->td_list);
        INIT_LIST_HEAD(&urbp->queue_list);
@@ -1473,6 +1478,73 @@
        spin_unlock(&urb->lock);
 }
 
+#ifdef PIIX3_BUGFIX
+/* Checks whether URB's qh->element points to an active td and fixes it
+ * when necessary. Gives HC a chance to correct this state by ignoring
+ * it for the first time
+ * 
+ * Note: URB lock has to be locked before passing URB to this function
+ */
+static void uhci_check_qh_element(struct uhci_hcd *hcd, struct urb* urb) {
+       struct urb_priv *urbp;
+       struct uhci_td *td;
+       struct uhci_td *element_td;
+       dma_addr_t dma_handle;
+       struct list_head *head;
+       __le32 element;
+       
+       if (urb->status != -EINPROGRESS)        /* URB dequeued, we've got 
nothing to do */
+               return;
+       
+       urbp = (struct urb_priv *)urb->hcpriv;
+       element = urbp->qh->element;
+       
+       if (element & UHCI_PTR_TERM)
+               return;
+               
+       /* CHECK ME: what can we do when element points to QH? I guess that 
nothing. */ 
+       if (element & UHCI_PTR_QH)
+               return;
+               
+       /* convert dma_handle to td's addresss */
+       /* CHECK ME: this is awkward way to do this, anything simpler? */
+       dma_handle = le32_to_cpu(element & ~ UHCI_PTR_BITS);
+
+       element_td = NULL;
+       head = &urbp->td_list;
+       list_for_each_entry(td, head, list) {
+               if (td->dma_handle == dma_handle) {
+                       element_td = td;
+                       break;
+               }
+       }
+       
+       /* reverse mapping failed, bail out */
+       if (element_td == NULL)
+               return;
+           
+       /* check qh->element's state */
+       if (!(td_status(element_td) & TD_CTRL_ACTIVE)) {
+               /* this is first time we observed this state, we give HC a time 
to take care of it */
+               if (urbp->last_element != element_td) {
+                       urbp->last_element = element_td;
+               /* HC haven't fixed the intermediate state since last check, 
we'll help it */
+               } else  {       
+                       /* set qh->element to next linked td */
+                       if (debug > 2)
+                               dev_dbg(uhci_dev(hcd), "Setting qh->element to 
td=%x (was %x) for URB %p\n",element_td->link,element,urb);
+                       
+                       urbp->qh->element = element_td->link;
+                       urbp->last_element = NULL;
+               }       
+       } else {
+               urbp->last_element = NULL;
+       }
+
+        return;
+}
+#endif
+
 static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
 {
        struct list_head *head, *tmp;
@@ -1629,6 +1701,13 @@
                tmp = tmp->next;
 
                spin_lock(&u->lock);
+               
+#ifdef PIIX3_BUGFIX
+               /* Check if the URB's qh->element points to an active td
+                * and fix it if necessary
+                */
+               uhci_check_qh_element(uhci, u);
+#endif         
 
                /* Check if the FSBR timed out */
                if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, 
up->fsbrtime + IDLE_TIMEOUT))
diff -Naur linux-2.6.9/drivers/usb/host/uhci-hcd.h 
linux-2.6.9-mod/drivers/usb/host/uhci-hcd.h
--- linux-2.6.9/drivers/usb/host/uhci-hcd.h     2004-10-18 23:54:55.000000000 
+0200
+++ linux-2.6.9-mod/drivers/usb/host/uhci-hcd.h 2004-11-17 12:51:54.000000000 
+0100
@@ -394,6 +394,11 @@
 
        unsigned long inserttime;       /* In jiffies */
        unsigned long fsbrtime;         /* In jiffies */
+       
+#ifdef PIIX3_BUGFIX    
+       struct uhci_td *last_element;   /* Set to the last observed inactive 
qh->element
+                                        * or to NULL if qh->element was active 
*/
+#endif
 
        struct list_head queue_list;    /* P: uhci->frame_list_lock */
 };


Liste de diffusion modem ALCATEL SpeedTouch USB
Pour se d�sinscrire : mailto:[EMAIL PROTECTED]

        

Reply via email to