diff options
Diffstat (limited to 'drivers/base/bus.c')
-rw-r--r-- | drivers/base/bus.c | 112 |
1 files changed, 96 insertions, 16 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 253868e03c70..1d76e2349654 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #define to_driver(obj) container_of(obj, struct device_driver, kobj) | 27 | #define to_driver(obj) container_of(obj, struct device_driver, kobj) |
28 | 28 | ||
29 | 29 | ||
30 | static int __must_check bus_rescan_devices_helper(struct device *dev, | ||
31 | void *data); | ||
32 | |||
30 | static ssize_t | 33 | static ssize_t |
31 | drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) | 34 | drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) |
32 | { | 35 | { |
@@ -60,8 +63,19 @@ static struct sysfs_ops driver_sysfs_ops = { | |||
60 | 63 | ||
61 | static void driver_release(struct kobject * kobj) | 64 | static void driver_release(struct kobject * kobj) |
62 | { | 65 | { |
63 | struct device_driver * drv = to_driver(kobj); | 66 | /* |
64 | complete(&drv->unloaded); | 67 | * Yes this is an empty release function, it is this way because struct |
68 | * device is always a static object, not a dynamic one. Yes, this is | ||
69 | * not nice and bad, but remember, drivers are code, reference counted | ||
70 | * by the module count, not a device, which is really data. And yes, | ||
71 | * in the future I do want to have all drivers be created dynamically, | ||
72 | * and am working toward that goal, but it will take a bit longer... | ||
73 | * | ||
74 | * But do not let this example give _anyone_ the idea that they can | ||
75 | * create a release function without any code in it at all, to do that | ||
76 | * is almost always wrong. If you have any questions about this, | ||
77 | * please send an email to <greg@kroah.com> | ||
78 | */ | ||
65 | } | 79 | } |
66 | 80 | ||
67 | static struct kobj_type ktype_driver = { | 81 | static struct kobj_type ktype_driver = { |
@@ -133,7 +147,6 @@ static decl_subsys(bus, &ktype_bus, NULL); | |||
133 | 147 | ||
134 | 148 | ||
135 | #ifdef CONFIG_HOTPLUG | 149 | #ifdef CONFIG_HOTPLUG |
136 | |||
137 | /* Manually detach a device from its associated driver. */ | 150 | /* Manually detach a device from its associated driver. */ |
138 | static int driver_helper(struct device *dev, void *data) | 151 | static int driver_helper(struct device *dev, void *data) |
139 | { | 152 | { |
@@ -199,6 +212,33 @@ static ssize_t driver_bind(struct device_driver *drv, | |||
199 | } | 212 | } |
200 | static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); | 213 | static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); |
201 | 214 | ||
215 | static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf) | ||
216 | { | ||
217 | return sprintf(buf, "%d\n", bus->drivers_autoprobe); | ||
218 | } | ||
219 | |||
220 | static ssize_t store_drivers_autoprobe(struct bus_type *bus, | ||
221 | const char *buf, size_t count) | ||
222 | { | ||
223 | if (buf[0] == '0') | ||
224 | bus->drivers_autoprobe = 0; | ||
225 | else | ||
226 | bus->drivers_autoprobe = 1; | ||
227 | return count; | ||
228 | } | ||
229 | |||
230 | static ssize_t store_drivers_probe(struct bus_type *bus, | ||
231 | const char *buf, size_t count) | ||
232 | { | ||
233 | struct device *dev; | ||
234 | |||
235 | dev = bus_find_device(bus, NULL, (void *)buf, driver_helper); | ||
236 | if (!dev) | ||
237 | return -ENODEV; | ||
238 | if (bus_rescan_devices_helper(dev, NULL) != 0) | ||
239 | return -EINVAL; | ||
240 | return count; | ||
241 | } | ||
202 | #endif | 242 | #endif |
203 | 243 | ||
204 | static struct device * next_device(struct klist_iter * i) | 244 | static struct device * next_device(struct klist_iter * i) |
@@ -418,21 +458,21 @@ out_put: | |||
418 | * - Add device to bus's list of devices. | 458 | * - Add device to bus's list of devices. |
419 | * - Try to attach to driver. | 459 | * - Try to attach to driver. |
420 | */ | 460 | */ |
421 | int bus_attach_device(struct device * dev) | 461 | void bus_attach_device(struct device * dev) |
422 | { | 462 | { |
423 | struct bus_type *bus = dev->bus; | 463 | struct bus_type *bus = dev->bus; |
424 | int ret = 0; | 464 | int ret = 0; |
425 | 465 | ||
426 | if (bus) { | 466 | if (bus) { |
427 | dev->is_registered = 1; | 467 | dev->is_registered = 1; |
428 | ret = device_attach(dev); | 468 | if (bus->drivers_autoprobe) |
429 | if (ret >= 0) { | 469 | ret = device_attach(dev); |
470 | WARN_ON(ret < 0); | ||
471 | if (ret >= 0) | ||
430 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); | 472 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); |
431 | ret = 0; | 473 | else |
432 | } else | ||
433 | dev->is_registered = 0; | 474 | dev->is_registered = 0; |
434 | } | 475 | } |
435 | return ret; | ||
436 | } | 476 | } |
437 | 477 | ||
438 | /** | 478 | /** |
@@ -515,9 +555,41 @@ static void remove_bind_files(struct device_driver *drv) | |||
515 | driver_remove_file(drv, &driver_attr_bind); | 555 | driver_remove_file(drv, &driver_attr_bind); |
516 | driver_remove_file(drv, &driver_attr_unbind); | 556 | driver_remove_file(drv, &driver_attr_unbind); |
517 | } | 557 | } |
558 | |||
559 | static int add_probe_files(struct bus_type *bus) | ||
560 | { | ||
561 | int retval; | ||
562 | |||
563 | bus->drivers_probe_attr.attr.name = "drivers_probe"; | ||
564 | bus->drivers_probe_attr.attr.mode = S_IWUSR; | ||
565 | bus->drivers_probe_attr.attr.owner = bus->owner; | ||
566 | bus->drivers_probe_attr.store = store_drivers_probe; | ||
567 | retval = bus_create_file(bus, &bus->drivers_probe_attr); | ||
568 | if (retval) | ||
569 | goto out; | ||
570 | |||
571 | bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; | ||
572 | bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; | ||
573 | bus->drivers_autoprobe_attr.attr.owner = bus->owner; | ||
574 | bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; | ||
575 | bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; | ||
576 | retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); | ||
577 | if (retval) | ||
578 | bus_remove_file(bus, &bus->drivers_probe_attr); | ||
579 | out: | ||
580 | return retval; | ||
581 | } | ||
582 | |||
583 | static void remove_probe_files(struct bus_type *bus) | ||
584 | { | ||
585 | bus_remove_file(bus, &bus->drivers_autoprobe_attr); | ||
586 | bus_remove_file(bus, &bus->drivers_probe_attr); | ||
587 | } | ||
518 | #else | 588 | #else |
519 | static inline int add_bind_files(struct device_driver *drv) { return 0; } | 589 | static inline int add_bind_files(struct device_driver *drv) { return 0; } |
520 | static inline void remove_bind_files(struct device_driver *drv) {} | 590 | static inline void remove_bind_files(struct device_driver *drv) {} |
591 | static inline int add_probe_files(struct bus_type *bus) { return 0; } | ||
592 | static inline void remove_probe_files(struct bus_type *bus) {} | ||
521 | #endif | 593 | #endif |
522 | 594 | ||
523 | /** | 595 | /** |
@@ -531,7 +603,7 @@ int bus_add_driver(struct device_driver *drv) | |||
531 | int error = 0; | 603 | int error = 0; |
532 | 604 | ||
533 | if (!bus) | 605 | if (!bus) |
534 | return 0; | 606 | return -EINVAL; |
535 | 607 | ||
536 | pr_debug("bus %s: add driver %s\n", bus->name, drv->name); | 608 | pr_debug("bus %s: add driver %s\n", bus->name, drv->name); |
537 | error = kobject_set_name(&drv->kobj, "%s", drv->name); | 609 | error = kobject_set_name(&drv->kobj, "%s", drv->name); |
@@ -541,9 +613,11 @@ int bus_add_driver(struct device_driver *drv) | |||
541 | if ((error = kobject_register(&drv->kobj))) | 613 | if ((error = kobject_register(&drv->kobj))) |
542 | goto out_put_bus; | 614 | goto out_put_bus; |
543 | 615 | ||
544 | error = driver_attach(drv); | 616 | if (drv->bus->drivers_autoprobe) { |
545 | if (error) | 617 | error = driver_attach(drv); |
546 | goto out_unregister; | 618 | if (error) |
619 | goto out_unregister; | ||
620 | } | ||
547 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); | 621 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); |
548 | module_add_driver(drv->owner, drv); | 622 | module_add_driver(drv->owner, drv); |
549 | 623 | ||
@@ -605,8 +679,6 @@ static int __must_check bus_rescan_devices_helper(struct device *dev, | |||
605 | ret = device_attach(dev); | 679 | ret = device_attach(dev); |
606 | if (dev->parent) | 680 | if (dev->parent) |
607 | up(&dev->parent->sem); | 681 | up(&dev->parent->sem); |
608 | if (ret > 0) | ||
609 | ret = 0; | ||
610 | } | 682 | } |
611 | return ret < 0 ? ret : 0; | 683 | return ret < 0 ? ret : 0; |
612 | } | 684 | } |
@@ -762,6 +834,12 @@ int bus_register(struct bus_type * bus) | |||
762 | 834 | ||
763 | klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); | 835 | klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); |
764 | klist_init(&bus->klist_drivers, NULL, NULL); | 836 | klist_init(&bus->klist_drivers, NULL, NULL); |
837 | |||
838 | bus->drivers_autoprobe = 1; | ||
839 | retval = add_probe_files(bus); | ||
840 | if (retval) | ||
841 | goto bus_probe_files_fail; | ||
842 | |||
765 | retval = bus_add_attrs(bus); | 843 | retval = bus_add_attrs(bus); |
766 | if (retval) | 844 | if (retval) |
767 | goto bus_attrs_fail; | 845 | goto bus_attrs_fail; |
@@ -770,6 +848,8 @@ int bus_register(struct bus_type * bus) | |||
770 | return 0; | 848 | return 0; |
771 | 849 | ||
772 | bus_attrs_fail: | 850 | bus_attrs_fail: |
851 | remove_probe_files(bus); | ||
852 | bus_probe_files_fail: | ||
773 | kset_unregister(&bus->drivers); | 853 | kset_unregister(&bus->drivers); |
774 | bus_drivers_fail: | 854 | bus_drivers_fail: |
775 | kset_unregister(&bus->devices); | 855 | kset_unregister(&bus->devices); |
@@ -779,7 +859,6 @@ out: | |||
779 | return retval; | 859 | return retval; |
780 | } | 860 | } |
781 | 861 | ||
782 | |||
783 | /** | 862 | /** |
784 | * bus_unregister - remove a bus from the system | 863 | * bus_unregister - remove a bus from the system |
785 | * @bus: bus. | 864 | * @bus: bus. |
@@ -791,6 +870,7 @@ void bus_unregister(struct bus_type * bus) | |||
791 | { | 870 | { |
792 | pr_debug("bus %s: unregistering\n", bus->name); | 871 | pr_debug("bus %s: unregistering\n", bus->name); |
793 | bus_remove_attrs(bus); | 872 | bus_remove_attrs(bus); |
873 | remove_probe_files(bus); | ||
794 | kset_unregister(&bus->drivers); | 874 | kset_unregister(&bus->drivers); |
795 | kset_unregister(&bus->devices); | 875 | kset_unregister(&bus->devices); |
796 | subsystem_unregister(&bus->subsys); | 876 | subsystem_unregister(&bus->subsys); |