diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 415a02acca..6d47058922 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -106,8 +106,10 @@ Hub::~Hub() continue; TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i])); - GetStack()->NotifyDeviceChange(fChildren[i], false); + rescan_item *rescanList = NULL; + GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false); GetBusManager()->FreeDevice(fChildren[i]); + GetStack()->RescanDrivers(rescanList); } delete fInterruptPipe; @@ -207,6 +209,7 @@ 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,13 +237,15 @@ Hub::Explore() // Remove previous device first TRACE(("USB Hub %d: removing device 0x%08lx\n", DeviceAddress(), fChildren[i])); - GetStack()->NotifyDeviceChange(fChildren[i], false); + 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; @@ -254,7 +259,8 @@ Hub::Explore() if (newDevice && Lock()) { fChildren[i] = newDevice; Unlock(); - GetStack()->NotifyDeviceChange(fChildren[i], true); + GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, true); + GetStack()->RescanDrivers(rescanList); } else { if (newDevice) GetBusManager()->FreeDevice(newDevice); @@ -271,13 +277,15 @@ 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], false); + GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false); if (Lock()) { GetBusManager()->FreeDevice(fChildren[i]); fChildren[i] = NULL; Unlock(); } + + GetStack()->RescanDrivers(rescanList); } } } diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp index 1f7471dfff..37a24518e2 100644 --- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp @@ -26,6 +26,7 @@ Pipe::Pipe(Object *parent, int8 deviceAddress, uint8 endpointAddress, Pipe::~Pipe() { + CancelQueuedTransfers(); GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED); } @@ -308,7 +309,7 @@ ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value, if (actualLength) *actualLength = 0; - // ToDo: cancel the transfer at the bus manager + CancelQueuedTransfers(); 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 3660e6caeb..5e36f7a9cc 100644 --- a/src/add-ons/kernel/bus_managers/usb/Stack.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Stack.cpp @@ -42,6 +42,7 @@ Stack::Stack() if (!fAllocator || fAllocator->InitCheck() < B_OK) { TRACE_ERROR(("USB Stack: failed to allocate the allocator\n")); delete fAllocator; + fAllocator = NULL; return; } @@ -268,7 +269,7 @@ Stack::AllocateArea(void **logicalAddress, void **physicalAddress, size_t size, void -Stack::NotifyDeviceChange(Device *device, bool added) +Stack::NotifyDeviceChange(Device *device, rescan_item **rescanList, bool added) { TRACE(("USB Stack: device %s\n", added ? "added" : "removed")); @@ -279,24 +280,16 @@ Stack::NotifyDeviceChange(Device *device, bool added) &element->cookies, added); if (result >= B_OK) { - // the device is supported by this driver. it either got notified - // already by the hooks or it is not loaded at this time. in any - // case we will rescan the driver so it either is loaded and can - // scan for supported devices or its publish_devices hook will be - // called to expose new devices. - const char *name = element->driver_name; - if (element->republish_driver_name) - name = element->republish_driver_name; + rescan_item *item = new(std::nothrow) rescan_item; + if (!item) + return; -#ifndef HAIKU_TARGET_PLATFORM_HAIKU - // the R5 way to republish a device in devfs - int devFS = open("/dev", O_WRONLY); - write(devFS, name, strlen(name)); - close(devFS); -#else - // use the private devfs API under Haiku - //devfs_rescan_driver(name); -#endif + item->name = element->driver_name; + if (element->republish_driver_name) + item->name = element->republish_driver_name; + + item->link = *rescanList; + *rescanList = item; } element = element->link; @@ -304,6 +297,33 @@ Stack::NotifyDeviceChange(Device *device, bool added) } +void +Stack::RescanDrivers(rescan_item *rescanItem) +{ + while (rescanItem) { + // the device is supported by this driver. it either got notified + // already by the hooks or it is not loaded at this time. in any + // case we will rescan the driver so it either is loaded and can + // scan for supported devices or its publish_devices hook will be + // called to expose changed devices. + +#ifndef HAIKU_TARGET_PLATFORM_HAIKU + // the R5 way to republish a device in devfs + int devFS = open("/dev", O_WRONLY); + write(devFS, rescanItem->name, strlen(rescanItem->name)); + close(devFS); +#else + // use the private devfs API under Haiku + //devfs_rescan_driver(name); +#endif + + rescan_item *next = rescanItem->link; + delete rescanItem; + rescanItem = next; + } +} + + status_t Stack::RegisterDriver(const char *driverName, const usb_support_descriptor *descriptors, 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 d6806f6494..a11ed9912a 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,12 @@ struct usb_driver_info { }; +struct rescan_item { + const char *name; + rescan_item *link; +}; + + typedef enum { USB_SPEED_LOWSPEED = 0, USB_SPEED_FULLSPEED, @@ -113,7 +119,9 @@ public: size_t size, const char *name); void NotifyDeviceChange(Device *device, + rescan_item **rescanList, bool added); + void RescanDrivers(rescan_item *rescanItem); // USB API status_t RegisterDriver(const char *driverName,