diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index 6527888ce5..31caf74004 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -888,9 +888,15 @@ EHCI::CancelQueuedTransfers(Pipe *pipe, bool force) if (!Lock()) return B_ERROR; + struct transfer_entry { + Transfer * transfer; + transfer_entry * next; + }; + + transfer_entry *list = NULL; transfer_data *current = fFirstTransfer; while (current) { - if (current->transfer->TransferPipe() == pipe) { + if (current->transfer && current->transfer->TransferPipe() == pipe) { // clear the active bit so the descriptors are canceled ehci_qtd *descriptor = (ehci_qtd *)current->queue_head->element_log; while (descriptor) { @@ -902,7 +908,14 @@ EHCI::CancelQueuedTransfers(Pipe *pipe, bool force) // if the transfer is canceled by force, the one causing the // cancel is probably not the one who initiated the transfer // and the callback is likely not safe anymore - current->transfer->Finished(B_CANCELED, 0); + transfer_entry *entry + = (transfer_entry *)malloc(sizeof(transfer_entry)); + if (entry != NULL) { + entry->transfer = current->transfer; + current->transfer = NULL; + entry->next = list; + list = entry; + } } current->canceled = true; @@ -913,6 +926,14 @@ EHCI::CancelQueuedTransfers(Pipe *pipe, bool force) Unlock(); + while (list != NULL) { + transfer_entry *next = list->next; + list->transfer->Finished(B_CANCELED, 0); + delete list->transfer; + free(list); + list = next; + } + // notify the finisher so it can clean up the canceled transfers release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); return B_OK; diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index e6f6f1bdb5..1b1da20420 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -426,9 +426,15 @@ OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) if (!Lock()) return B_ERROR; + struct transfer_entry { + Transfer * transfer; + transfer_entry * next; + }; + + transfer_entry *list = NULL; transfer_data *current = fFirstTransfer; while (current) { - if (current->transfer->TransferPipe() == pipe) { + if (current->transfer && current->transfer->TransferPipe() == pipe) { // Check if the skip bit is already set if (!(current->endpoint->flags & OHCI_ENDPOINT_SKIP)) { current->endpoint->flags |= OHCI_ENDPOINT_SKIP; @@ -445,7 +451,14 @@ OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) // If the transfer is canceled by force, the one causing the // cancel is probably not the one who initiated the transfer // and the callback is likely not safe anymore - current->transfer->Finished(B_CANCELED, 0); + transfer_entry *entry + = (transfer_entry *)malloc(sizeof(transfer_entry)); + if (entry != NULL) { + entry->transfer = current->transfer; + current->transfer = NULL; + entry->next = list; + list = entry; + } } current->canceled = true; } @@ -454,6 +467,14 @@ OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) Unlock(); + while (list != NULL) { + transfer_entry *next = list->next; + list->transfer->Finished(B_CANCELED, 0); + delete list->transfer; + free(list); + list = next; + } + // notify the finisher so it can clean up the canceled transfers release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); return B_OK; diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 0ea8cd0cb8..119e4998bb 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -614,9 +614,15 @@ UHCI::CancelQueuedTransfers(Pipe *pipe, bool force) if (!Lock()) return B_ERROR; + struct transfer_entry { + Transfer * transfer; + transfer_entry * next; + }; + + transfer_entry *list = NULL; transfer_data *current = fFirstTransfer; while (current) { - if (current->transfer->TransferPipe() == pipe) { + if (current->transfer && current->transfer->TransferPipe() == pipe) { // clear the active bit so the descriptors are canceled uhci_td *descriptor = current->first_descriptor; while (descriptor) { @@ -628,7 +634,14 @@ UHCI::CancelQueuedTransfers(Pipe *pipe, bool force) // if the transfer is canceled by force, the one causing the // cancel is probably not the one who initiated the transfer // and the callback is likely not safe anymore - current->transfer->Finished(B_CANCELED, 0); + transfer_entry *entry + = (transfer_entry *)malloc(sizeof(transfer_entry)); + if (entry != NULL) { + entry->transfer = current->transfer; + current->transfer = NULL; + entry->next = list; + list = entry; + } } current->canceled = true; @@ -638,6 +651,14 @@ UHCI::CancelQueuedTransfers(Pipe *pipe, bool force) Unlock(); + while (list != NULL) { + transfer_entry *next = list->next; + list->transfer->Finished(B_CANCELED, 0); + delete list->transfer; + free(list); + list = next; + } + // notify the finisher so it can clean up the canceled transfers release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); return B_OK;