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