]> err.no Git - linux-2.6/commitdiff
[PATCH] driver core: Add the ability to unbind drivers to devices from userspace
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 22 Jun 2005 23:09:05 +0000 (16:09 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 30 Jun 2005 05:48:04 +0000 (22:48 -0700)
This adds a single file, "unbind", to the sysfs directory of every
device that is currently bound to a driver.  To unbind the driver from
the device, write anything to this file and they will be disconnected
from each other.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/base/bus.c

index 2c64b792d07466c919d97906b9a2e10214fd7f2e..fa41ee90a53a03b9de7ef95e539759eabcd6fa62 100644 (file)
@@ -133,6 +133,34 @@ static struct kobj_type ktype_bus = {
 decl_subsys(bus, &ktype_bus, NULL);
 
 
+/* Manually detach a device from it's associated driver. */
+static int driver_helper(struct device *dev, void *data)
+{
+       const char *name = data;
+
+       if (strcmp(name, dev->bus_id) == 0)
+               return 1;
+       return 0;
+}
+
+static ssize_t driver_unbind(struct device_driver *drv,
+                            const char *buf, size_t count)
+{
+       struct bus_type *bus = get_bus(drv->bus);
+       struct device *dev;
+       int err = -ENODEV;
+
+       dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+       if ((dev) &&
+           (dev->driver == drv)) {
+               device_release_driver(dev);
+               err = count;
+       }
+       return err;
+}
+static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
+
+
 static struct device * next_device(struct klist_iter * i)
 {
        struct klist_node * n = klist_next(i);
@@ -396,6 +424,7 @@ int bus_add_driver(struct device_driver * drv)
                module_add_driver(drv->owner, drv);
 
                driver_add_attrs(bus, drv);
+               driver_create_file(drv, &driver_attr_unbind);
        }
        return error;
 }
@@ -413,6 +442,7 @@ int bus_add_driver(struct device_driver * drv)
 void bus_remove_driver(struct device_driver * drv)
 {
        if (drv->bus) {
+               driver_remove_file(drv, &driver_attr_unbind);
                driver_remove_attrs(drv->bus, drv);
                klist_remove(&drv->knode_bus);
                pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);