diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/base/driver.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/base/driver.c')
-rw-r--r-- | drivers/base/driver.c | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c new file mode 100644 index 00000000000..3b269f7e521 --- /dev/null +++ b/drivers/base/driver.c @@ -0,0 +1,138 @@ +/* + * driver.c - centralized device driver management + * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * + * This file is released under the GPLv2 + * + */ + +#include <linux/config.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/string.h> +#include "base.h" + +#define to_dev(node) container_of(node, struct device, driver_list) +#define to_drv(obj) container_of(obj, struct device_driver, kobj) + +/** + * driver_create_file - create sysfs file for driver. + * @drv: driver. + * @attr: driver attribute descriptor. + */ + +int driver_create_file(struct device_driver * drv, struct driver_attribute * attr) +{ + int error; + if (get_driver(drv)) { + error = sysfs_create_file(&drv->kobj, &attr->attr); + put_driver(drv); + } else + error = -EINVAL; + return error; +} + + +/** + * driver_remove_file - remove sysfs file for driver. + * @drv: driver. + * @attr: driver attribute descriptor. + */ + +void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr) +{ + if (get_driver(drv)) { + sysfs_remove_file(&drv->kobj, &attr->attr); + put_driver(drv); + } +} + + +/** + * get_driver - increment driver reference count. + * @drv: driver. + */ +struct device_driver * get_driver(struct device_driver * drv) +{ + return drv ? to_drv(kobject_get(&drv->kobj)) : NULL; +} + + +/** + * put_driver - decrement driver's refcount. + * @drv: driver. + */ +void put_driver(struct device_driver * drv) +{ + kobject_put(&drv->kobj); +} + + +/** + * driver_register - register driver with bus + * @drv: driver to register + * + * We pass off most of the work to the bus_add_driver() call, + * since most of the things we have to do deal with the bus + * structures. + * + * The one interesting aspect is that we setup @drv->unloaded + * as a completion that gets complete when the driver reference + * count reaches 0. + */ +int driver_register(struct device_driver * drv) +{ + INIT_LIST_HEAD(&drv->devices); + init_completion(&drv->unloaded); + return bus_add_driver(drv); +} + + +/** + * driver_unregister - remove driver from system. + * @drv: driver. + * + * Again, we pass off most of the work to the bus-level call. + * + * Though, once that is done, we wait until @drv->unloaded is completed. + * This will block until the driver refcount reaches 0, and it is + * released. Only modular drivers will call this function, and we + * have to guarantee that it won't complete, letting the driver + * unload until all references are gone. + */ + +void driver_unregister(struct device_driver * drv) +{ + bus_remove_driver(drv); + wait_for_completion(&drv->unloaded); +} + +/** + * driver_find - locate driver on a bus by its name. + * @name: name of the driver. + * @bus: bus to scan for the driver. + * + * Call kset_find_obj() to iterate over list of drivers on + * a bus to find driver by name. Return driver if found. + * + * Note that kset_find_obj increments driver's reference count. + */ +struct device_driver *driver_find(const char *name, struct bus_type *bus) +{ + struct kobject *k = kset_find_obj(&bus->drivers, name); + if (k) + return to_drv(k); + return NULL; +} + +EXPORT_SYMBOL_GPL(driver_register); +EXPORT_SYMBOL_GPL(driver_unregister); +EXPORT_SYMBOL_GPL(get_driver); +EXPORT_SYMBOL_GPL(put_driver); +EXPORT_SYMBOL_GPL(driver_find); + +EXPORT_SYMBOL_GPL(driver_create_file); +EXPORT_SYMBOL_GPL(driver_remove_file); |