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>
This commit is contained in:
Clemens Ladisch 2010-03-01 09:12:50 +01:00 коммит произвёл Greg Kroah-Hartman
Родитель bf162019b7
Коммит 92bc3648e6
1 изменённых файлов: 19 добавлений и 5 удалений

Просмотреть файл

@ -1565,13 +1565,27 @@ itd_patch(
static inline void static inline void
itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
{ {
/* always prepend ITD/SITD ... only QH tree is order-sensitive */ union ehci_shadow *prev = &ehci->pshadow[frame];
itd->itd_next = ehci->pshadow [frame]; __hc32 *hw_p = &ehci->periodic[frame];
itd->hw_next = ehci->periodic [frame]; union ehci_shadow here = *prev;
ehci->pshadow [frame].itd = itd; __hc32 type = 0;
/* skip any iso nodes which might belong to previous microframes */
while (here.ptr) {
type = Q_NEXT_TYPE(ehci, *hw_p);
if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
break;
prev = periodic_next_shadow(ehci, prev, type);
hw_p = shadow_next_periodic(ehci, &here, type);
here = *prev;
}
itd->itd_next = here;
itd->hw_next = *hw_p;
prev->itd = itd;
itd->frame = frame; itd->frame = frame;
wmb (); wmb ();
ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
} }
/* fit urb's itds into the selected schedule slot; activate as needed */ /* fit urb's itds into the selected schedule slot; activate as needed */