diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-22 19:09:05 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-30 01:48:04 -0400 |
commit | 151ef38f7c0ec1b0420f04438b0316e3a30bf2e4 (patch) | |
tree | 3aa6504e12c08f70cacb7f9de6ef5858b45ee86d /drivers/base/bus.c | |
parent | 0edb586049e57c56e625536476931117a57671e9 (diff) |
[PATCH] driver core: Add the ability to unbind drivers to devices from userspace
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>
Diffstat (limited to 'drivers/base/bus.c')
-rw-r--r-- | drivers/base/bus.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2c64b792d074..fa41ee90a53a 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -133,6 +133,34 @@ static struct kobj_type ktype_bus = { | |||
133 | decl_subsys(bus, &ktype_bus, NULL); | 133 | decl_subsys(bus, &ktype_bus, NULL); |
134 | 134 | ||
135 | 135 | ||
136 | /* Manually detach a device from it's associated driver. */ | ||
137 | static int driver_helper(struct device *dev, void *data) | ||
138 | { | ||
139 | const char *name = data; | ||
140 | |||
141 | if (strcmp(name, dev->bus_id) == 0) | ||
142 | return 1; | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static ssize_t driver_unbind(struct device_driver *drv, | ||
147 | const char *buf, size_t count) | ||
148 | { | ||
149 | struct bus_type *bus = get_bus(drv->bus); | ||
150 | struct device *dev; | ||
151 | int err = -ENODEV; | ||
152 | |||
153 | dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); | ||
154 | if ((dev) && | ||
155 | (dev->driver == drv)) { | ||
156 | device_release_driver(dev); | ||
157 | err = count; | ||
158 | } | ||
159 | return err; | ||
160 | } | ||
161 | static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); | ||
162 | |||
163 | |||
136 | static struct device * next_device(struct klist_iter * i) | 164 | static struct device * next_device(struct klist_iter * i) |
137 | { | 165 | { |
138 | struct klist_node * n = klist_next(i); | 166 | struct klist_node * n = klist_next(i); |
@@ -396,6 +424,7 @@ int bus_add_driver(struct device_driver * drv) | |||
396 | module_add_driver(drv->owner, drv); | 424 | module_add_driver(drv->owner, drv); |
397 | 425 | ||
398 | driver_add_attrs(bus, drv); | 426 | driver_add_attrs(bus, drv); |
427 | driver_create_file(drv, &driver_attr_unbind); | ||
399 | } | 428 | } |
400 | return error; | 429 | return error; |
401 | } | 430 | } |
@@ -413,6 +442,7 @@ int bus_add_driver(struct device_driver * drv) | |||
413 | void bus_remove_driver(struct device_driver * drv) | 442 | void bus_remove_driver(struct device_driver * drv) |
414 | { | 443 | { |
415 | if (drv->bus) { | 444 | if (drv->bus) { |
445 | driver_remove_file(drv, &driver_attr_unbind); | ||
416 | driver_remove_attrs(drv->bus, drv); | 446 | driver_remove_attrs(drv->bus, drv); |
417 | klist_remove(&drv->knode_bus); | 447 | klist_remove(&drv->knode_bus); |
418 | pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); | 448 | pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); |