This patch fixes a long-standing (albeit unidentified) problem in the
queueing code for the UHCI HCD.  The code propagates data toggle settings
between messages in a queue for control transfers just the same as bulk
and interrupt transfers.  That is a mistake, since control messages always
restart with data toggle 0.  With this patch, the UHCI driver now passes
test 10 (control URB queueing) in David Brownell's usbtest suite.

The patch appears to change more than it really does, because it alters
the indentation level of a large section of code.

Charles, this will probably fix up the problems you were having when you 
tried to run usbtest a month ago.

Johannes, I would appreciate it if you could verify this patch together 
with the two others I sent in last week (as80 and as81) so that they can 
be applied.

Alan Stern


--- 2.6.0/drivers/usb/host/uhci-hcd.c.orig      Mon Aug 11 09:36:37 2003
+++ 2.6.0/drivers/usb/host/uhci-hcd.c   Mon Aug 11 10:25:33 2003
@@ -522,8 +522,12 @@
 
        lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
 
-       usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe),
-               uhci_fixup_toggle(urb, uhci_toggle(td_token(lltd)) ^ 1));
+       /* Control transfers always start with toggle 0 */
+       if (!usb_pipecontrol(urb->pipe))
+               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                               usb_pipeout(urb->pipe),
+                               uhci_fixup_toggle(urb,
+                                       uhci_toggle(td_token(lltd)) ^ 1));
 
        /* All qh's in the queue need to link to the next queue */
        urbp->qh->link = eurbp->qh->link;
@@ -557,38 +561,43 @@
 
        nurbp = list_entry(urbp->queue_list.next, struct urb_priv, queue_list);
 
-       /* Fix up the toggle for the next URB's */
-       if (!urbp->queued)
-               /* We just set the toggle in uhci_unlink_generic */
-               toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), 
usb_pipeout(urb->pipe));
-       else {
-               /* If we're in the middle of the queue, grab the toggle */
-               /*  from the TD previous to us */
-               purbp = list_entry(urbp->queue_list.prev, struct urb_priv,
-                               queue_list);
+       /*
+        * Fix up the toggle for the following URBs in the queue.
+        * Only needed for bulk and interrupt: control and isochronous
+        * endpoints don't propagate toggles between messages.
+        */
+       if (usb_pipebulk(urb->pipe) || usb_pipeint(urb->pipe)) {
+               if (!urbp->queued)
+                       /* We just set the toggle in uhci_unlink_generic */
+                       toggle = usb_gettoggle(urb->dev,
+                                       usb_pipeendpoint(urb->pipe),
+                                       usb_pipeout(urb->pipe));
+               else {
+                       /* If we're in the middle of the queue, grab the */
+                       /* toggle from the TD previous to us */
+                       purbp = list_entry(urbp->queue_list.prev,
+                                       struct urb_priv, queue_list);
+                       pltd = list_entry(purbp->td_list.prev,
+                                       struct uhci_td, list);
+                       toggle = uhci_toggle(td_token(pltd)) ^ 1;
+               }
+
+               head = &urbp->queue_list;
+               tmp = head->next;
+               while (head != tmp) {
+                       struct urb_priv *turbp;
+
+                       turbp = list_entry(tmp, struct urb_priv, queue_list);
+                       tmp = tmp->next;
+
+                       if (!turbp->queued)
+                               break;
+                       toggle = uhci_fixup_toggle(turbp->urb, toggle);
+               }
 
-               pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-
-               toggle = uhci_toggle(td_token(pltd)) ^ 1;
-       }
-
-       head = &urbp->queue_list;
-       tmp = head->next;
-       while (head != tmp) {
-               struct urb_priv *turbp;
-
-               turbp = list_entry(tmp, struct urb_priv, queue_list);
-
-               tmp = tmp->next;
-
-               if (!turbp->queued)
-                       break;
-
-               toggle = uhci_fixup_toggle(turbp->urb, toggle);
+               usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+                               usb_pipeout(urb->pipe), toggle);
        }
-
-       usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
-               usb_pipeout(urb->pipe), toggle);
 
        if (!urbp->queued) {
                struct uhci_qh *pqh;





-------------------------------------------------------
This SF.Net email sponsored by: Free pre-built ASP.NET sites including
Data Reports, E-commerce, Portals, and Forums are available now.
Download today and enter to win an XBOX or Visual Studio .NET.
http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to