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>
This commit is contained in:
Родитель
bf162019b7
Коммит
92bc3648e6
|
@ -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 */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче