driver core: add root_device_register()
Add support for allocating root device objects which group device objects under /sys/devices directories. Also add a sysfs 'module' symlink which points to the owner of the root device object. This symlink will be used in virtio to allow userspace to determine which virtio bus implementation a given device is associated with. [Includes suggestions from Cornelia Huck] Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
7232800ba8
commit
0aa0dc41bf
@@ -1217,6 +1217,97 @@ EXPORT_SYMBOL_GPL(put_device);
|
|||||||
EXPORT_SYMBOL_GPL(device_create_file);
|
EXPORT_SYMBOL_GPL(device_create_file);
|
||||||
EXPORT_SYMBOL_GPL(device_remove_file);
|
EXPORT_SYMBOL_GPL(device_remove_file);
|
||||||
|
|
||||||
|
struct root_device
|
||||||
|
{
|
||||||
|
struct device dev;
|
||||||
|
struct module *owner;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define to_root_device(dev) container_of(dev, struct root_device, dev)
|
||||||
|
|
||||||
|
static void root_device_release(struct device *dev)
|
||||||
|
{
|
||||||
|
kfree(to_root_device(dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __root_device_register - allocate and register a root device
|
||||||
|
* @name: root device name
|
||||||
|
* @owner: owner module of the root device, usually THIS_MODULE
|
||||||
|
*
|
||||||
|
* This function allocates a root device and registers it
|
||||||
|
* using device_register(). In order to free the returned
|
||||||
|
* device, use root_device_unregister().
|
||||||
|
*
|
||||||
|
* Root devices are dummy devices which allow other devices
|
||||||
|
* to be grouped under /sys/devices. Use this function to
|
||||||
|
* allocate a root device and then use it as the parent of
|
||||||
|
* any device which should appear under /sys/devices/{name}
|
||||||
|
*
|
||||||
|
* The /sys/devices/{name} directory will also contain a
|
||||||
|
* 'module' symlink which points to the @owner directory
|
||||||
|
* in sysfs.
|
||||||
|
*
|
||||||
|
* Note: You probably want to use root_device_register().
|
||||||
|
*/
|
||||||
|
struct device *__root_device_register(const char *name, struct module *owner)
|
||||||
|
{
|
||||||
|
struct root_device *root;
|
||||||
|
int err = -ENOMEM;
|
||||||
|
|
||||||
|
root = kzalloc(sizeof(struct root_device), GFP_KERNEL);
|
||||||
|
if (!root)
|
||||||
|
return ERR_PTR(err);
|
||||||
|
|
||||||
|
err = dev_set_name(&root->dev, name);
|
||||||
|
if (err) {
|
||||||
|
kfree(root);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
root->dev.release = root_device_release;
|
||||||
|
|
||||||
|
err = device_register(&root->dev);
|
||||||
|
if (err) {
|
||||||
|
put_device(&root->dev);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MODULE /* gotta find a "cleaner" way to do this */
|
||||||
|
if (owner) {
|
||||||
|
struct module_kobject *mk = &owner->mkobj;
|
||||||
|
|
||||||
|
err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module");
|
||||||
|
if (err) {
|
||||||
|
device_unregister(&root->dev);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
root->owner = owner;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return &root->dev;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(__root_device_register);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* root_device_unregister - unregister and free a root device
|
||||||
|
* @root: device going away.
|
||||||
|
*
|
||||||
|
* This function unregisters and cleans up a device that was created by
|
||||||
|
* root_device_register().
|
||||||
|
*/
|
||||||
|
void root_device_unregister(struct device *dev)
|
||||||
|
{
|
||||||
|
struct root_device *root = to_root_device(dev);
|
||||||
|
|
||||||
|
if (root->owner)
|
||||||
|
sysfs_remove_link(&root->dev.kobj, "module");
|
||||||
|
|
||||||
|
device_unregister(dev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(root_device_unregister);
|
||||||
|
|
||||||
|
|
||||||
static void device_create_release(struct device *dev)
|
static void device_create_release(struct device *dev)
|
||||||
{
|
{
|
||||||
|
@@ -482,6 +482,17 @@ extern struct device *device_find_child(struct device *dev, void *data,
|
|||||||
extern int device_rename(struct device *dev, char *new_name);
|
extern int device_rename(struct device *dev, char *new_name);
|
||||||
extern int device_move(struct device *dev, struct device *new_parent);
|
extern int device_move(struct device *dev, struct device *new_parent);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Root device objects for grouping under /sys/devices
|
||||||
|
*/
|
||||||
|
extern struct device *__root_device_register(const char *name,
|
||||||
|
struct module *owner);
|
||||||
|
static inline struct device *root_device_register(const char *name)
|
||||||
|
{
|
||||||
|
return __root_device_register(name, THIS_MODULE);
|
||||||
|
}
|
||||||
|
extern void root_device_unregister(struct device *root);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Manual binding of a device to driver. See drivers/base/bus.c
|
* Manual binding of a device to driver. See drivers/base/bus.c
|
||||||
* for information on use.
|
* for information on use.
|
||||||
|
Reference in New Issue
Block a user