From patchwork Tue Aug 25 19:06:12 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: David X-Patchwork-Id: 43790 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n7PJ74Mw005376 for ; Tue, 25 Aug 2009 19:07:04 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755662AbZHYTHB (ORCPT ); Tue, 25 Aug 2009 15:07:01 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1755641AbZHYTHB (ORCPT ); Tue, 25 Aug 2009 15:07:01 -0400 Received: from ns01.unsolicited.net ([69.10.132.115]:3033 "EHLO ns01.unsolicited.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755512AbZHYTHA (ORCPT ); Tue, 25 Aug 2009 15:07:00 -0400 Message-ID: <4A943624.8090302@unsolicited.net> Date: Tue, 25 Aug 2009 20:06:12 +0100 From: David User-Agent: Thunderbird 2.0.0.23 (X11/20090817) MIME-Version: 1.0 To: =?ISO-8859-1?Q?Andr=E9_Weidemann?= CC: linux-media@vger.kernel.org Subject: Re: Technotrend TT-Connect S-2400 References: <4A90CA6B.4080303@gmail.com> <4A92CB24.4060300@unsolicited.net> <4A92D752.3050009@web.de> In-Reply-To: <4A92D752.3050009@web.de> X-Enigmail-Version: 0.95.0 Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org André Weidemann wrote: > Could please post a link to this patch? I think that a few people on > this list, including me, are interested in a solution. The patches should be small enough to post here and are attached. They were sent to me by Alan Stern when he was looking at the issue. Apply patch 1 then 2. (I think they only apply to 2.6.30) Cheers David Index: usb-2.6/drivers/usb/host/ehci-hcd.c =================================================================== --- usb-2.6.orig/drivers/usb/host/ehci-hcd.c +++ usb-2.6/drivers/usb/host/ehci-hcd.c @@ -1032,12 +1032,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_qh *qh; int eptype = usb_endpoint_type(&ep->desc); + int epnum = usb_endpoint_num(&ep->desc); + int is_out = usb_endpoint_dir_out(&ep->desc); + unsigned long flags; if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT) return; - rescan: - spin_lock_irq(&ehci->lock); + spin_lock_irqsave(&ehci->lock, flags); qh = ep->hcpriv; /* For Bulk and Interrupt endpoints we maintain the toggle state @@ -1046,29 +1048,24 @@ ehci_endpoint_reset(struct usb_hcd *hcd, * the toggle bit in the QH. */ if (qh) { + usb_settoggle(qh->dev, epnum, is_out, 0); if (!list_empty(&qh->qtd_list)) { WARN_ONCE(1, "clear_halt for a busy endpoint\n"); - } else if (qh->qh_state == QH_STATE_IDLE) { - qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); - } else { - /* It's not safe to write into the overlay area - * while the QH is active. Unlink it first and - * wait for the unlink to complete. + } else if (qh->qh_state == QH_STATE_LINKED) { + + /* The toggle value in the QH can't be updated + * while the QH is active. Unlink it now; + * re-linking will call qh_refresh(). */ - if (qh->qh_state == QH_STATE_LINKED) { - if (eptype == USB_ENDPOINT_XFER_BULK) { - unlink_async(ehci, qh); - } else { - intr_deschedule(ehci, qh); - (void) qh_schedule(ehci, qh); - } + if (eptype == USB_ENDPOINT_XFER_BULK) { + unlink_async(ehci, qh); + } else { + intr_deschedule(ehci, qh); + (void) qh_schedule(ehci, qh); } - spin_unlock_irq(&ehci->lock); - schedule_timeout_uninterruptible(1); - goto rescan; } } - spin_unlock_irq(&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); } static int ehci_get_frame (struct usb_hcd *hcd) Index: usb-2.6/drivers/usb/host/ehci-q.c =================================================================== --- usb-2.6.orig/drivers/usb/host/ehci-q.c +++ usb-2.6/drivers/usb/host/ehci-q.c @@ -93,6 +93,22 @@ qh_update (struct ehci_hcd *ehci, struct qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); qh->hw_alt_next = EHCI_LIST_END(ehci); + /* Except for control endpoints, we make hardware maintain data + * toggle (like OHCI) ... here (re)initialize the toggle in the QH, + * and set the pseudo-toggle in udev. Only usb_clear_halt() will + * ever clear it. + */ + if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { + unsigned is_out, epnum; + + is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); + epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f; + if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { + qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); + usb_settoggle (qh->dev, epnum, is_out, 1); + } + } + /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ wmb (); qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); @@ -877,6 +893,7 @@ done: qh->qh_state = QH_STATE_IDLE; qh->hw_info1 = cpu_to_hc32(ehci, info1); qh->hw_info2 = cpu_to_hc32(ehci, info2); + usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); qh_refresh (ehci, qh); return qh; } @@ -911,7 +928,7 @@ static void qh_link_async (struct ehci_h } } - /* clear halt and maybe recover from silicon quirk */ + /* clear halt and/or toggle; and maybe recover from silicon quirk */ if (qh->qh_state == QH_STATE_IDLE) qh_refresh (ehci, qh);