]>
Commit | Line | Data |
---|---|---|
0d1514e0 GKH |
1 | From e04f5f7e423018bcec84c11af2058cdce87816f3 Mon Sep 17 00:00:00 2001 |
2 | From: Alan Stern <stern@rowland.harvard.edu> | |
3 | Date: Tue, 19 Jul 2011 14:01:23 -0400 | |
4 | Subject: EHCI: fix direction handling for interrupt data toggles | |
5 | ||
6 | From: Alan Stern <stern@rowland.harvard.edu> | |
7 | ||
8 | commit e04f5f7e423018bcec84c11af2058cdce87816f3 upstream. | |
9 | ||
10 | This patch (as1480) fixes a rather obscure bug in ehci-hcd. The | |
11 | qh_update() routine needs to know the number and direction of the | |
12 | endpoint corresponding to its QH argument. The number can be taken | |
13 | directly from the QH data structure, but the direction isn't stored | |
14 | there. The direction is taken instead from the first qTD linked to | |
15 | the QH. | |
16 | ||
17 | However, it turns out that for interrupt transfers, qh_update() gets | |
18 | called before the qTDs are linked to the QH. As a result, qh_update() | |
19 | computes a bogus direction value, which messes up the endpoint toggle | |
20 | handling. Under the right combination of circumstances this causes | |
21 | usb_reset_endpoint() not to work correctly, which causes packets to be | |
22 | dropped and communications to fail. | |
23 | ||
24 | Now, it's silly for the QH structure not to have direct access to all | |
25 | the descriptor information for the corresponding endpoint. Ultimately | |
26 | it may get a pointer to the usb_host_endpoint structure; for now, | |
27 | adding a copy of the direction flag solves the immediate problem. | |
28 | ||
29 | This allows the Spyder2 color-calibration system (a low-speed USB | |
30 | device that sends all its interrupt data packets with the toggle set | |
31 | to 0 and hance requires constant use of usb_reset_endpoint) to work | |
32 | when connected through a high-speed hub. Thanks to Graeme Gill for | |
33 | supplying the hardware that allowed me to track down this bug. | |
34 | ||
35 | Signed-off-by: Alan Stern <stern@rowland.harvard.edu> | |
36 | Reported-by: Graeme Gill <graeme@argyllcms.com> | |
37 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
38 | ||
39 | --- | |
40 | drivers/usb/host/ehci-q.c | 3 ++- | |
41 | drivers/usb/host/ehci.h | 1 + | |
42 | 2 files changed, 3 insertions(+), 1 deletion(-) | |
43 | ||
44 | --- a/drivers/usb/host/ehci-q.c | |
45 | +++ b/drivers/usb/host/ehci-q.c | |
46 | @@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct | |
47 | if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { | |
48 | unsigned is_out, epnum; | |
49 | ||
50 | - is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); | |
51 | + is_out = qh->is_out; | |
52 | epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; | |
53 | if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { | |
54 | hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); | |
55 | @@ -946,6 +946,7 @@ done: | |
56 | hw = qh->hw; | |
57 | hw->hw_info1 = cpu_to_hc32(ehci, info1); | |
58 | hw->hw_info2 = cpu_to_hc32(ehci, info2); | |
59 | + qh->is_out = !is_input; | |
60 | usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); | |
61 | qh_refresh (ehci, qh); | |
62 | return qh; | |
63 | --- a/drivers/usb/host/ehci.h | |
64 | +++ b/drivers/usb/host/ehci.h | |
65 | @@ -375,6 +375,7 @@ struct ehci_qh { | |
66 | #define NO_FRAME ((unsigned short)~0) /* pick new start */ | |
67 | ||
68 | struct usb_device *dev; /* access to TT */ | |
69 | + unsigned is_out:1; /* bulk or intr OUT */ | |
70 | unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ | |
71 | }; | |
72 |