diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2010-03-01 03:12:50 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-03-19 10:24:05 -0400 |
commit | 92bc3648e6027384479852b770a542722fadee7c (patch) | |
tree | 9803348ef9fd9186ad375abf89a4e7862e9badc4 | |
parent | bf162019b7f5bda9eb3241ae22de831df2126132 (diff) |
USB: EHCI: fix ITD list order
When isochronous URBs are shorter than one frame and when more than one
ITD in a frame has been completed before the interrupt can be handled,
scan_periodic() completes the URBs in the order in which they are found
in the descriptor list. Therefore, the descriptor list must contain the
ITDs in the correct order, i.e., a new ITD must be linked in after any
previous ITDs of the same endpoint.
This should fix garbled capture data in the USB audio drivers.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Reported-by: Colin Fletcher <colin.m.fletcher@googlemail.com>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 39340ae00ac4..cd1e8bf5327e 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -1565,13 +1565,27 @@ itd_patch( | |||
1565 | static inline void | 1565 | static inline void |
1566 | itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) | 1566 | itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) |
1567 | { | 1567 | { |
1568 | /* always prepend ITD/SITD ... only QH tree is order-sensitive */ | 1568 | union ehci_shadow *prev = &ehci->pshadow[frame]; |
1569 | itd->itd_next = ehci->pshadow [frame]; | 1569 | __hc32 *hw_p = &ehci->periodic[frame]; |
1570 | itd->hw_next = ehci->periodic [frame]; | 1570 | union ehci_shadow here = *prev; |
1571 | ehci->pshadow [frame].itd = itd; | 1571 | __hc32 type = 0; |
1572 | |||
1573 | /* skip any iso nodes which might belong to previous microframes */ | ||
1574 | while (here.ptr) { | ||
1575 | type = Q_NEXT_TYPE(ehci, *hw_p); | ||
1576 | if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) | ||
1577 | break; | ||
1578 | prev = periodic_next_shadow(ehci, prev, type); | ||
1579 | hw_p = shadow_next_periodic(ehci, &here, type); | ||
1580 | here = *prev; | ||
1581 | } | ||
1582 | |||
1583 | itd->itd_next = here; | ||
1584 | itd->hw_next = *hw_p; | ||
1585 | prev->itd = itd; | ||
1572 | itd->frame = frame; | 1586 | itd->frame = frame; |
1573 | wmb (); | 1587 | wmb (); |
1574 | ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); | 1588 | *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); |
1575 | } | 1589 | } |
1576 | 1590 | ||
1577 | /* fit urb's itds into the selected schedule slot; activate as needed */ | 1591 | /* fit urb's itds into the selected schedule slot; activate as needed */ |