Completely redesign the USB explore process. Replaces the scary race conditions of the previous locking mechanism and simplifies handling of device changes by a more centralized approach.

Changes are now collected during explore and notifications as well as rescans are done at once. Through this a driver is also not rescanned multiple times anymore.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22929 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2007-11-14 22:11:05 +00:00
parent d3625d72ed
commit 13508e8bd0
13 changed files with 174 additions and 110 deletions

View File

@ -269,7 +269,7 @@ BusManager::SubmitTransfer(Transfer *transfer)
status_t status_t
BusManager::CancelQueuedTransfers(Pipe *pipe) BusManager::CancelQueuedTransfers(Pipe *pipe, bool force)
{ {
// virtual function to be overridden // virtual function to be overridden
return B_ERROR; return B_ERROR;

View File

@ -15,6 +15,7 @@ Device::Device(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
: Object(parent), : Object(parent),
fDeviceDescriptor(desc), fDeviceDescriptor(desc),
fInitOK(false), fInitOK(false),
fAvailable(true),
fConfigurations(NULL), fConfigurations(NULL),
fCurrentConfiguration(NULL), fCurrentConfiguration(NULL),
fSpeed(speed), 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 status_t
Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID, Device::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
void *data, size_t dataLength, size_t *actualLength) void *data, size_t dataLength, size_t *actualLength)
{ {
if (!fAvailable)
return B_ERROR;
return fDefaultPipe->SendRequest( return fDefaultPipe->SendRequest(
USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD, // type
USB_REQUEST_GET_DESCRIPTOR, // request USB_REQUEST_GET_DESCRIPTOR, // request
@ -304,6 +324,8 @@ Device::SetConfiguration(const usb_configuration_info *configuration)
status_t status_t
Device::SetConfigurationAt(uint8 index) Device::SetConfigurationAt(uint8 index)
{ {
if (!fAvailable)
return B_ERROR;
if (index >= fDeviceDescriptor.num_configurations) if (index >= fDeviceDescriptor.num_configurations)
return B_BAD_VALUE; return B_BAD_VALUE;
if (&fConfigurations[index] == fCurrentConfiguration) if (&fConfigurations[index] == fCurrentConfiguration)
@ -382,7 +404,7 @@ Device::Unconfigure(bool atDeviceLevel)
// another configuration unconfigure will be called with // another configuration unconfigure will be called with
// atDevice = false. otherwise we explicitly want to unconfigure // atDevice = false. otherwise we explicitly want to unconfigure
// the device and have to send it the corresponding request. // the device and have to send it the corresponding request.
if (atDeviceLevel) { if (atDeviceLevel && fAvailable) {
status_t result = fDefaultPipe->SendRequest( status_t result = fDefaultPipe->SendRequest(
USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD, // type
USB_REQUEST_SET_CONFIGURATION, // request USB_REQUEST_SET_CONFIGURATION, // request
@ -426,7 +448,7 @@ Device::DeviceDescriptor() const
status_t status_t
Device::ReportDevice(usb_support_descriptor *supportDescriptors, Device::ReportDevice(usb_support_descriptor *supportDescriptors,
uint32 supportDescriptorCount, const usb_notify_hooks *hooks, 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)); TRACE(("USB Device %d: reporting device\n", fDeviceAddress));
bool supported = false; bool supported = false;
@ -526,6 +548,9 @@ Device::BuildDeviceName(char *string, uint32 *index, size_t bufferSize,
status_t status_t
Device::SetFeature(uint16 selector) Device::SetFeature(uint16 selector)
{ {
if (!fAvailable)
return B_ERROR;
return fDefaultPipe->SendRequest( return fDefaultPipe->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
USB_REQUEST_SET_FEATURE, USB_REQUEST_SET_FEATURE,
@ -541,6 +566,9 @@ Device::SetFeature(uint16 selector)
status_t status_t
Device::ClearFeature(uint16 selector) Device::ClearFeature(uint16 selector)
{ {
if (!fAvailable)
return B_ERROR;
return fDefaultPipe->SendRequest( return fDefaultPipe->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT, USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_OUT,
USB_REQUEST_CLEAR_FEATURE, USB_REQUEST_CLEAR_FEATURE,
@ -556,6 +584,9 @@ Device::ClearFeature(uint16 selector)
status_t status_t
Device::GetStatus(uint16 *status) Device::GetStatus(uint16 *status)
{ {
if (!fAvailable)
return B_ERROR;
return fDefaultPipe->SendRequest( return fDefaultPipe->SendRequest(
USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_IN, USB_REQTYPE_STANDARD | USB_REQTYPE_DEVICE_IN,
USB_REQUEST_GET_STATUS, USB_REQUEST_GET_STATUS,

View File

@ -30,11 +30,6 @@ Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
// Set to false again for the hub init. // Set to false again for the hub init.
fInitOK = false; 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) { if (fDeviceDescriptor.device_class != 9) {
TRACE_ERROR(("USB Hub %d: wrong class! bailing out\n", DeviceAddress())); TRACE_ERROR(("USB Hub %d: wrong class! bailing out\n", DeviceAddress()));
return; return;
@ -97,36 +92,26 @@ Hub::Hub(Object *parent, usb_device_descriptor &desc, int8 deviceAddress,
Hub::~Hub() 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; delete fInterruptPipe;
} }
bool status_t
Hub::Lock() 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 fChildren[i]->Changed(changeList, false);
Hub::Unlock() fChildren[i] = NULL;
{ }
benaphore_unlock(&fLock);
return B_OK;
} }
@ -189,7 +174,7 @@ Hub::ResetPort(uint8 index)
void void
Hub::Explore() Hub::Explore(change_item **changeList)
{ {
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
status_t result = UpdatePortStatus(i); status_t result = UpdatePortStatus(i);
@ -209,7 +194,6 @@ Hub::Explore()
USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1, USB_REQUEST_CLEAR_FEATURE, C_PORT_CONNECTION, i + 1,
0, NULL, 0, NULL); 0, NULL, 0, NULL);
rescan_item *rescanList = NULL;
if (fPortStatus[i].status & PORT_STATUS_CONNECTION) { if (fPortStatus[i].status & PORT_STATUS_CONNECTION) {
// new device attached! // new device attached!
TRACE(("USB Hub %d: new device connected\n", DeviceAddress())); TRACE(("USB Hub %d: new device connected\n", DeviceAddress()));
@ -234,18 +218,8 @@ Hub::Explore()
if (fChildren[i]) { if (fChildren[i]) {
TRACE_ERROR(("USB Hub %d: new device on a port that is already in use\n", DeviceAddress())); TRACE_ERROR(("USB Hub %d: new device on a port that is already in use\n", DeviceAddress()));
fChildren[i]->Changed(changeList, false);
// Remove previous device first fChildren[i] = NULL;
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);
} }
usb_speed speed = USB_SPEED_FULLSPEED; usb_speed speed = USB_SPEED_FULLSPEED;
@ -256,15 +230,10 @@ Hub::Explore()
Device *newDevice = GetBusManager()->AllocateDevice(this, speed); Device *newDevice = GetBusManager()->AllocateDevice(this, speed);
if (newDevice && Lock()) { if (newDevice) {
newDevice->Changed(changeList, true);
fChildren[i] = newDevice; fChildren[i] = newDevice;
Unlock();
GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, true);
GetStack()->RescanDrivers(rescanList);
} else { } else {
if (newDevice)
GetBusManager()->FreeDevice(newDevice);
// the device failed to setup correctly, disable the port // the device failed to setup correctly, disable the port
// so that the device doesn't get in the way of future // so that the device doesn't get in the way of future
// addressing. // addressing.
@ -277,15 +246,8 @@ Hub::Explore()
TRACE(("USB Hub %d: device removed\n", DeviceAddress())); TRACE(("USB Hub %d: device removed\n", DeviceAddress()));
if (fChildren[i]) { if (fChildren[i]) {
TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i])); TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i]));
GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false); fChildren[i]->Changed(changeList, false);
fChildren[i] = NULL;
if (Lock()) {
GetBusManager()->FreeDevice(fChildren[i]);
fChildren[i] = NULL;
Unlock();
}
GetStack()->RescanDrivers(rescanList);
} }
} }
} }
@ -325,7 +287,7 @@ Hub::Explore()
if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0) if (!fChildren[i] || (fChildren[i]->Type() & USB_OBJECT_HUB) == 0)
continue; continue;
((Hub *)fChildren[i])->Explore(); ((Hub *)fChildren[i])->Explore(changeList);
} }
} }
@ -357,28 +319,26 @@ Hub::GetDescriptor(uint8 descriptorType, uint8 index, uint16 languageID,
status_t status_t
Hub::ReportDevice(usb_support_descriptor *supportDescriptors, Hub::ReportDevice(usb_support_descriptor *supportDescriptors,
uint32 supportDescriptorCount, const usb_notify_hooks *hooks, 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())); TRACE(("USB Hub %d: reporting hub\n", DeviceAddress()));
// Report ourselfs first // Report ourselfs first
status_t result = Device::ReportDevice(supportDescriptors, status_t result = Device::ReportDevice(supportDescriptors,
supportDescriptorCount, hooks, cookies, added); supportDescriptorCount, hooks, cookies, added, recursive);
// Then report all of our children if (!recursive)
if (!Lock()) return result;
return B_ERROR;
for (int32 i = 0; i < fHubDescriptor.num_ports; i++) { for (int32 i = 0; i < fHubDescriptor.num_ports; i++) {
if (!fChildren[i]) if (!fChildren[i])
continue; continue;
if (fChildren[i]->ReportDevice(supportDescriptors, if (fChildren[i]->ReportDevice(supportDescriptors,
supportDescriptorCount, hooks, cookies, added) == B_OK) supportDescriptorCount, hooks, cookies, added, true) == B_OK)
result = B_OK; result = B_OK;
} }
Unlock();
return result; return result;
} }

View File

@ -26,7 +26,7 @@ Pipe::Pipe(Object *parent, int8 deviceAddress, uint8 endpointAddress,
Pipe::~Pipe() Pipe::~Pipe()
{ {
CancelQueuedTransfers(); CancelQueuedTransfers(true);
GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED); GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED);
} }
@ -40,9 +40,9 @@ Pipe::SubmitTransfer(Transfer *transfer)
status_t 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) if (actualLength)
*actualLength = 0; *actualLength = 0;
CancelQueuedTransfers(); CancelQueuedTransfers(false);
return B_TIMED_OUT; return B_TIMED_OUT;
} }

View File

@ -28,8 +28,13 @@ Stack::Stack()
{ {
TRACE(("USB Stack: stack init\n")); TRACE(("USB Stack: stack init\n"));
if (benaphore_init(&fLock, "usb stack lock") < B_OK) { if (benaphore_init(&fStackLock, "usb stack lock") < B_OK) {
TRACE_ERROR(("USB Stack: failed to create benaphore lock\n")); 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; return;
} }
@ -85,8 +90,10 @@ Stack::~Stack()
fStopThreads = true; fStopThreads = true;
wait_for_thread(fExploreThread, &result); wait_for_thread(fExploreThread, &result);
Lock(); benaphore_lock(&fStackLock);
benaphore_destroy(&fLock); benaphore_destroy(&fStackLock);
benaphore_lock(&fExploreLock);
benaphore_destroy(&fExploreLock);
//Release the bus modules //Release the bus modules
for (Vector<BusManager *>::Iterator i = fBusManagers.Begin(); for (Vector<BusManager *>::Iterator i = fBusManagers.Begin();
@ -111,14 +118,14 @@ Stack::InitCheck()
bool bool
Stack::Lock() Stack::Lock()
{ {
return (benaphore_lock(&fLock) == B_OK); return (benaphore_lock(&fStackLock) == B_OK);
} }
void void
Stack::Unlock() Stack::Unlock()
{ {
benaphore_unlock(&fLock); benaphore_unlock(&fStackLock);
} }
@ -189,13 +196,33 @@ Stack::ExploreThread(void *data)
Stack *stack = (Stack *)data; Stack *stack = (Stack *)data;
while (!stack->fStopThreads) { 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++) { for (int32 i = 0; i < stack->fBusManagers.Count(); i++) {
Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub(); Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub();
if (rootHub) 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; stack->fFirstExploreDone = true;
benaphore_unlock(&stack->fExploreLock);
stack->RescanDrivers(rescanList);
snooze(USB_DELAY_HUB_EXPLORE); snooze(USB_DELAY_HUB_EXPLORE);
} }
@ -277,19 +304,33 @@ Stack::NotifyDeviceChange(Device *device, rescan_item **rescanList, bool added)
while (element) { while (element) {
status_t result = device->ReportDevice(element->support_descriptors, status_t result = device->ReportDevice(element->support_descriptors,
element->support_descriptor_count, &element->notify_hooks, element->support_descriptor_count, &element->notify_hooks,
&element->cookies, added); &element->cookies, added, false);
if (result >= B_OK) { if (result >= B_OK) {
rescan_item *item = new(std::nothrow) rescan_item; const char *driverName = element->driver_name;
if (!item)
return;
item->name = element->driver_name;
if (element->republish_driver_name) if (element->republish_driver_name)
item->name = element->republish_driver_name; driverName = element->republish_driver_name;
item->link = *rescanList; bool already = false;
*rescanList = item; 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; element = element->link;
@ -403,6 +444,9 @@ Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks)
usb_driver_info *element = fDriverList; usb_driver_info *element = fDriverList;
while (element) { while (element) {
if (strcmp(element->driver_name, driverName) == 0) { if (strcmp(element->driver_name, driverName) == 0) {
if (benaphore_lock(&fExploreLock) != B_OK)
return B_ERROR;
// inform driver about any already present devices // inform driver about any already present devices
for (int32 i = 0; i < fBusManagers.Count(); i++) { for (int32 i = 0; i < fBusManagers.Count(); i++) {
Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); 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 // Report device will recurse down the whole tree
rootHub->ReportDevice(element->support_descriptors, rootHub->ReportDevice(element->support_descriptors,
element->support_descriptor_count, hooks, element->support_descriptor_count, hooks,
&element->cookies, true); &element->cookies, true, true);
} }
} }
element->notify_hooks.device_added = hooks->device_added; element->notify_hooks.device_added = hooks->device_added;
element->notify_hooks.device_removed = hooks->device_removed; element->notify_hooks.device_removed = hooks->device_removed;
benaphore_unlock(&fExploreLock);
return B_OK; return B_OK;
} }
@ -434,17 +479,21 @@ Stack::UninstallNotify(const char *driverName)
usb_driver_info *element = fDriverList; usb_driver_info *element = fDriverList;
while (element) { while (element) {
if (strcmp(element->driver_name, driverName) == 0) { if (strcmp(element->driver_name, driverName) == 0) {
if (benaphore_lock(&fExploreLock) != B_OK)
return B_ERROR;
// trigger the device removed hook // trigger the device removed hook
for (int32 i = 0; i < fBusManagers.Count(); i++) { for (int32 i = 0; i < fBusManagers.Count(); i++) {
Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub(); Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
if (rootHub) if (rootHub)
rootHub->ReportDevice(element->support_descriptors, rootHub->ReportDevice(element->support_descriptors,
element->support_descriptor_count, 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_added = NULL;
element->notify_hooks.device_removed = NULL; element->notify_hooks.device_removed = NULL;
benaphore_unlock(&fExploreLock);
return B_OK; return B_OK;
} }

View File

@ -318,7 +318,7 @@ cancel_queued_transfers(usb_pipe pipe)
if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) if (!object || (object->Type() & USB_OBJECT_PIPE) == 0)
return B_DEV_INVALID_PIPE; return B_DEV_INVALID_PIPE;
return ((Pipe *)object)->CancelQueuedTransfers(); return ((Pipe *)object)->CancelQueuedTransfers(false);
} }

View File

@ -60,6 +60,13 @@ struct usb_driver_info {
}; };
struct change_item {
bool added;
Device *device;
change_item *link;
};
struct rescan_item { struct rescan_item {
const char *name; const char *name;
rescan_item *link; rescan_item *link;
@ -141,7 +148,8 @@ static int32 ExploreThread(void *data);
bool fFirstExploreDone; bool fFirstExploreDone;
bool fStopThreads; bool fStopThreads;
benaphore fLock; benaphore fStackLock;
benaphore fExploreLock;
PhysicalMemoryAllocator *fAllocator; PhysicalMemoryAllocator *fAllocator;
uint32 fObjectIndex; uint32 fObjectIndex;
@ -178,7 +186,8 @@ virtual status_t Start();
virtual status_t Stop(); virtual status_t Stop();
virtual status_t SubmitTransfer(Transfer *transfer); 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, virtual status_t NotifyPipeChange(Pipe *pipe,
usb_change change); usb_change change);
@ -260,7 +269,7 @@ virtual bool DataToggle() { return fDataToggle; };
virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; }; virtual void SetDataToggle(bool toggle) { fDataToggle = toggle; };
status_t SubmitTransfer(Transfer *transfer); status_t SubmitTransfer(Transfer *transfer);
status_t CancelQueuedTransfers(); status_t CancelQueuedTransfers(bool force);
// Convenience functions for standard requests // Convenience functions for standard requests
virtual status_t SetFeature(uint16 selector); virtual status_t SetFeature(uint16 selector);
@ -414,6 +423,9 @@ virtual ~Device();
status_t InitCheck(); status_t InitCheck();
virtual status_t Changed(change_item **changeList,
bool added);
virtual uint32 Type() { return USB_OBJECT_DEVICE; }; virtual uint32 Type() { return USB_OBJECT_DEVICE; };
ControlPipe *DefaultPipe() { return fDefaultPipe; }; ControlPipe *DefaultPipe() { return fDefaultPipe; };
@ -437,7 +449,7 @@ virtual status_t ReportDevice(
uint32 supportDescriptorCount, uint32 supportDescriptorCount,
const usb_notify_hooks *hooks, const usb_notify_hooks *hooks,
usb_driver_cookie **cookies, usb_driver_cookie **cookies,
bool added); bool added, bool recursive);
virtual status_t BuildDeviceName(char *string, virtual status_t BuildDeviceName(char *string,
uint32 *index, size_t bufferSize, uint32 *index, size_t bufferSize,
Device *device); Device *device);
@ -452,6 +464,7 @@ protected:
bool fInitOK; bool fInitOK;
private: private:
bool fAvailable;
usb_configuration_info *fConfigurations; usb_configuration_info *fConfigurations;
usb_configuration_info *fCurrentConfiguration; usb_configuration_info *fCurrentConfiguration;
usb_speed fSpeed; usb_speed fSpeed;
@ -468,8 +481,8 @@ public:
usb_speed speed); usb_speed speed);
virtual ~Hub(); virtual ~Hub();
bool Lock(); virtual status_t Changed(change_item **changeList,
void Unlock(); bool added);
virtual uint32 Type() { return USB_OBJECT_DEVICE | USB_OBJECT_HUB; }; 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 UpdatePortStatus(uint8 index);
status_t ResetPort(uint8 index); status_t ResetPort(uint8 index);
void Explore(); void Explore(change_item **changeList);
static void InterruptCallback(void *cookie, static void InterruptCallback(void *cookie,
status_t status, void *data, status_t status, void *data,
size_t actualLength); size_t actualLength);
@ -490,14 +503,12 @@ virtual status_t ReportDevice(
uint32 supportDescriptorCount, uint32 supportDescriptorCount,
const usb_notify_hooks *hooks, const usb_notify_hooks *hooks,
usb_driver_cookie **cookies, usb_driver_cookie **cookies,
bool added); bool added, bool recursive);
virtual status_t BuildDeviceName(char *string, virtual status_t BuildDeviceName(char *string,
uint32 *index, size_t bufferSize, uint32 *index, size_t bufferSize,
Device *device); Device *device);
private: private:
benaphore fLock;
InterruptPipe *fInterruptPipe; InterruptPipe *fInterruptPipe;
usb_hub_descriptor fHubDescriptor; usb_hub_descriptor fHubDescriptor;

View File

@ -864,7 +864,7 @@ EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
status_t status_t
EHCI::CancelQueuedTransfers(Pipe *pipe) EHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
{ {
if (!Lock()) if (!Lock())
return B_ERROR; return B_ERROR;
@ -879,7 +879,13 @@ EHCI::CancelQueuedTransfers(Pipe *pipe)
descriptor = (ehci_qtd *)descriptor->next_log; 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; current->canceled = true;
} }

View File

@ -37,7 +37,7 @@ public:
virtual status_t SubmitTransfer(Transfer *transfer); virtual status_t SubmitTransfer(Transfer *transfer);
status_t SubmitPeriodicTransfer(Transfer *transfer); status_t SubmitPeriodicTransfer(Transfer *transfer);
status_t SubmitAsyncTransfer(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, virtual status_t NotifyPipeChange(Pipe *pipe,
usb_change change); usb_change change);

View File

@ -791,7 +791,7 @@ OHCI::_ReadReg(uint32 reg)
status_t status_t
OHCI::CancelQueuedTransfers(Pipe *pipe) OHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
{ {
return B_ERROR; return B_ERROR;
} }

View File

@ -57,7 +57,8 @@ public:
status_t Start(); status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer); 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); status_t SubmitRequest(Transfer *transfer);
virtual status_t NotifyPipeChange(Pipe *pipe, virtual status_t NotifyPipeChange(Pipe *pipe,

View File

@ -603,7 +603,7 @@ UHCI::SubmitTransfer(Transfer *transfer)
status_t status_t
UHCI::CancelQueuedTransfers(Pipe *pipe) UHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
{ {
if (pipe->Type() & USB_OBJECT_ISO_PIPE) if (pipe->Type() & USB_OBJECT_ISO_PIPE)
return CancelQueuedIsochronousTransfers(pipe); return CancelQueuedIsochronousTransfers(pipe);
@ -621,7 +621,13 @@ UHCI::CancelQueuedTransfers(Pipe *pipe)
descriptor = (uhci_td *)descriptor->link_log; 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->canceled = true;
} }
current = current->link; current = current->link;

View File

@ -91,7 +91,7 @@ public:
status_t Start(); status_t Start();
virtual status_t SubmitTransfer(Transfer *transfer); 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 CancelQueuedIsochronousTransfers(Pipe *pipe);
status_t SubmitRequest(Transfer *transfer); status_t SubmitRequest(Transfer *transfer);
status_t SubmitIsochronous(Transfer *transfer); status_t SubmitIsochronous(Transfer *transfer);