diff options
Diffstat (limited to 'drivers/base/driver.c')
| -rw-r--r-- | drivers/base/driver.c | 107 |
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); |
