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:
Michael Lotz
2008-01-13 18:49:39 +00:00
parent 3be509a228
commit bece4ef7ab
+46 -21
View File
@@ -134,6 +134,8 @@ struct driver_entry {
int32 *api_version;
device_hooks *(*find_device)(const char *);
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;
}
// 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
// finally publish its device entries
// 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();
if (devicePaths == NULL) {
dprintf("%s: publish_devices() returned NULL.\n", name);
@@ -279,7 +286,7 @@ load_driver(driver_entry *driver)
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) {
driver->image = image;
return B_OK;
@@ -288,20 +295,12 @@ load_driver(driver_entry *driver)
status = B_ERROR; // whatever...
error3:
{
status_t (*uninit_driver)(void);
if (get_image_symbol(image, "uninit_driver", B_SYMBOL_TYPE_TEXT,
(void **)&uninit_driver) == B_OK)
uninit_driver();
}
if (driver->uninit_driver)
driver->uninit_driver();
error2:
{
status_t (*uninit_hardware)(void);
if (get_image_symbol(image, "uninit_hardware", B_SYMBOL_TYPE_TEXT,
(void **)&uninit_hardware) == B_OK)
uninit_hardware();
}
if (driver->uninit_hardware)
driver->uninit_hardware();
error1:
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)
{
// see if we already know this driver
@@ -361,6 +380,12 @@ add_driver(const char *path, image_id image)
driver->image = image;
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);
// Even if loading the driver fails - its entry will stay with us
@@ -1059,7 +1084,7 @@ republish_driver(driver_entry *driver)
if (hooks == NULL)
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,
driver, hooks, *driver->api_version) == B_OK)
exported++;
@@ -1068,7 +1093,7 @@ republish_driver(driver_entry *driver)
// what's left in currentNodes was present but is not anymore -> unpublish
node_path_entry *entry = currentNodes.Head();
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);
node_path_entry *next = currentNodes.GetNext(entry);
currentNodes.Remove(entry);
@@ -1077,8 +1102,8 @@ republish_driver(driver_entry *driver)
}
if (exported == 0) {
dprintf("devfs: driver \"%s\" does not publish any more nodes and could be unloaded\n", driver->path);
// ToDo: here we could unload the driver if it doesn't publish anything
TRACE(("devfs: driver \"%s\" does not publish any more nodes and is unloaded\n", driver->path));
unload_driver(driver);
}
return B_OK;