Change the way notify hooks and rescans are handeled. The rescans are now delayed to after all notify hooks are called (like in BeOS).

This also ensures that the rescans do not happen while the devices are not yet added or already removed.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21905 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2007-08-12 12:04:41 +00:00
parent 154860eb4b
commit d2e77702cb
4 changed files with 60 additions and 23 deletions
+12 -4
View File
@@ -106,8 +106,10 @@ Hub::~Hub()
continue; continue;
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], false); rescan_item *rescanList = NULL;
GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false);
GetBusManager()->FreeDevice(fChildren[i]); GetBusManager()->FreeDevice(fChildren[i]);
GetStack()->RescanDrivers(rescanList);
} }
delete fInterruptPipe; delete fInterruptPipe;
@@ -207,6 +209,7 @@ 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,13 +237,15 @@ Hub::Explore()
// Remove previous device first // Remove previous device first
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], false); GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false);
if (Lock()) { if (Lock()) {
GetBusManager()->FreeDevice(fChildren[i]); GetBusManager()->FreeDevice(fChildren[i]);
fChildren[i] = NULL; fChildren[i] = NULL;
Unlock(); Unlock();
} }
GetStack()->RescanDrivers(rescanList);
} }
usb_speed speed = USB_SPEED_FULLSPEED; usb_speed speed = USB_SPEED_FULLSPEED;
@@ -254,7 +259,8 @@ Hub::Explore()
if (newDevice && Lock()) { if (newDevice && Lock()) {
fChildren[i] = newDevice; fChildren[i] = newDevice;
Unlock(); Unlock();
GetStack()->NotifyDeviceChange(fChildren[i], true); GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, true);
GetStack()->RescanDrivers(rescanList);
} else { } else {
if (newDevice) if (newDevice)
GetBusManager()->FreeDevice(newDevice); GetBusManager()->FreeDevice(newDevice);
@@ -271,13 +277,15 @@ 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], false); GetStack()->NotifyDeviceChange(fChildren[i], &rescanList, false);
if (Lock()) { if (Lock()) {
GetBusManager()->FreeDevice(fChildren[i]); GetBusManager()->FreeDevice(fChildren[i]);
fChildren[i] = NULL; fChildren[i] = NULL;
Unlock(); Unlock();
} }
GetStack()->RescanDrivers(rescanList);
} }
} }
} }
+2 -1
View File
@@ -26,6 +26,7 @@ Pipe::Pipe(Object *parent, int8 deviceAddress, uint8 endpointAddress,
Pipe::~Pipe() Pipe::~Pipe()
{ {
CancelQueuedTransfers();
GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED); GetBusManager()->NotifyPipeChange(this, USB_CHANGE_DESTROYED);
} }
@@ -308,7 +309,7 @@ ControlPipe::SendRequest(uint8 requestType, uint8 request, uint16 value,
if (actualLength) if (actualLength)
*actualLength = 0; *actualLength = 0;
// ToDo: cancel the transfer at the bus manager CancelQueuedTransfers();
return B_TIMED_OUT; return B_TIMED_OUT;
} }
+38 -18
View File
@@ -42,6 +42,7 @@ Stack::Stack()
if (!fAllocator || fAllocator->InitCheck() < B_OK) { if (!fAllocator || fAllocator->InitCheck() < B_OK) {
TRACE_ERROR(("USB Stack: failed to allocate the allocator\n")); TRACE_ERROR(("USB Stack: failed to allocate the allocator\n"));
delete fAllocator; delete fAllocator;
fAllocator = NULL;
return; return;
} }
@@ -268,7 +269,7 @@ Stack::AllocateArea(void **logicalAddress, void **physicalAddress, size_t size,
void 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")); TRACE(("USB Stack: device %s\n", added ? "added" : "removed"));
@@ -279,24 +280,16 @@ Stack::NotifyDeviceChange(Device *device, bool added)
&element->cookies, added); &element->cookies, added);
if (result >= B_OK) { if (result >= B_OK) {
// the device is supported by this driver. it either got notified rescan_item *item = new(std::nothrow) rescan_item;
// already by the hooks or it is not loaded at this time. in any if (!item)
// case we will rescan the driver so it either is loaded and can return;
// 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;
#ifndef HAIKU_TARGET_PLATFORM_HAIKU item->name = element->driver_name;
// the R5 way to republish a device in devfs if (element->republish_driver_name)
int devFS = open("/dev", O_WRONLY); item->name = element->republish_driver_name;
write(devFS, name, strlen(name));
close(devFS); item->link = *rescanList;
#else *rescanList = item;
// use the private devfs API under Haiku
//devfs_rescan_driver(name);
#endif
} }
element = element->link; 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 status_t
Stack::RegisterDriver(const char *driverName, Stack::RegisterDriver(const char *driverName,
const usb_support_descriptor *descriptors, const usb_support_descriptor *descriptors,
@@ -60,6 +60,12 @@ struct usb_driver_info {
}; };
struct rescan_item {
const char *name;
rescan_item *link;
};
typedef enum { typedef enum {
USB_SPEED_LOWSPEED = 0, USB_SPEED_LOWSPEED = 0,
USB_SPEED_FULLSPEED, USB_SPEED_FULLSPEED,
@@ -113,7 +119,9 @@ public:
size_t size, const char *name); size_t size, const char *name);
void NotifyDeviceChange(Device *device, void NotifyDeviceChange(Device *device,
rescan_item **rescanList,
bool added); bool added);
void RescanDrivers(rescan_item *rescanItem);
// USB API // USB API
status_t RegisterDriver(const char *driverName, status_t RegisterDriver(const char *driverName,