summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/base.h6
-rw-r--r--drivers/base/bus.c134
-rw-r--r--drivers/base/core.c131
-rw-r--r--drivers/base/driver.c10
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;
}