diff --git a/src/add-ons/kernel/bus_managers/usb/BusManager.cpp b/src/add-ons/kernel/bus_managers/usb/BusManager.cpp index 8e9d7678b8..bb7c7db319 100644 --- a/src/add-ons/kernel/bus_managers/usb/BusManager.cpp +++ b/src/add-ons/kernel/bus_managers/usb/BusManager.cpp @@ -269,7 +269,7 @@ BusManager::SubmitTransfer(Transfer *transfer) status_t -BusManager::CancelQueuedTransfers(Pipe *pipe) +BusManager::CancelQueuedTransfers(Pipe *pipe, bool force) { // virtual function to be overridden return B_ERROR; diff --git a/src/add-ons/kernel/bus_managers/usb/Device.cpp b/src/add-ons/kernel/bus_managers/usb/Device.cpp index 1970c7df52..0d4b24ced5 100644 --- a/src/add-ons/kernel/bus_managers/usb/Device.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Device.cpp @@ -15,6 +15,7 @@ Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress, : Object(parent), fDeviceDescriptor(desc), fInitOK(false), + fAvailable(true), fConfigurations(NULL), fCurrentConfiguration(NULL), fSpeed(speed), @@ -252,10 +253,29 @@ Device::InitCheck() } +status_t +Device::Changed(change_item **changeList, bool added) +{ + fAvailable = added; + change_item *changeItem = new(std::nothrow) change_item; + if (!changeItem) + return B_NO_MEMORY; + + changeItem->added = added; + changeItem->device = this; + changeItem->link = *changeList; + *changeList = changeItem; + return B_OK; +} + + status_t Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID, void *data, size_t dataLength, size_t *actualLength) { + if (!fAvailable) + return B_ERROR; + return fDefaultPipe->SendRequest( USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type USB_REQUEST_GET_DESCRIPTOR, // request @@ -304,6 +324,8 @@ Device::SetConfiguration(const usb_configuration_info *configuration) status_t Device::SetConfigurationAt(uint8 index) { + if (!fAvailable) + return B_ERROR; if (index >= fDeviceDescriptor.num_configurations) return B_BAD_VALUE; if (&fConfigurations[index] == fCurrentConfiguration) @@ -382,7 +404,7 @@ Device::Unconfigure(bool atDeviceLevel) // another configuration unconfigure will be called with // atDevice = false. otherwise we explicitly want to unconfigure // the device and have to send it the corresponding request. - if (atDeviceLevel) { + if (atDeviceLevel && fAvailable) { status_t result = fDefaultPipe->SendRequest( USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type USB_REQUEST_SET_CONFIGURATION, // request @@ -426,7 +448,7 @@ Device::DeviceDescriptor() const status_t Device::ReportDevice(usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - usb_driver_cookie **cookies, bool added) + usb_driver_cookie **cookies, bool added, bool recursive) { TRACE(("USB Device %d: reporting device\n", fDeviceAddress)); bool supported = false; @@ -526,6 +548,9 @@ Device::BuildDeviceName(char *string, uint32 *index, size_t bufferSize, status_t Device::SetFeature(uint16 selector) { + if (!fAvailable) + return B_ERROR; + return fDefaultPipe->SendRequest( USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, USB_REQUEST_SET_FEATURE, @@ -541,6 +566,9 @@ Device::SetFeature(uint16 selector) status_t Device::ClearFeature(uint16 selector) { + if (!fAvailable) + return B_ERROR; + return fDefaultPipe->SendRequest( USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, USB_REQUEST_CLEAR_FEATURE, @@ -556,6 +584,9 @@ Device::ClearFeature(uint16 selector) status_t Device::GetStatus(uint16 *status) { + if (!fAvailable) + return B_ERROR; + return fDefaultPipe->SendRequest( USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_IN, USB_REQUEST_GET_STATUS, diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 6d47058922..b0b705ac1f 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -30,11 +30,6 @@ Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress, // Set to false again for the hub init. fInitOK = false; - if (benaphore_init(&fLock, "usb hub lock") < B_OK) { - TRACE_ERROR(("USB Hub %d: failed to create hub lock\n", DeviceAddress())); - return; - } - if (fDeviceDescriptor.device_class != 9) { TRACE_ERROR(("USB Hub %d: wrong class! bailing out\n", DeviceAddress())); return; @@ -97,36 +92,26 @@ Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress, Hub::~Hub() { - Lock(); - benaphore_destroy(&fLock); - - // Remove all child devices - for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { - if (!fChildren[i]) - continue; - - TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i])); - rescan_item *rescanList = NULL; - GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false); - GetBusManager()->FreeDevice(fChildren[i]); - GetStack()->RescanDrivers(rescanList); - } - delete fInterruptPipe; } -bool -Hub::Lock() +status_t +Hub::Changed(change_item **changeList, bool added) { - return (benaphore_lock(&fLock) == B_OK); -} + status_t result = Device::Changed(changeList, added); + if (added || result < B_OK) + return result; + for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { + if (fChildren[i] == NULL) + continue; -void -Hub::Unlock() -{ - benaphore_unlock(&fLock); + fChildren[i]->Changed(changeList, false); + fChildren[i] = NULL; + } + + return B_OK; } @@ -189,7 +174,7 @@ Hub::ResetPort(uint8 index) void -Hub::Explore() +Hub::Explore(change_item **changeList) { for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { status_t result = UpdatePortStatus(i); @@ -209,7 +194,6 @@ Hub::Explore() USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1, 0, NULL, 0, NULL); - rescan_item *rescanList = NULL; if (fPortStatus[i].status & PORT_STATUS_CONNECTION) { // new device attached! TRACE(("USB Hub %d: new device connected\n", DeviceAddress())); @@ -234,18 +218,8 @@ Hub::Explore() if (fChildren[i]) { TRACE_ERROR(("USB Hub %d: new device on a port that is already in use\n", DeviceAddress())); - - // Remove previous device first - TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i])); - GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false); - - if (Lock()) { - GetBusManager()->FreeDevice(fChildren[i]); - fChildren[i] = NULL; - Unlock(); - } - - GetStack()->RescanDrivers(rescanList); + fChildren[i]->Changed(changeList, false); + fChildren[i] = NULL; } usb_speed speed = USB_SPEED_FULLSPEED; @@ -256,15 +230,10 @@ Hub::Explore() Device *newDevice = GetBusManager()->AllocateDevice(this, speed); - if (newDevice && Lock()) { + if (newDevice) { + newDevice->Changed(changeList, true); fChildren[i] = newDevice; - Unlock(); - GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, true); - GetStack()->RescanDrivers(rescanList); } else { - if (newDevice) - GetBusManager()->FreeDevice(newDevice); - // the device failed to setup correctly, disable the port // so that the device doesn't get in the way of future // addressing. @@ -277,15 +246,8 @@ Hub::Explore() TRACE(("USB Hub %d: device removed\n", DeviceAddress())); if (fChildren[i]) { TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i])); - GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false); - - if (Lock()) { - GetBusManager()->FreeDevice(fChildren[i]); - fChildren[i] = NULL; - Unlock(); - } - - GetStack()->RescanDrivers(rescanList); + fChildren[i]->Changed(changeList, false); + fChildren[i] = NULL; } } } @@ -325,7 +287,7 @@ Hub::Explore() if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0) continue; - ((Hub *)fChildren[i])->Explore(); + ((Hub *)fChildren[i])->Explore(changeList); } } @@ -357,28 +319,26 @@ Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID, status_t Hub::ReportDevice(usb_support_descriptor *supportDescriptors, uint32 supportDescriptorCount, const usb_notify_hooks *hooks, - usb_driver_cookie **cookies, bool added) + usb_driver_cookie **cookies, bool added, bool recursive) { TRACE(("USB Hub %d: reporting hub\n", DeviceAddress())); // Report ourselfs first status_t result = Device::ReportDevice(supportDescriptors, - supportDescriptorCount, hooks, cookies, added); + supportDescriptorCount, hooks, cookies, added, recursive); - // Then report all of our children - if (!Lock()) - return B_ERROR; + if (!recursive) + return result; for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { if (!fChildren[i]) continue; if (fChildren[i]->ReportDevice(supportDescriptors, - supportDescriptorCount, hooks, cookies, added) == B_OK) + supportDescriptorCount, hooks, cookies, added, true) == B_OK) result = B_OK; } - Unlock(); return result; } diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp index 37a24518e2..3d8bb92367 100644 --- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp @@ -26,7 +26,7 @@ Pipe::Pipe(Object *parent, int8 deviceAddress, uint8 endpointAddress, Pipe::~Pipe() { - CancelQueuedTransfers(); + CancelQueuedTransfers(true); GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED); } @@ -40,9 +40,9 @@ Pipe::SubmitTransfer(Transfer *transfer) status_t -Pipe::CancelQueuedTransfers() +Pipe::CancelQueuedTransfers(bool force) { - return GetBusManager()->CancelQueuedTransfers(this); + return GetBusManager()->CancelQueuedTransfers(this, force); } @@ -309,7 +309,7 @@ ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value, if (actualLength) *actualLength = 0; - CancelQueuedTransfers(); + CancelQueuedTransfers(false); return B_TIMED_OUT; } diff --git a/src/add-ons/kernel/bus_managers/usb/Stack.cpp b/src/add-ons/kernel/bus_managers/usb/Stack.cpp index 5e36f7a9cc..699a78cbc2 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -28,8 +28,13 @@ Stack::Stack() { TRACE(("USB Stack: stack init\n")); - if (benaphore_init(&fLock, "usb stack lock") < B_OK) { - TRACE_ERROR(("USB Stack: failed to create benaphore lock\n")); + if (benaphore_init(&fStackLock, "usb stack lock") < B_OK) { + TRACE_ERROR(("USB Stack: failed to create stack lock\n")); + return; + } + + if (benaphore_init(&fExploreLock, "usb explore lock") < B_OK) { + TRACE_ERROR(("USB Stack: failed to create explore lock\n")); return; } @@ -85,8 +90,10 @@ Stack::~Stack() fStopThreads = true; wait_for_thread(fExploreThread, &result); - Lock(); - benaphore_destroy(&fLock); + benaphore_lock(&fStackLock); + benaphore_destroy(&fStackLock); + benaphore_lock(&fExploreLock); + benaphore_destroy(&fExploreLock); //Release the bus modules for (Vector::Iterator i = fBusManagers.Begin(); @@ -111,14 +118,14 @@ Stack::InitCheck() bool Stack::Lock() { - return (benaphore_lock(&fLock) == B_OK); + return (benaphore_lock(&fStackLock) == B_OK); } void Stack::Unlock() { - benaphore_unlock(&fLock); + benaphore_unlock(&fStackLock); } @@ -189,13 +196,33 @@ Stack::ExploreThread(void *data) Stack *stack = (Stack *)data; while (!stack->fStopThreads) { + if (benaphore_lock(&stack->fExploreLock) != B_OK) + break; + + rescan_item *rescanList = NULL; + change_item *changeItem = NULL; for (int32 i = 0; i < stack->fBusManagers.Count(); i++) { Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub(); if (rootHub) - rootHub->Explore(); + rootHub->Explore(&changeItem); + } + + while (changeItem) { + stack->NotifyDeviceChange(changeItem->device, &rescanList, changeItem->added); + if (!changeItem->added) { + // everyone possibly holding a reference is now notified so we + // can delete the device + changeItem->device->GetBusManager()->FreeDevice(changeItem->device); + } + + change_item *next = changeItem->link; + delete changeItem; + changeItem = next; } stack->fFirstExploreDone = true; + benaphore_unlock(&stack->fExploreLock); + stack->RescanDrivers(rescanList); snooze(USB_DELAY_HUB_EXPLORE); } @@ -277,19 +304,33 @@ Stack::NotifyDeviceChange(Device *device, rescan_item **rescanList, bool added) while (element) { status_t result = device->ReportDevice(element->support_descriptors, element->support_descriptor_count, &element->notify_hooks, - &element->cookies, added); + &element->cookies, added, false); if (result >= B_OK) { - rescan_item *item = new(std::nothrow) rescan_item; - if (!item) - return; - - item->name = element->driver_name; + const char *driverName = element->driver_name; if (element->republish_driver_name) - item->name = element->republish_driver_name; + driverName = element->republish_driver_name; - item->link = *rescanList; - *rescanList = item; + bool already = false; + rescan_item *rescanItem = *rescanList; + while (rescanItem) { + if (strcmp(rescanItem->name, driverName) == 0) { + // this driver is going to be rescanned already + already = true; + break; + } + rescanItem = rescanItem->link; + } + + if (!already) { + rescanItem = new(std::nothrow) rescan_item; + if (!rescanItem) + return; + + rescanItem->name = driverName; + rescanItem->link = *rescanList; + *rescanList = rescanItem; + } } element = element->link; @@ -403,6 +444,9 @@ Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks) usb_driver_info *element = fDriverList; while (element) { if (strcmp(element->driver_name, driverName) == 0) { + if (benaphore_lock(&fExploreLock) != B_OK) + return B_ERROR; + // inform driver about any already present devices for (int32 i = 0; i < fBusManagers.Count(); i++) { Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); @@ -410,12 +454,13 @@ Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks) // Report device will recurse down the whole tree rootHub->ReportDevice(element->support_descriptors, element->support_descriptor_count, hooks, - &element->cookies, true); + &element->cookies, true, true); } } element->notify_hooks.device_added = hooks->device_added; element->notify_hooks.device_removed = hooks->device_removed; + benaphore_unlock(&fExploreLock); return B_OK; } @@ -434,17 +479,21 @@ Stack::UninstallNotify(const char *driverName) usb_driver_info *element = fDriverList; while (element) { if (strcmp(element->driver_name, driverName) == 0) { + if (benaphore_lock(&fExploreLock) != B_OK) + return B_ERROR; + // trigger the device removed hook for (int32 i = 0; i < fBusManagers.Count(); i++) { Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); if (rootHub) rootHub->ReportDevice(element->support_descriptors, element->support_descriptor_count, - &element->notify_hooks, &element->cookies, false); + &element->notify_hooks, &element->cookies, false, true); } element->notify_hooks.device_added = NULL; element->notify_hooks.device_removed = NULL; + benaphore_unlock(&fExploreLock); return B_OK; } diff --git a/src/add-ons/kernel/bus_managers/usb/usb.cpp b/src/add-ons/kernel/bus_managers/usb/usb.cpp index 1cfaa27f86..35b7fe04ff 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb.cpp +++ b/src/add-ons/kernel/bus_managers/usb/usb.cpp @@ -318,7 +318,7 @@ cancel_queued_transfers(usb_pipe pipe) if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) return B_DEV_INVALID_PIPE; - return ((Pipe *)object)->CancelQueuedTransfers(); + return ((Pipe *)object)->CancelQueuedTransfers(false); } diff --git a/src/add-ons/kernel/bus_managers/usb/usb_p.h b/src/add-ons/kernel/bus_managers/usb/usb_p.h index a11ed9912a..2fbd3006b8 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_p.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_p.h @@ -60,6 +60,13 @@ struct usb_driver_info { }; +struct change_item { + bool added; + Device *device; + change_item *link; +}; + + struct rescan_item { const char *name; rescan_item *link; @@ -141,7 +148,8 @@ static int32 ExploreThread(void *data); bool fFirstExploreDone; bool fStopThreads; - benaphore fLock; + benaphore fStackLock; + benaphore fExploreLock; PhysicalMemoryAllocator *fAllocator; uint32 fObjectIndex; @@ -178,7 +186,8 @@ virtual status_t Start(); virtual status_t Stop(); virtual status_t SubmitTransfer(Transfer *transfer); -virtual status_t CancelQueuedTransfers(Pipe *pipe); +virtual status_t CancelQueuedTransfers(Pipe *pipe, + bool force); virtual status_t NotifyPipeChange(Pipe *pipe, usb_change change); @@ -260,7 +269,7 @@ virtual bool DataToggle() { return fDataToggle; }; virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; }; status_t SubmitTransfer(Transfer *transfer); - status_t CancelQueuedTransfers(); + status_t CancelQueuedTransfers(bool force); // Convenience functions for standard requests virtual status_t SetFeature(uint16 selector); @@ -414,6 +423,9 @@ virtual ~Device(); status_t InitCheck(); +virtual status_t Changed(change_item **changeList, + bool added); + virtual uint32 Type() { return USB_OBJECT_DEVICE; }; ControlPipe *DefaultPipe() { return fDefaultPipe; }; @@ -437,7 +449,7 @@ virtual status_t ReportDevice( uint32 supportDescriptorCount, const usb_notify_hooks *hooks, usb_driver_cookie **cookies, - bool added); + bool added, bool recursive); virtual status_t BuildDeviceName(char *string, uint32 *index, size_t bufferSize, Device *device); @@ -452,6 +464,7 @@ protected: bool fInitOK; private: + bool fAvailable; usb_configuration_info *fConfigurations; usb_configuration_info *fCurrentConfiguration; usb_speed fSpeed; @@ -468,8 +481,8 @@ public: usb_speed speed); virtual ~Hub(); - bool Lock(); - void Unlock(); +virtual status_t Changed(change_item **changeList, + bool added); virtual uint32 Type() { return USB_OBJECT_DEVICE | USB_OBJECT_HUB; }; @@ -480,7 +493,7 @@ virtual status_t GetDescriptor(uint8 descriptorType, status_t UpdatePortStatus(uint8 index); status_t ResetPort(uint8 index); - void Explore(); + void Explore(change_item **changeList); static void InterruptCallback(void *cookie, status_t status, void *data, size_t actualLength); @@ -490,14 +503,12 @@ virtual status_t ReportDevice( uint32 supportDescriptorCount, const usb_notify_hooks *hooks, usb_driver_cookie **cookies, - bool added); + bool added, bool recursive); virtual status_t BuildDeviceName(char *string, uint32 *index, size_t bufferSize, Device *device); private: - benaphore fLock; - InterruptPipe *fInterruptPipe; usb_hub_descriptor fHubDescriptor; diff --git a/src/add-ons/kernel/busses/usb/ehci.cpp b/src/add-ons/kernel/busses/usb/ehci.cpp index 8d05b83f12..f24e7276f9 100644 --- a/src/add-ons/kernel/busses/usb/ehci.cpp +++ b/src/add-ons/kernel/busses/usb/ehci.cpp @@ -864,7 +864,7 @@ EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead, status_t -EHCI::CancelQueuedTransfers(Pipe *pipe) +EHCI::CancelQueuedTransfers(Pipe *pipe, bool force) { if (!Lock()) return B_ERROR; @@ -879,7 +879,13 @@ EHCI::CancelQueuedTransfers(Pipe *pipe) descriptor = (ehci_qtd *)descriptor->next_log; } - current->transfer->Finished(B_CANCELED, 0); + if (!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); + } + current->canceled = true; } diff --git a/src/add-ons/kernel/busses/usb/ehci.h b/src/add-ons/kernel/busses/usb/ehci.h index 3faca7d5a3..a042fce72e 100644 --- a/src/add-ons/kernel/busses/usb/ehci.h +++ b/src/add-ons/kernel/busses/usb/ehci.h @@ -37,7 +37,7 @@ public: virtual status_t SubmitTransfer(Transfer *transfer); status_t SubmitPeriodicTransfer(Transfer *transfer); status_t SubmitAsyncTransfer(Transfer *transfer); -virtual status_t CancelQueuedTransfers(Pipe *pipe); +virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force); virtual status_t NotifyPipeChange(Pipe *pipe, usb_change change); diff --git a/src/add-ons/kernel/busses/usb/ohci.cpp b/src/add-ons/kernel/busses/usb/ohci.cpp index f07ace2863..da7b0d7d58 100644 --- a/src/add-ons/kernel/busses/usb/ohci.cpp +++ b/src/add-ons/kernel/busses/usb/ohci.cpp @@ -791,7 +791,7 @@ OHCI::_ReadReg(uint32 reg) status_t -OHCI::CancelQueuedTransfers(Pipe *pipe) +OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) { return B_ERROR; } diff --git a/src/add-ons/kernel/busses/usb/ohci.h b/src/add-ons/kernel/busses/usb/ohci.h index 01d3a17245..6aa14284bb 100644 --- a/src/add-ons/kernel/busses/usb/ohci.h +++ b/src/add-ons/kernel/busses/usb/ohci.h @@ -57,7 +57,8 @@ public: status_t Start(); virtual status_t SubmitTransfer(Transfer *transfer); -virtual status_t CancelQueuedTransfers(Pipe *pipe); +virtual status_t CancelQueuedTransfers(Pipe *pipe, + bool force); status_t SubmitRequest(Transfer *transfer); virtual status_t NotifyPipeChange(Pipe *pipe, diff --git a/src/add-ons/kernel/busses/usb/uhci.cpp b/src/add-ons/kernel/busses/usb/uhci.cpp index 011f72fb28..fcf6207654 100644 --- a/src/add-ons/kernel/busses/usb/uhci.cpp +++ b/src/add-ons/kernel/busses/usb/uhci.cpp @@ -603,7 +603,7 @@ UHCI::SubmitTransfer(Transfer *transfer) status_t -UHCI::CancelQueuedTransfers(Pipe *pipe) +UHCI::CancelQueuedTransfers(Pipe *pipe, bool force) { if (pipe->Type() & USB_OBJECT_ISO_PIPE) return CancelQueuedIsochronousTransfers(pipe); @@ -621,7 +621,13 @@ UHCI::CancelQueuedTransfers(Pipe *pipe) descriptor = (uhci_td *)descriptor->link_log; } - current->transfer->Finished(B_CANCELED, 0); + if (!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); + } + current->canceled = true; } current = current->link; diff --git a/src/add-ons/kernel/busses/usb/uhci.h b/src/add-ons/kernel/busses/usb/uhci.h index e24e857ca7..9225c0a379 100644 --- a/src/add-ons/kernel/busses/usb/uhci.h +++ b/src/add-ons/kernel/busses/usb/uhci.h @@ -91,7 +91,7 @@ public: status_t Start(); virtual status_t SubmitTransfer(Transfer *transfer); -virtual status_t CancelQueuedTransfers(Pipe *pipe); +virtual status_t CancelQueuedTransfers(Pipe *pipe, bool force); status_t CancelQueuedIsochronousTransfers(Pipe *pipe); status_t SubmitRequest(Transfer *transfer); status_t SubmitIsochronous(Transfer *transfer);