summaryrefslogtreecommitdiff
path: root/drivers/base/driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/driver.c')
-rw-r--r--drivers/base/driver.c107
1 files changed, 57 insertions, 50 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 221e525736bd..4bf4a005b918 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -16,29 +16,61 @@ int driver_for_each_dev(struct device_driver * drv, void * data,
int (*callback)(struct device *, void * ))
{
struct list_head * node;
- struct device * prev = NULL;
int error = 0;
- get_driver(drv);
- spin_lock(&device_lock);
- list_for_each(node,&drv->devices) {
- struct device * dev = get_device_locked(to_dev(node));
- if (dev) {
- spin_unlock(&device_lock);
- error = callback(dev,data);
- if (prev)
- put_device(prev);
- prev = dev;
- spin_lock(&device_lock);
- if (error)
- break;
+ drv = get_driver(drv);
+ if (drv) {
+ down_read(&drv->bus->rwsem);
+ list_for_each(node,&drv->devices) {
+ struct device * dev = get_device(to_dev(node));
+ if (dev) {
+ error = callback(dev,data);
+ put_device(dev);
+ if (error)
+ break;
+ }
}
+ up_read(&drv->bus->rwsem);
+ put_driver(drv);
}
- spin_unlock(&device_lock);
- put_driver(drv);
return error;
}
+struct device_driver * get_driver(struct device_driver * drv)
+{
+ struct device_driver * ret = drv;
+ spin_lock(&device_lock);
+ if (drv && drv->present && atomic_read(&drv->refcount) > 0)
+ atomic_inc(&drv->refcount);
+ else
+ ret = NULL;
+ spin_unlock(&device_lock);
+ return ret;
+}
+
+
+void remove_driver(struct device_driver * drv)
+{
+ BUG();
+}
+
+/**
+ * put_driver - decrement driver's refcount and clean up if necessary
+ * @drv: driver in question
+ */
+void put_driver(struct device_driver * drv)
+{
+ struct bus_type * bus = drv->bus;
+ if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
+ return;
+ spin_unlock(&device_lock);
+ BUG_ON(drv->present);
+ bus_remove_driver(drv);
+ if (drv->release)
+ drv->release(drv);
+ put_bus(bus);
+}
+
/**
* driver_register - register driver with bus
* @drv: driver to register
@@ -50,54 +82,29 @@ int driver_register(struct device_driver * drv)
if (!drv->bus)
return -EINVAL;
- pr_debug("Registering driver '%s' with bus '%s'\n",drv->name,drv->bus->name);
+ pr_debug("driver %s:%s: registering\n",drv->bus->name,drv->name);
get_bus(drv->bus);
atomic_set(&drv->refcount,2);
rwlock_init(&drv->lock);
INIT_LIST_HEAD(&drv->devices);
- spin_lock(&device_lock);
- list_add(&drv->bus_list,&drv->bus->drivers);
- spin_unlock(&device_lock);
- driver_make_dir(drv);
- driver_attach(drv);
+ drv->present = 1;
+ bus_add_driver(drv);
put_driver(drv);
return 0;
}
-static void __remove_driver(struct device_driver * drv)
-{
- pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
- driver_detach(drv);
- driver_remove_dir(drv);
- if (drv->release)
- drv->release(drv);
- put_bus(drv->bus);
-}
-
-void remove_driver(struct device_driver * drv)
+void driver_unregister(struct device_driver * drv)
{
spin_lock(&device_lock);
- atomic_set(&drv->refcount,0);
- list_del_init(&drv->bus_list);
+ drv->present = 0;
spin_unlock(&device_lock);
- __remove_driver(drv);
-}
-
-/**
- * put_driver - decrement driver's refcount and clean up if necessary
- * @drv: driver in question
- */
-void put_driver(struct device_driver * drv)
-{
- if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
- return;
- list_del_init(&drv->bus_list);
- spin_unlock(&device_lock);
- __remove_driver(drv);
+ pr_debug("driver %s:%s: unregistering\n",drv->bus->name,drv->name);
+ put_driver(drv);
}
EXPORT_SYMBOL(driver_for_each_dev);
EXPORT_SYMBOL(driver_register);
+EXPORT_SYMBOL(driver_unregister);
+EXPORT_SYMBOL(get_driver);
EXPORT_SYMBOL(put_driver);
-EXPORT_SYMBOL(remove_driver);