[argyllcms] Re: Spyder2 stopped working - device. Linux ehci-hcd driver has a bug.

  • From: Graeme Gill <graeme@xxxxxxxxxxxxx>
  • To: argyllcms@xxxxxxxxxxxxx
  • Date: Tue, 19 Jul 2011 11:44:08 +1000

Ok, here's a status report.

Alan has looked into the problem and noticed a subtle bug in
Linux's ehci-hcd controller, and supplied a patch.

I've tried this out on my (getting old) 2.6.23.1 Linux
system, and this does indeed fix the problem I've been able
to reproduce using an external USB 2.0 hub.

I guess it will take a while for this fix to make it into
Linux releases, so the only short term fix would be for
people to patch their own Linux kernel and re-compile it.

Attached is Alan's patch for those who feel up to doing this.

cheers,

Graeme Gill.

Index: usb-3.0/drivers/usb/host/ehci-q.c
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci-q.c
+++ usb-3.0/drivers/usb/host/ehci-q.c
@@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct
        if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
                unsigned        is_out, epnum;

-               is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+               is_out = qh->is_out;
                epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
                if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
                        hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
@@ -946,6 +946,7 @@ done:
        hw = qh->hw;
        hw->hw_info1 = cpu_to_hc32(ehci, info1);
        hw->hw_info2 = cpu_to_hc32(ehci, info2);
+       qh->is_out = !is_input;
        usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
        qh_refresh (ehci, qh);
        return qh;
Index: usb-3.0/drivers/usb/host/ehci.h
===================================================================
--- usb-3.0.orig/drivers/usb/host/ehci.h
+++ usb-3.0/drivers/usb/host/ehci.h
@@ -377,6 +377,7 @@ struct ehci_qh {
 #define NO_FRAME ((unsigned short)~0)                  /* pick new start */

        struct usb_device       *dev;           /* access to TT */
+       unsigned                is_out:1;       /* bulk or intr OUT */
        unsigned                clearing_tt:1;  /* Clear-TT-Buf in progress */
 };




Other related posts: