diff options
Diffstat (limited to 'drivers/base/bus.c')
-rw-r--r-- | drivers/base/bus.c | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index fa601b085eb..29f6af554e7 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -152,7 +152,11 @@ static ssize_t driver_unbind(struct device_driver *drv, | |||
152 | 152 | ||
153 | dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); | 153 | dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); |
154 | if (dev && dev->driver == drv) { | 154 | if (dev && dev->driver == drv) { |
155 | if (dev->parent) /* Needed for USB */ | ||
156 | down(&dev->parent->sem); | ||
155 | device_release_driver(dev); | 157 | device_release_driver(dev); |
158 | if (dev->parent) | ||
159 | up(&dev->parent->sem); | ||
156 | err = count; | 160 | err = count; |
157 | } | 161 | } |
158 | put_device(dev); | 162 | put_device(dev); |
@@ -175,9 +179,13 @@ static ssize_t driver_bind(struct device_driver *drv, | |||
175 | 179 | ||
176 | dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); | 180 | dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); |
177 | if (dev && dev->driver == NULL) { | 181 | if (dev && dev->driver == NULL) { |
182 | if (dev->parent) /* Needed for USB */ | ||
183 | down(&dev->parent->sem); | ||
178 | down(&dev->sem); | 184 | down(&dev->sem); |
179 | err = driver_probe_device(drv, dev); | 185 | err = driver_probe_device(drv, dev); |
180 | up(&dev->sem); | 186 | up(&dev->sem); |
187 | if (dev->parent) | ||
188 | up(&dev->parent->sem); | ||
181 | } | 189 | } |
182 | put_device(dev); | 190 | put_device(dev); |
183 | put_bus(bus); | 191 | put_bus(bus); |
@@ -420,6 +428,26 @@ static void driver_remove_attrs(struct bus_type * bus, struct device_driver * dr | |||
420 | } | 428 | } |
421 | } | 429 | } |
422 | 430 | ||
431 | #ifdef CONFIG_HOTPLUG | ||
432 | /* | ||
433 | * Thanks to drivers making their tables __devinit, we can't allow manual | ||
434 | * bind and unbind from userspace unless CONFIG_HOTPLUG is enabled. | ||
435 | */ | ||
436 | static void add_bind_files(struct device_driver *drv) | ||
437 | { | ||
438 | driver_create_file(drv, &driver_attr_unbind); | ||
439 | driver_create_file(drv, &driver_attr_bind); | ||
440 | } | ||
441 | |||
442 | static void remove_bind_files(struct device_driver *drv) | ||
443 | { | ||
444 | driver_remove_file(drv, &driver_attr_bind); | ||
445 | driver_remove_file(drv, &driver_attr_unbind); | ||
446 | } | ||
447 | #else | ||
448 | static inline void add_bind_files(struct device_driver *drv) {} | ||
449 | static inline void remove_bind_files(struct device_driver *drv) {} | ||
450 | #endif | ||
423 | 451 | ||
424 | /** | 452 | /** |
425 | * bus_add_driver - Add a driver to the bus. | 453 | * bus_add_driver - Add a driver to the bus. |
@@ -449,8 +477,7 @@ int bus_add_driver(struct device_driver * drv) | |||
449 | module_add_driver(drv->owner, drv); | 477 | module_add_driver(drv->owner, drv); |
450 | 478 | ||
451 | driver_add_attrs(bus, drv); | 479 | driver_add_attrs(bus, drv); |
452 | driver_create_file(drv, &driver_attr_unbind); | 480 | add_bind_files(drv); |
453 | driver_create_file(drv, &driver_attr_bind); | ||
454 | } | 481 | } |
455 | return error; | 482 | return error; |
456 | } | 483 | } |
@@ -468,8 +495,7 @@ int bus_add_driver(struct device_driver * drv) | |||
468 | void bus_remove_driver(struct device_driver * drv) | 495 | void bus_remove_driver(struct device_driver * drv) |
469 | { | 496 | { |
470 | if (drv->bus) { | 497 | if (drv->bus) { |
471 | driver_remove_file(drv, &driver_attr_bind); | 498 | remove_bind_files(drv); |
472 | driver_remove_file(drv, &driver_attr_unbind); | ||
473 | driver_remove_attrs(drv->bus, drv); | 499 | driver_remove_attrs(drv->bus, drv); |
474 | klist_remove(&drv->knode_bus); | 500 | klist_remove(&drv->knode_bus); |
475 | pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); | 501 | pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); |
@@ -484,8 +510,13 @@ void bus_remove_driver(struct device_driver * drv) | |||
484 | /* Helper for bus_rescan_devices's iter */ | 510 | /* Helper for bus_rescan_devices's iter */ |
485 | static int bus_rescan_devices_helper(struct device *dev, void *data) | 511 | static int bus_rescan_devices_helper(struct device *dev, void *data) |
486 | { | 512 | { |
487 | if (!dev->driver) | 513 | if (!dev->driver) { |
514 | if (dev->parent) /* Needed for USB */ | ||
515 | down(&dev->parent->sem); | ||
488 | device_attach(dev); | 516 | device_attach(dev); |
517 | if (dev->parent) | ||
518 | up(&dev->parent->sem); | ||
519 | } | ||
489 | return 0; | 520 | return 0; |
490 | } | 521 | } |
491 | 522 | ||