int bus_register(struct bus_type * bus)
{
- spin_lock(&device_lock);
rwlock_init(&bus->lock);
INIT_LIST_HEAD(&bus->devices);
INIT_LIST_HEAD(&bus->drivers);
- list_add_tail(&bus->node,&bus_driver_list);
atomic_set(&bus->refcount,2);
+
+ spin_lock(&device_lock);
+ list_add_tail(&bus->node,&bus_driver_list);
spin_unlock(&device_lock);
pr_debug("bus type '%s' registered\n",bus->name);
static void device_detach(struct device * dev)
{
- /* detach from driver */
- if (dev->driver && dev->driver->remove)
- dev->driver->remove(dev);
+ if (dev->driver) {
+ write_lock(&dev->driver->lock);
+ list_del_init(&dev->driver_list);
+ write_unlock(&dev->driver->lock);
+
+ lock_device(dev);
+ dev->driver = NULL;
+ unlock_device(dev);
+
+ /* detach from driver */
+ if (dev->driver->remove)
+ dev->driver->remove(dev);
+ put_driver(dev->driver);
+ }
}
static int do_driver_attach(struct device * dev, void * data)
struct list_head * node;
int error = 0;
- read_lock(&drv->lock);
+ write_lock(&drv->lock);
node = drv->devices.next;
while (node != &drv->devices) {
next = list_entry(node,struct device,driver_list);
get_device(next);
- read_unlock(&drv->lock);
+ list_del_init(&next->driver_list);
+ write_unlock(&drv->lock);
if (dev)
put_device(dev);
put_device(dev);
break;
}
- read_lock(&drv->lock);
- node = dev->driver_list.next;
+ write_lock(&drv->lock);
+ node = drv->devices.next;
}
- read_unlock(&drv->lock);
+ write_unlock(&drv->lock);
if (dev)
put_device(dev);
}
if (!dev || !strlen(dev->bus_id))
return -EINVAL;
- spin_lock(&device_lock);
INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children);
INIT_LIST_HEAD(&dev->g_list);
spin_lock_init(&dev->lock);
atomic_set(&dev->refcount,2);
+ spin_lock(&device_lock);
if (dev != &device_root) {
if (!dev->parent)
dev->parent = &device_root;
static void __remove_driver(struct device_driver * drv)
{
- if (drv->bus) {
- pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
-
- driver_detach(drv);
- write_lock(&drv->bus->lock);
- list_del_init(&drv->bus_list);
- write_unlock(&drv->bus->lock);
-
- driverfs_remove_dir(&drv->dir);
- put_bus(drv->bus);
- }
+ pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
+ driver_detach(drv);
+ driverfs_remove_dir(&drv->dir);
if (drv->release)
drv->release(drv);
+ put_bus(drv->bus);
}
void remove_driver(struct device_driver * drv)
{
- spin_lock(&device_lock);
+ write_lock(&drv->bus->lock);
atomic_set(&drv->refcount,0);
- spin_unlock(&device_lock);
+ list_del_init(&drv->bus_list);
+ write_unlock(&drv->bus->lock);
__remove_driver(drv);
}
*/
void put_driver(struct device_driver * drv)
{
- if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
+ write_lock(&drv->bus->lock);
+ if (!atomic_dec_and_test(&drv->refcount)) {
+ write_unlock(&drv->bus->lock);
return;
- spin_unlock(&device_lock);
-
+ }
+ list_del_init(&drv->bus_list);
+ write_unlock(&drv->bus->lock);
__remove_driver(drv);
}