diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index cb8f2ed1cf..08dbc66aa6 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -119,6 +119,7 @@ EHCI::EHCI(pci_info *info, Stack *stack) fCleanupThread(-1), fStopThreads(false), fFreeListHead(NULL), + fProcessingPipe(NULL), fRootHub(NULL), fRootHubAddress(0), fPortCount(0), @@ -941,6 +942,10 @@ EHCI::CancelQueuedTransfers(Pipe *pipe, bool force) list = next; } + // wait for any transfers that might have made it before canceling + while (fProcessingPipe == pipe) + snooze(1000); + // notify the finisher so it can clean up the canceled transfers release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); return B_OK; @@ -1075,6 +1080,11 @@ EHCI::FinishTransfers() if (transfer == fLastTransfer) fLastTransfer = lastTransfer; + // store the currently processing pipe here so we can wait + // in cancel if we are processing something on the target pipe + if (!transfer->canceled) + fProcessingPipe = transfer->transfer->TransferPipe(); + transfer->link = NULL; Unlock(); } @@ -1135,6 +1145,7 @@ EHCI::FinishTransfers() } transfer->transfer->Finished(callbackStatus, actualLength); + fProcessingPipe = NULL; } // unlink hardware queue and delete the transfer diff --git a/src/add-ons/kernel/busses/usb/ehci.h b/src/add-ons/kernel/busses/usb/ehci.h index 1cf6e0c866..6c5417817b 100644 --- a/src/add-ons/kernel/busses/usb/ehci.h +++ b/src/add-ons/kernel/busses/usb/ehci.h @@ -157,6 +157,7 @@ static pci_module_info * sPCIModule; thread_id fCleanupThread; bool fStopThreads; ehci_qh * fFreeListHead; + Pipe * fProcessingPipe; // Root Hub EHCIRootHub * fRootHub; diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index 7a3179effd..ec67e3168d 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -71,6 +71,7 @@ OHCI::OHCI(pci_info *info, Stack *stack) fFinishTransfersSem(-1), fFinishThread(-1), fStopFinishThread(false), + fProcessingPipe(NULL), fRootHub(NULL), fRootHubAddress(0), fPortCount(0) @@ -472,6 +473,10 @@ OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) list = next; } + // wait for any transfers that might have made it before canceling + while (fProcessingPipe == pipe) + snooze(1000); + // notify the finisher so it can clean up the canceled transfers release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); return B_OK; @@ -1021,6 +1026,11 @@ OHCI::_FinishTransfers() if (transfer == fLastTransfer) fLastTransfer = lastTransfer; + // store the currently processing pipe here so we can wait + // in cancel if we are processing something on the target pipe + if (!transfer->canceled) + fProcessingPipe = transfer->transfer->TransferPipe(); + transfer->link = NULL; Unlock(); } @@ -1071,6 +1081,7 @@ OHCI::_FinishTransfers() } transfer->transfer->Finished(callbackStatus, actualLength); + fProcessingPipe = NULL; } if (callbackStatus != B_OK) { diff --git a/src/add-ons/kernel/busses/usb/ohci.h b/src/add-ons/kernel/busses/usb/ohci.h index b23ce6f46e..1117406116 100644 --- a/src/add-ons/kernel/busses/usb/ohci.h +++ b/src/add-ons/kernel/busses/usb/ohci.h @@ -163,6 +163,7 @@ static pci_module_info * sPCIModule; sem_id fFinishTransfersSem; thread_id fFinishThread; bool fStopFinishThread; + Pipe * fProcessingPipe; // Root Hub OHCIRootHub * fRootHub; diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index c9f7fb554f..30364b5af1 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -335,6 +335,7 @@ UHCI::UHCI(pci_info *info, Stack *stack) fFinishTransfersSem(-1), fFinishThread(-1), fStopThreads(false), + fProcessingPipe(NULL), fFreeList(NULL), fCleanupThread(-1), fCleanupSem(-1), @@ -795,6 +796,10 @@ UHCI::CancelQueuedTransfers(Pipe *pipe, bool force) list = next; } + // wait for any transfers that might have made it before canceling + while (fProcessingPipe == pipe) + snooze(1000); + // notify the finisher so it can clean up the canceled transfers release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); return B_OK; @@ -1340,6 +1345,11 @@ UHCI::FinishTransfers() if (transfer == fLastTransfer) fLastTransfer = lastTransfer; + // store the currently processing pipe here so we can wait + // in cancel if we are processing something on the target pipe + if (!transfer->canceled) + fProcessingPipe = transfer->transfer->TransferPipe(); + transfer->link = NULL; Unlock(); } @@ -1399,6 +1409,7 @@ UHCI::FinishTransfers() } transfer->transfer->Finished(callbackStatus, actualLength); + fProcessingPipe = NULL; } // remove and free the hardware queue and its descriptors diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index e4623ea1b9..195fda68eb 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -233,6 +233,7 @@ static pci_module_info * sPCIModule; sem_id fFinishTransfersSem; thread_id fFinishThread; bool fStopThreads; + Pipe * fProcessingPipe; transfer_data * fFreeList; thread_id fCleanupThread;