diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/base/base.h | 6 | ||||
| -rw-r--r-- | drivers/base/bus.c | 134 | ||||
| -rw-r--r-- | drivers/base/core.c | 131 | ||||
| -rw-r--r-- | drivers/base/driver.c | 10 |
4 files changed, 136 insertions, 145 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h index 0c05ae058971..a95361aafe3d 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -20,6 +20,9 @@ extern void device_remove_dir(struct device * dev); extern int bus_make_dir(struct bus_type * bus); extern void bus_remove_dir(struct bus_type * bus); +extern int bus_add_driver(struct device_driver *); +extern void bus_remove_driver(struct device_driver *); + extern int driver_make_dir(struct device_driver * drv); extern void driver_remove_dir(struct device_driver * drv); @@ -48,9 +51,6 @@ extern int interface_add(struct device_class *, struct device *); extern void interface_remove(struct device_class *, struct device *); -extern int driver_attach(struct device_driver * drv); -extern void driver_detach(struct device_driver * drv); - #ifdef CONFIG_HOTPLUG extern int dev_hotplug(struct device *dev, const char *action); #else diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 559956c29763..1f3b6471a582 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -94,6 +94,104 @@ int bus_for_each_drv(struct bus_type * bus, void * data, return error; } +static void attach(struct device * dev) +{ + pr_debug("bound device '%s' to driver '%s'\n", + dev->bus_id,dev->driver->name); + list_add_tail(&dev->driver_list,&dev->driver->devices); +} + +static int bus_match(struct device * dev, struct device_driver * drv) +{ + int error = 0; + if (dev->bus->match(dev,drv)) { + dev->driver = drv; + if (drv->probe) { + if (!(error = drv->probe(dev))) + attach(dev); + else + dev->driver = NULL; + } + } + return error; +} + +static int device_attach(struct device * dev) +{ + struct bus_type * bus = dev->bus; + struct list_head * entry; + int error = 0; + + if (dev->driver) { + attach(dev); + return 0; + } + + if (!bus->match) + return 0; + + list_for_each(entry,&bus->drivers) { + struct device_driver * drv = + get_driver(container_of(entry,struct device_driver,bus_list)); + if (!drv) + continue; + error = bus_match(dev,drv); + put_driver(drv); + if (!error) + break; + } + return error; +} + +static int driver_attach(struct device_driver * drv) +{ + struct bus_type * bus = drv->bus; + struct list_head * entry; + int error = 0; + + if (!bus->match) + return 0; + + list_for_each(entry,&bus->devices) { + struct device * dev = container_of(entry,struct device,bus_list); + if (get_device(dev)) { + if (!bus_match(dev,drv) && dev->driver) + devclass_add_device(dev); + put_device(dev); + } + } + return error; +} + +static void detach(struct device * dev, struct device_driver * drv) +{ + if (drv) { + list_del_init(&dev->driver_list); + devclass_remove_device(dev); + if (drv->remove) + drv->remove(dev); + dev->driver = NULL; + } +} + +static void device_detach(struct device * dev) +{ + detach(dev,dev->driver); +} + +static void driver_detach(struct device_driver * drv) +{ + struct list_head * entry; + list_for_each(entry,&drv->devices) { + struct device * dev = container_of(entry,struct device,driver_list); + if (get_device(dev)) { + detach(dev,drv); + put_device(dev); + } + } + +} + /** * bus_add_device - add device to bus * @dev: device being added @@ -105,11 +203,12 @@ int bus_for_each_drv(struct bus_type * bus, void * data, */ int bus_add_device(struct device * dev) { - if (dev->bus) { + struct bus_type * bus = get_bus(dev->bus); + if (bus) { down_write(&dev->bus->rwsem); - pr_debug("registering %s with bus '%s'\n",dev->bus_id,dev->bus->name); - get_bus(dev->bus); + pr_debug("bus %s: add device %s\n",bus->name,dev->bus_id); list_add_tail(&dev->bus_list,&dev->bus->devices); + device_attach(dev); up_write(&dev->bus->rwsem); device_bus_link(dev); } @@ -127,13 +226,40 @@ void bus_remove_device(struct device * dev) { if (dev->bus) { down_write(&dev->bus->rwsem); - list_del_init(&dev->bus_list); + pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id); device_remove_symlink(&dev->bus->device_dir,dev->bus_id); + device_detach(dev); + list_del_init(&dev->bus_list); up_write(&dev->bus->rwsem); put_bus(dev->bus); } } +int bus_add_driver(struct device_driver * drv) +{ + struct bus_type * bus = get_bus(drv->bus); + if (bus) { + down_write(&bus->rwsem); + pr_debug("bus %s: add driver %s\n",bus->name,drv->name); + list_add_tail(&drv->bus_list,&bus->drivers); + driver_attach(drv); + up_write(&bus->rwsem); + driver_make_dir(drv); + } + return 0; +} + +void bus_remove_driver(struct device_driver * drv) +{ + if (drv->bus) { + down_write(&drv->bus->rwsem); + pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name); + driver_detach(drv); + list_del_init(&drv->bus_list); + up_write(&drv->bus->rwsem); + } +} + struct bus_type * get_bus(struct bus_type * bus) { struct bus_type * ret = bus; diff --git a/drivers/base/core.c b/drivers/base/core.c index a1a41f4b0a07..0b7248cf1280 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -23,132 +23,6 @@ spinlock_t device_lock = SPIN_LOCK_UNLOCKED; #define to_dev(node) container_of(node,struct device,driver_list) -static int probe(struct device * dev, struct device_driver * drv) -{ - dev->driver = drv; - return drv->probe ? drv->probe(dev) : 0; -} - -static void attach(struct device * dev) -{ - spin_lock(&device_lock); - list_add_tail(&dev->driver_list,&dev->driver->devices); - spin_unlock(&device_lock); - devclass_add_device(dev); -} - -/** - * found_match - do actual binding of device to driver - * @dev: device - * @drv: driver - * - * We're here because the bus's match callback returned success for this - * pair. We call the driver's probe callback to verify they're really a - * match made in heaven. - * - * In the future, we may want to notify userspace of the binding. (But, - * we might not want to do it here). - * - * We may also want to create a symlink in the driver's directory to the - * device's physical directory. - */ -static int found_match(struct device * dev, struct device_driver * drv) -{ - int error = 0; - - if (!(error = probe(dev,get_driver(drv)))) { - pr_debug("bound device '%s' to driver '%s'\n", - dev->bus_id,drv->name); - attach(dev); - } else { - put_driver(drv); - dev->driver = NULL; - } - return error; -} - -/** - * device_attach - try to associated device with a driver - * @drv: current driver to try - * @data: device in disguise - * - * This function is used as a callback to bus_for_each_drv. - * It calls the bus's match callback to check if the driver supports - * the device. If so, it calls the found_match() function above to - * take care of all the details. - */ -static int do_device_attach(struct device_driver * drv, void * data) -{ - struct device * dev = (struct device *)data; - int error = 0; - - if (drv->bus->match && drv->bus->match(dev,drv)) - error = found_match(dev,drv); - return error; -} - -static int device_attach(struct device * dev) -{ - int error = 0; - if (!dev->driver) { - if (dev->bus) - error = bus_for_each_drv(dev->bus,dev,do_device_attach); - } else - attach(dev); - return error; -} - -static void device_detach(struct device * dev) -{ - struct device_driver * drv = dev->driver; - - if (drv) { - devclass_remove_device(dev); - if (drv && drv->remove) - drv->remove(dev); - dev->driver = NULL; - } -} - -static int do_driver_attach(struct device * dev, void * data) -{ - struct device_driver * drv = (struct device_driver *)data; - int error = 0; - - if (!dev->driver) { - if (dev->bus->match && dev->bus->match(dev,drv)) - error = found_match(dev,drv); - } - return error; -} - -int driver_attach(struct device_driver * drv) -{ - return bus_for_each_dev(drv->bus,drv,do_driver_attach); -} - -void driver_detach(struct device_driver * drv) -{ - struct list_head * node; - struct device * prev = NULL; - - spin_lock(&device_lock); - list_for_each(node,&drv->devices) { - struct device * dev = get_device_locked(to_dev(node)); - if (dev) { - if (prev) - list_del_init(&prev->driver_list); - spin_unlock(&device_lock); - device_detach(dev); - if (prev) - put_device(prev); - prev = dev; - spin_lock(&device_lock); - } - } - spin_unlock(&device_lock); -} - int device_add(struct device *dev) { int error; @@ -173,9 +47,6 @@ int device_add(struct device *dev) bus_add_device(dev); - /* bind to driver */ - device_attach(dev); - /* notify platform of device entry */ if (platform_notify) platform_notify(dev); @@ -183,6 +54,7 @@ int device_add(struct device *dev) /* notify userspace of device entry */ dev_hotplug(dev, "add"); + devclass_add_device(dev); register_done: if (error) { spin_lock(&device_lock); @@ -284,7 +156,6 @@ void device_del(struct device * dev) /* notify userspace that this device is about to disappear */ dev_hotplug (dev, "remove"); - device_detach(dev); bus_remove_device(dev); /* remove the driverfs directory */ diff --git a/drivers/base/driver.c b/drivers/base/driver.c index b19b06201dd5..2c0412400500 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -66,11 +66,9 @@ void put_driver(struct device_driver * drv) struct bus_type * bus = drv->bus; if (!atomic_dec_and_lock(&drv->refcount,&device_lock)) return; - list_del_init(&drv->bus_list); spin_unlock(&device_lock); BUG_ON(drv->present); - driver_detach(drv); - driver_remove_dir(drv); + bus_remove_driver(drv); if (drv->release) drv->release(drv); put_bus(bus); @@ -94,11 +92,7 @@ int driver_register(struct device_driver * drv) rwlock_init(&drv->lock); INIT_LIST_HEAD(&drv->devices); drv->present = 1; - spin_lock(&device_lock); - list_add(&drv->bus_list,&drv->bus->drivers); - spin_unlock(&device_lock); - driver_make_dir(drv); - driver_attach(drv); + bus_add_driver(drv); put_driver(drv); return 0; } |
