Implemented driver unloading. When a driver is rescaned and doesn't publish
any devices anymore it gets unloaded. Also made sure the function pointers are properly initialized and disabled debug output. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23494 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -134,6 +134,8 @@ struct driver_entry {
|
|||||||
int32 *api_version;
|
int32 *api_version;
|
||||||
device_hooks *(*find_device)(const char *);
|
device_hooks *(*find_device)(const char *);
|
||||||
const char **(*publish_devices)(void);
|
const char **(*publish_devices)(void);
|
||||||
|
status_t (*uninit_driver)(void);
|
||||||
|
status_t (*uninit_hardware)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -256,13 +258,18 @@ load_driver(driver_entry *driver)
|
|||||||
goto error2;
|
goto error2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolve and cache those for the driver unload code
|
||||||
|
if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT,
|
||||||
|
(void **)&driver->uninit_driver) != B_OK)
|
||||||
|
driver->uninit_driver = NULL;
|
||||||
|
if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT,
|
||||||
|
(void **)&driver->uninit_hardware) != B_OK)
|
||||||
|
driver->uninit_hardware = NULL;
|
||||||
|
|
||||||
// The driver has successfully been initialized, now we can
|
// The driver has successfully been initialized, now we can
|
||||||
// finally publish its device entries
|
// finally publish its device entries
|
||||||
|
|
||||||
// we keep the driver loaded if it exports at least a single interface
|
// we keep the driver loaded if it exports at least a single interface
|
||||||
// ToDo: we could/should always unload drivers until they will be used for real
|
|
||||||
// ToDo: this function is probably better kept in devfs, so that it could remember
|
|
||||||
// the driver stuff (and even keep it loaded if there is enough memory)
|
|
||||||
devicePaths = driver->publish_devices();
|
devicePaths = driver->publish_devices();
|
||||||
if (devicePaths == NULL) {
|
if (devicePaths == NULL) {
|
||||||
dprintf("%s: publish_devices() returned NULL.\n", name);
|
dprintf("%s: publish_devices() returned NULL.\n", name);
|
||||||
@@ -279,7 +286,7 @@ load_driver(driver_entry *driver)
|
|||||||
exported++;
|
exported++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we're all done, driver will be kept loaded (for now, see above comment)
|
// we're all done, driver will be kept loaded
|
||||||
if (exported > 0) {
|
if (exported > 0) {
|
||||||
driver->image = image;
|
driver->image = image;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -288,20 +295,12 @@ load_driver(driver_entry *driver)
|
|||||||
status = B_ERROR; // whatever...
|
status = B_ERROR; // whatever...
|
||||||
|
|
||||||
error3:
|
error3:
|
||||||
{
|
if (driver->uninit_driver)
|
||||||
status_t (*uninit_driver)(void);
|
driver->uninit_driver();
|
||||||
if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT,
|
|
||||||
(void **)&uninit_driver) == B_OK)
|
|
||||||
uninit_driver();
|
|
||||||
}
|
|
||||||
|
|
||||||
error2:
|
error2:
|
||||||
{
|
if (driver->uninit_hardware)
|
||||||
status_t (*uninit_hardware)(void);
|
driver->uninit_hardware();
|
||||||
if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT,
|
|
||||||
(void **)&uninit_hardware) == B_OK)
|
|
||||||
uninit_hardware();
|
|
||||||
}
|
|
||||||
|
|
||||||
error1:
|
error1:
|
||||||
if (driver->image < 0) {
|
if (driver->image < 0) {
|
||||||
@@ -313,7 +312,27 @@ error1:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
|
unload_driver(driver_entry *driver)
|
||||||
|
{
|
||||||
|
if (driver->image < 0) {
|
||||||
|
// driver is not currently loaded
|
||||||
|
return B_NO_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (driver->uninit_driver)
|
||||||
|
driver->uninit_driver();
|
||||||
|
|
||||||
|
if (driver->uninit_hardware)
|
||||||
|
driver->uninit_hardware();
|
||||||
|
|
||||||
|
unload_kernel_add_on(driver->image);
|
||||||
|
driver->image = -1;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
add_driver(const char *path, image_id image)
|
add_driver(const char *path, image_id image)
|
||||||
{
|
{
|
||||||
// see if we already know this driver
|
// see if we already know this driver
|
||||||
@@ -361,6 +380,12 @@ add_driver(const char *path, image_id image)
|
|||||||
driver->image = image;
|
driver->image = image;
|
||||||
driver->last_modified = stat.st_mtime;
|
driver->last_modified = stat.st_mtime;
|
||||||
|
|
||||||
|
driver->api_version = NULL;
|
||||||
|
driver->find_device = NULL;
|
||||||
|
driver->publish_devices = NULL;
|
||||||
|
driver->uninit_driver = NULL;
|
||||||
|
driver->uninit_hardware = NULL;
|
||||||
|
|
||||||
hash_insert(sDeviceFileSystem->driver_hash, driver);
|
hash_insert(sDeviceFileSystem->driver_hash, driver);
|
||||||
|
|
||||||
// Even if loading the driver fails - its entry will stay with us
|
// Even if loading the driver fails - its entry will stay with us
|
||||||
@@ -1059,7 +1084,7 @@ republish_driver(driver_entry *driver)
|
|||||||
if (hooks == NULL)
|
if (hooks == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dprintf("devfs: publishing new device \"%s\"\n", devicePaths[0]);
|
TRACE(("devfs: publishing new device \"%s\"\n", devicePaths[0]));
|
||||||
if (publish_device(sDeviceFileSystem, devicePaths[0], NULL, NULL,
|
if (publish_device(sDeviceFileSystem, devicePaths[0], NULL, NULL,
|
||||||
driver, hooks, *driver->api_version) == B_OK)
|
driver, hooks, *driver->api_version) == B_OK)
|
||||||
exported++;
|
exported++;
|
||||||
@@ -1068,7 +1093,7 @@ republish_driver(driver_entry *driver)
|
|||||||
// what's left in currentNodes was present but is not anymore -> unpublish
|
// what's left in currentNodes was present but is not anymore -> unpublish
|
||||||
node_path_entry *entry = currentNodes.Head();
|
node_path_entry *entry = currentNodes.Head();
|
||||||
while (entry) {
|
while (entry) {
|
||||||
dprintf("devfs: unpublishing no more present \"%s\"\n", entry->path);
|
TRACE(("devfs: unpublishing no more present \"%s\"\n", entry->path));
|
||||||
devfs_unpublish_device(entry->path, true);
|
devfs_unpublish_device(entry->path, true);
|
||||||
node_path_entry *next = currentNodes.GetNext(entry);
|
node_path_entry *next = currentNodes.GetNext(entry);
|
||||||
currentNodes.Remove(entry);
|
currentNodes.Remove(entry);
|
||||||
@@ -1077,8 +1102,8 @@ republish_driver(driver_entry *driver)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (exported == 0) {
|
if (exported == 0) {
|
||||||
dprintf("devfs: driver \"%s\" does not publish any more nodes and could be unloaded\n", driver->path);
|
TRACE(("devfs: driver \"%s\" does not publish any more nodes and is unloaded\n", driver->path));
|
||||||
// ToDo: here we could unload the driver if it doesn't publish anything
|
unload_driver(driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|||||||
Reference in New Issue
Block a user