* Properly implement rescan in devfs (rescan when closed and republish when open)
* Cache the looked up image symbols as well as the API version in the driver entry git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23441 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
7f27c6c3c8
commit
1d99d469a0
@ -129,6 +129,16 @@ struct driver_entry {
|
||||
ino_t node;
|
||||
time_t last_modified;
|
||||
image_id image;
|
||||
|
||||
// driver image information
|
||||
int32 *api_version;
|
||||
device_hooks *(*find_device)(const char *);
|
||||
const char **(*publish_devices)(void);
|
||||
};
|
||||
|
||||
|
||||
struct node_path_entry : DoublyLinkedListLinkImpl<node_path_entry> {
|
||||
char path[B_PATH_NAME_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
@ -141,6 +151,7 @@ static status_t publish_device(struct devfs *fs, const char *path,
|
||||
|
||||
/* the one and only allowed devfs instance */
|
||||
static struct devfs *sDeviceFileSystem = NULL;
|
||||
static int32 sDefaultApiVersion = 1;
|
||||
|
||||
|
||||
// #pragma mark - driver private
|
||||
@ -198,20 +209,19 @@ load_driver(driver_entry *driver)
|
||||
|
||||
// For a valid device driver the following exports are required
|
||||
|
||||
int32 defaultApiVersion = 1;
|
||||
int32 *apiVersion = &defaultApiVersion;
|
||||
driver->api_version = &sDefaultApiVersion;
|
||||
if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA,
|
||||
(void **)&apiVersion) == B_OK) {
|
||||
(void **)&driver->api_version) == B_OK) {
|
||||
#if B_CUR_DRIVER_API_VERSION != 2
|
||||
// just in case someone decides to bump up the api version
|
||||
#error Add checks here for new vs old api version!
|
||||
#endif
|
||||
if (*apiVersion > B_CUR_DRIVER_API_VERSION) {
|
||||
dprintf("%s: api_version %ld not handled\n", name, *apiVersion);
|
||||
if (*driver->api_version > B_CUR_DRIVER_API_VERSION) {
|
||||
dprintf("%s: api_version %ld not handled\n", name, *driver->api_version);
|
||||
status = B_BAD_VALUE;
|
||||
goto error1;
|
||||
}
|
||||
if (*apiVersion < 1) {
|
||||
if (*driver->api_version < 1) {
|
||||
dprintf("%s: api_version invalid\n", name);
|
||||
status = B_BAD_VALUE;
|
||||
goto error1;
|
||||
@ -219,12 +229,10 @@ load_driver(driver_entry *driver)
|
||||
} else
|
||||
dprintf("%s: api_version missing\n", name);
|
||||
|
||||
device_hooks *(*find_device)(const char *);
|
||||
const char **(*publish_devices)(void);
|
||||
if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT,
|
||||
(void **)&publish_devices) != B_OK
|
||||
(void **)&driver->publish_devices) != B_OK
|
||||
|| get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT,
|
||||
(void **)&find_device) != B_OK) {
|
||||
(void **)&driver->find_device) != B_OK) {
|
||||
dprintf("%s: mandatory driver symbol(s) missing!\n", name);
|
||||
status = B_BAD_VALUE;
|
||||
goto error1;
|
||||
@ -255,7 +263,7 @@ load_driver(driver_entry *driver)
|
||||
// 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 = publish_devices();
|
||||
devicePaths = driver->publish_devices();
|
||||
if (devicePaths == NULL) {
|
||||
dprintf("%s: publish_devices() returned NULL.\n", name);
|
||||
status = ENXIO;
|
||||
@ -263,11 +271,11 @@ load_driver(driver_entry *driver)
|
||||
}
|
||||
|
||||
for (; devicePaths[0]; devicePaths++) {
|
||||
device_hooks *hooks = find_device(devicePaths[0]);
|
||||
device_hooks *hooks = driver->find_device(devicePaths[0]);
|
||||
|
||||
if (hooks != NULL
|
||||
&& publish_device(sDeviceFileSystem, devicePaths[0],
|
||||
NULL, NULL, driver, hooks, *apiVersion) == B_OK)
|
||||
NULL, NULL, driver, hooks, *driver->api_version) == B_OK)
|
||||
exported++;
|
||||
}
|
||||
|
||||
@ -980,6 +988,103 @@ publish_device(struct devfs *fs, const char *path, device_node_info *deviceNode,
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
republish_driver(driver_entry *driver)
|
||||
{
|
||||
if (driver->image < 0)
|
||||
return B_NO_INIT;
|
||||
|
||||
RecursiveLocker locker(&sDeviceFileSystem->lock);
|
||||
|
||||
// build the list of currently present devices by iterating through all
|
||||
// present nodes
|
||||
struct hash_iterator i;
|
||||
hash_open(sDeviceFileSystem->vnode_hash, &i);
|
||||
|
||||
devfs_vnode *vnode = (devfs_vnode *)hash_next(
|
||||
sDeviceFileSystem->vnode_hash, &i);
|
||||
|
||||
DoublyLinkedList<node_path_entry> currentNodes;
|
||||
while (vnode) {
|
||||
if (S_ISCHR(vnode->stream.type)) {
|
||||
if (vnode->stream.u.dev.driver == driver) {
|
||||
node_path_entry *path = new(std::nothrow) node_path_entry;
|
||||
if (!path) {
|
||||
while ((path = currentNodes.RemoveHead()))
|
||||
delete path;
|
||||
hash_close(sDeviceFileSystem->vnode_hash, &i, false);
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
get_device_name(vnode, path->path, sizeof(path->path));
|
||||
currentNodes.Add(path);
|
||||
}
|
||||
}
|
||||
|
||||
vnode = (devfs_vnode *)hash_next(sDeviceFileSystem->vnode_hash, &i);
|
||||
}
|
||||
hash_close(sDeviceFileSystem->vnode_hash, &i, false);
|
||||
|
||||
// now ask the driver for it's currently published devices
|
||||
const char **devicePaths = driver->publish_devices();
|
||||
if (devicePaths == NULL) {
|
||||
node_path_entry *entry = NULL;
|
||||
while ((entry = currentNodes.RemoveHead()))
|
||||
delete entry;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
int32 exported = 0;
|
||||
for (; devicePaths[0]; devicePaths++) {
|
||||
bool present = false;
|
||||
node_path_entry *entry = currentNodes.Head();
|
||||
while (entry) {
|
||||
if (strncmp(entry->path, devicePaths[0], B_PATH_NAME_LENGTH) == 0) {
|
||||
// this device was present before and still is -> no republish
|
||||
currentNodes.Remove(entry);
|
||||
delete entry;
|
||||
exported++;
|
||||
present = true;
|
||||
break;
|
||||
}
|
||||
|
||||
entry = currentNodes.GetNext(entry);
|
||||
}
|
||||
|
||||
if (present)
|
||||
continue;
|
||||
|
||||
// the device was not present before -> publish it now
|
||||
device_hooks *hooks = driver->find_device(devicePaths[0]);
|
||||
if (hooks == NULL)
|
||||
continue;
|
||||
|
||||
dprintf("devfs: publishing new device \"%s\"\n", devicePaths[0]);
|
||||
if (publish_device(sDeviceFileSystem, devicePaths[0], NULL, NULL,
|
||||
driver, hooks, *driver->api_version) == B_OK)
|
||||
exported++;
|
||||
}
|
||||
|
||||
// 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);
|
||||
devfs_unpublish_device(entry->path, true);
|
||||
node_path_entry *next = currentNodes.GetNext(entry);
|
||||
currentNodes.Remove(entry);
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/** Construct complete device name (as used for device_open()).
|
||||
* This is safe to use only when the device is in use (and therefore
|
||||
* cannot be unpublished during the iteration).
|
||||
@ -2455,6 +2560,7 @@ devfs_unpublish_device(const char *path, bool disconnect)
|
||||
if (status == B_OK && disconnect)
|
||||
vfs_disconnect_vnode(sDeviceFileSystem->id, node->id);
|
||||
|
||||
remove_vnode(sDeviceFileSystem->id, node->id);
|
||||
put_vnode(sDeviceFileSystem->id, node->id);
|
||||
return status;
|
||||
}
|
||||
@ -2482,6 +2588,8 @@ devfs_rescan_driver(const char *driverName)
|
||||
{
|
||||
TRACE(("devfs_rescan_driver: %s\n", driverName));
|
||||
|
||||
RecursiveLocker locker(&sDeviceFileSystem->lock);
|
||||
|
||||
// iterate over the drivers and search a matching driverName
|
||||
struct hash_iterator i;
|
||||
hash_open(sDeviceFileSystem->driver_hash, &i);
|
||||
@ -2497,8 +2605,13 @@ devfs_rescan_driver(const char *driverName)
|
||||
|
||||
if (!strcmp(name, driverName)) {
|
||||
hash_close(sDeviceFileSystem->driver_hash, &i, false);
|
||||
// ToDo: force a uninit/init cycle on the driver if loaded
|
||||
return load_driver(driver);
|
||||
if (driver->image < 0) {
|
||||
// The driver is not yet loaded
|
||||
return load_driver(driver);
|
||||
} else {
|
||||
// The driver is loaded, just republish its entries
|
||||
return republish_driver(driver);
|
||||
}
|
||||
}
|
||||
|
||||
driver = (driver_entry *)hash_next(sDeviceFileSystem->driver_hash, &i);
|
||||
|
Loading…
x
Reference in New Issue
Block a user