From ae61e1b716e7df7a63ce7741299ef9ce90c80a6e Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 27 Sep 2021 16:26:00 -0400 Subject: [PATCH] USB bus drivers: Return error when combining other transfers with a fragmented one. The drivers do not support this properly at present, they would run the other transfers interspersed with fragments from the fragemented one, which is obviously the wrong thing to do. No USB device drivers seem to do this at present (it would cause data corruption if they had.) Fixes #17275. --- src/add-ons/kernel/busses/usb/ehci.cpp | 13 +++++++++++++ src/add-ons/kernel/busses/usb/ohci.cpp | 11 +++++++++++ src/add-ons/kernel/busses/usb/uhci.cpp | 13 +++++++++++++ src/add-ons/kernel/busses/usb/xhci.cpp | 8 ++++++++ 4 files changed, 45 insertions(+) diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index 2be4281c2d..d8713479a2 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -1547,6 +1547,19 @@ EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead, return B_ERROR; } + // We do not support queuing other transfers in tandem with a fragmented one. + transfer_data *it = fFirstTransfer; + while (it) { + if (it->transfer && it->transfer->TransferPipe() == transfer->TransferPipe() + && it->transfer->IsFragmented()) { + TRACE_ERROR("cannot submit transfer: a fragmented transfer is queued\n"); + + Unlock(); + delete data; + return B_DEV_RESOURCE_CONFLICT; + } + } + if (fLastTransfer) fLastTransfer->link = data; else diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index d4df19f559..2490c5b534 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -1451,6 +1451,17 @@ OHCI::_SubmitTransfer(Transfer *transfer) = (ohci_endpoint_descriptor *)pipe->ControllerCookie(); MutexLocker endpointLocker(endpoint->lock); + + // We do not support queuing other transfers in tandem with a fragmented one. + transfer_data *it = fFirstTransfer; + while (it) { + if (it->transfer && it->transfer->TransferPipe() == pipe && it->transfer->IsFragmented()) { + TRACE_ERROR("cannot submit transfer: a fragmented transfer is queued\n"); + _FreeDescriptorChain(firstDescriptor); + return B_DEV_RESOURCE_CONFLICT; + } + } + result = _AddPendingTransfer(transfer, endpoint, firstDescriptor, firstDescriptor, lastDescriptor, directionIn); if (result < B_OK) { diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 644f949a61..86c13cd6f2 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -1065,6 +1065,19 @@ UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue, return B_ERROR; } + // We do not support queuing other transfers in tandem with a fragmented one. + transfer_data *it = fFirstTransfer; + while (it) { + if (it->transfer && it->transfer->TransferPipe() == transfer->TransferPipe() + && it->transfer->IsFragmented()) { + TRACE_ERROR("cannot submit transfer: a fragmented transfer is queued\n"); + + Unlock(); + delete data; + return B_DEV_RESOURCE_CONFLICT; + } + } + if (fLastTransfer) fLastTransfer->link = data; if (!fFirstTransfer) diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index 73d1564281..486fa28729 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -1846,6 +1846,14 @@ XHCI::_LinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint) return B_BAD_VALUE; } + // We do not support queuing other transfers in tandem with a fragmented one. + if (endpoint->td_head != NULL && endpoint->td_head->transfer != NULL + && endpoint->td_head->transfer->IsFragmented()) { + TRACE_ERROR("cannot submit transfer: a fragmented transfer is queued\n"); + mutex_unlock(&endpoint->lock); + return B_DEV_RESOURCE_CONFLICT; + } + endpoint->used++; descriptor->next = endpoint->td_head; endpoint->td_head = descriptor;