diff options
Diffstat (limited to 'drivers/base/bus.c')
-rw-r--r-- | drivers/base/bus.c | 116 |
1 files changed, 74 insertions, 42 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 61c67526a656..9a19b071c573 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -30,6 +30,17 @@ | |||
30 | static int __must_check bus_rescan_devices_helper(struct device *dev, | 30 | static int __must_check bus_rescan_devices_helper(struct device *dev, |
31 | void *data); | 31 | void *data); |
32 | 32 | ||
33 | static struct bus_type *bus_get(struct bus_type *bus) | ||
34 | { | ||
35 | return bus ? container_of(kset_get(&bus->subsys), | ||
36 | struct bus_type, subsys) : NULL; | ||
37 | } | ||
38 | |||
39 | static void bus_put(struct bus_type *bus) | ||
40 | { | ||
41 | kset_put(&bus->subsys); | ||
42 | } | ||
43 | |||
33 | static ssize_t | 44 | static ssize_t |
34 | drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) | 45 | drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) |
35 | { | 46 | { |
@@ -78,7 +89,7 @@ static void driver_release(struct kobject * kobj) | |||
78 | */ | 89 | */ |
79 | } | 90 | } |
80 | 91 | ||
81 | static struct kobj_type ktype_driver = { | 92 | static struct kobj_type driver_ktype = { |
82 | .sysfs_ops = &driver_sysfs_ops, | 93 | .sysfs_ops = &driver_sysfs_ops, |
83 | .release = driver_release, | 94 | .release = driver_release, |
84 | }; | 95 | }; |
@@ -122,9 +133,9 @@ static struct sysfs_ops bus_sysfs_ops = { | |||
122 | int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) | 133 | int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) |
123 | { | 134 | { |
124 | int error; | 135 | int error; |
125 | if (get_bus(bus)) { | 136 | if (bus_get(bus)) { |
126 | error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); | 137 | error = sysfs_create_file(&bus->subsys.kobj, &attr->attr); |
127 | put_bus(bus); | 138 | bus_put(bus); |
128 | } else | 139 | } else |
129 | error = -EINVAL; | 140 | error = -EINVAL; |
130 | return error; | 141 | return error; |
@@ -132,9 +143,9 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr) | |||
132 | 143 | ||
133 | void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) | 144 | void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr) |
134 | { | 145 | { |
135 | if (get_bus(bus)) { | 146 | if (bus_get(bus)) { |
136 | sysfs_remove_file(&bus->subsys.kobj, &attr->attr); | 147 | sysfs_remove_file(&bus->subsys.kobj, &attr->attr); |
137 | put_bus(bus); | 148 | bus_put(bus); |
138 | } | 149 | } |
139 | } | 150 | } |
140 | 151 | ||
@@ -172,7 +183,7 @@ static int driver_helper(struct device *dev, void *data) | |||
172 | static ssize_t driver_unbind(struct device_driver *drv, | 183 | static ssize_t driver_unbind(struct device_driver *drv, |
173 | const char *buf, size_t count) | 184 | const char *buf, size_t count) |
174 | { | 185 | { |
175 | struct bus_type *bus = get_bus(drv->bus); | 186 | struct bus_type *bus = bus_get(drv->bus); |
176 | struct device *dev; | 187 | struct device *dev; |
177 | int err = -ENODEV; | 188 | int err = -ENODEV; |
178 | 189 | ||
@@ -186,7 +197,7 @@ static ssize_t driver_unbind(struct device_driver *drv, | |||
186 | err = count; | 197 | err = count; |
187 | } | 198 | } |
188 | put_device(dev); | 199 | put_device(dev); |
189 | put_bus(bus); | 200 | bus_put(bus); |
190 | return err; | 201 | return err; |
191 | } | 202 | } |
192 | static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); | 203 | static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); |
@@ -199,7 +210,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind); | |||
199 | static ssize_t driver_bind(struct device_driver *drv, | 210 | static ssize_t driver_bind(struct device_driver *drv, |
200 | const char *buf, size_t count) | 211 | const char *buf, size_t count) |
201 | { | 212 | { |
202 | struct bus_type *bus = get_bus(drv->bus); | 213 | struct bus_type *bus = bus_get(drv->bus); |
203 | struct device *dev; | 214 | struct device *dev; |
204 | int err = -ENODEV; | 215 | int err = -ENODEV; |
205 | 216 | ||
@@ -219,7 +230,7 @@ static ssize_t driver_bind(struct device_driver *drv, | |||
219 | err = -ENODEV; | 230 | err = -ENODEV; |
220 | } | 231 | } |
221 | put_device(dev); | 232 | put_device(dev); |
222 | put_bus(bus); | 233 | bus_put(bus); |
223 | return err; | 234 | return err; |
224 | } | 235 | } |
225 | static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); | 236 | static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind); |
@@ -430,7 +441,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } | |||
430 | */ | 441 | */ |
431 | int bus_add_device(struct device * dev) | 442 | int bus_add_device(struct device * dev) |
432 | { | 443 | { |
433 | struct bus_type * bus = get_bus(dev->bus); | 444 | struct bus_type * bus = bus_get(dev->bus); |
434 | int error = 0; | 445 | int error = 0; |
435 | 446 | ||
436 | if (bus) { | 447 | if (bus) { |
@@ -459,7 +470,7 @@ out_subsys: | |||
459 | out_id: | 470 | out_id: |
460 | device_remove_attrs(bus, dev); | 471 | device_remove_attrs(bus, dev); |
461 | out_put: | 472 | out_put: |
462 | put_bus(dev->bus); | 473 | bus_put(dev->bus); |
463 | return error; | 474 | return error; |
464 | } | 475 | } |
465 | 476 | ||
@@ -509,7 +520,7 @@ void bus_remove_device(struct device * dev) | |||
509 | } | 520 | } |
510 | pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); | 521 | pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); |
511 | device_release_driver(dev); | 522 | device_release_driver(dev); |
512 | put_bus(dev->bus); | 523 | bus_put(dev->bus); |
513 | } | 524 | } |
514 | } | 525 | } |
515 | 526 | ||
@@ -568,32 +579,29 @@ static void remove_bind_files(struct device_driver *drv) | |||
568 | driver_remove_file(drv, &driver_attr_unbind); | 579 | driver_remove_file(drv, &driver_attr_unbind); |
569 | } | 580 | } |
570 | 581 | ||
582 | static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); | ||
583 | static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, | ||
584 | show_drivers_autoprobe, store_drivers_autoprobe); | ||
585 | |||
571 | static int add_probe_files(struct bus_type *bus) | 586 | static int add_probe_files(struct bus_type *bus) |
572 | { | 587 | { |
573 | int retval; | 588 | int retval; |
574 | 589 | ||
575 | bus->drivers_probe_attr.attr.name = "drivers_probe"; | 590 | retval = bus_create_file(bus, &bus_attr_drivers_probe); |
576 | bus->drivers_probe_attr.attr.mode = S_IWUSR; | ||
577 | bus->drivers_probe_attr.store = store_drivers_probe; | ||
578 | retval = bus_create_file(bus, &bus->drivers_probe_attr); | ||
579 | if (retval) | 591 | if (retval) |
580 | goto out; | 592 | goto out; |
581 | 593 | ||
582 | bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe"; | 594 | retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); |
583 | bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO; | ||
584 | bus->drivers_autoprobe_attr.show = show_drivers_autoprobe; | ||
585 | bus->drivers_autoprobe_attr.store = store_drivers_autoprobe; | ||
586 | retval = bus_create_file(bus, &bus->drivers_autoprobe_attr); | ||
587 | if (retval) | 595 | if (retval) |
588 | bus_remove_file(bus, &bus->drivers_probe_attr); | 596 | bus_remove_file(bus, &bus_attr_drivers_probe); |
589 | out: | 597 | out: |
590 | return retval; | 598 | return retval; |
591 | } | 599 | } |
592 | 600 | ||
593 | static void remove_probe_files(struct bus_type *bus) | 601 | static void remove_probe_files(struct bus_type *bus) |
594 | { | 602 | { |
595 | bus_remove_file(bus, &bus->drivers_autoprobe_attr); | 603 | bus_remove_file(bus, &bus_attr_drivers_autoprobe); |
596 | bus_remove_file(bus, &bus->drivers_probe_attr); | 604 | bus_remove_file(bus, &bus_attr_drivers_probe); |
597 | } | 605 | } |
598 | #else | 606 | #else |
599 | static inline int add_bind_files(struct device_driver *drv) { return 0; } | 607 | static inline int add_bind_files(struct device_driver *drv) { return 0; } |
@@ -602,6 +610,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; } | |||
602 | static inline void remove_probe_files(struct bus_type *bus) {} | 610 | static inline void remove_probe_files(struct bus_type *bus) {} |
603 | #endif | 611 | #endif |
604 | 612 | ||
613 | static ssize_t driver_uevent_store(struct device_driver *drv, | ||
614 | const char *buf, size_t count) | ||
615 | { | ||
616 | enum kobject_action action; | ||
617 | |||
618 | if (kobject_action_type(buf, count, &action) == 0) | ||
619 | kobject_uevent(&drv->kobj, action); | ||
620 | return count; | ||
621 | } | ||
622 | static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); | ||
623 | |||
605 | /** | 624 | /** |
606 | * bus_add_driver - Add a driver to the bus. | 625 | * bus_add_driver - Add a driver to the bus. |
607 | * @drv: driver. | 626 | * @drv: driver. |
@@ -609,7 +628,7 @@ static inline void remove_probe_files(struct bus_type *bus) {} | |||
609 | */ | 628 | */ |
610 | int bus_add_driver(struct device_driver *drv) | 629 | int bus_add_driver(struct device_driver *drv) |
611 | { | 630 | { |
612 | struct bus_type * bus = get_bus(drv->bus); | 631 | struct bus_type * bus = bus_get(drv->bus); |
613 | int error = 0; | 632 | int error = 0; |
614 | 633 | ||
615 | if (!bus) | 634 | if (!bus) |
@@ -632,6 +651,11 @@ int bus_add_driver(struct device_driver *drv) | |||
632 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); | 651 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); |
633 | module_add_driver(drv->owner, drv); | 652 | module_add_driver(drv->owner, drv); |
634 | 653 | ||
654 | error = driver_create_file(drv, &driver_attr_uevent); | ||
655 | if (error) { | ||
656 | printk(KERN_ERR "%s: uevent attr (%s) failed\n", | ||
657 | __FUNCTION__, drv->name); | ||
658 | } | ||
635 | error = driver_add_attrs(bus, drv); | 659 | error = driver_add_attrs(bus, drv); |
636 | if (error) { | 660 | if (error) { |
637 | /* How the hell do we get out of this pickle? Give up */ | 661 | /* How the hell do we get out of this pickle? Give up */ |
@@ -649,7 +673,7 @@ int bus_add_driver(struct device_driver *drv) | |||
649 | out_unregister: | 673 | out_unregister: |
650 | kobject_unregister(&drv->kobj); | 674 | kobject_unregister(&drv->kobj); |
651 | out_put_bus: | 675 | out_put_bus: |
652 | put_bus(bus); | 676 | bus_put(bus); |
653 | return error; | 677 | return error; |
654 | } | 678 | } |
655 | 679 | ||
@@ -669,12 +693,13 @@ void bus_remove_driver(struct device_driver * drv) | |||
669 | 693 | ||
670 | remove_bind_files(drv); | 694 | remove_bind_files(drv); |
671 | driver_remove_attrs(drv->bus, drv); | 695 | driver_remove_attrs(drv->bus, drv); |
696 | driver_remove_file(drv, &driver_attr_uevent); | ||
672 | klist_remove(&drv->knode_bus); | 697 | klist_remove(&drv->knode_bus); |
673 | pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); | 698 | pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name); |
674 | driver_detach(drv); | 699 | driver_detach(drv); |
675 | module_remove_driver(drv); | 700 | module_remove_driver(drv); |
676 | kobject_unregister(&drv->kobj); | 701 | kobject_unregister(&drv->kobj); |
677 | put_bus(drv->bus); | 702 | bus_put(drv->bus); |
678 | } | 703 | } |
679 | 704 | ||
680 | 705 | ||
@@ -729,18 +754,6 @@ int device_reprobe(struct device *dev) | |||
729 | } | 754 | } |
730 | EXPORT_SYMBOL_GPL(device_reprobe); | 755 | EXPORT_SYMBOL_GPL(device_reprobe); |
731 | 756 | ||
732 | struct bus_type *get_bus(struct bus_type *bus) | ||
733 | { | ||
734 | return bus ? container_of(subsys_get(&bus->subsys), | ||
735 | struct bus_type, subsys) : NULL; | ||
736 | } | ||
737 | |||
738 | void put_bus(struct bus_type * bus) | ||
739 | { | ||
740 | subsys_put(&bus->subsys); | ||
741 | } | ||
742 | |||
743 | |||
744 | /** | 757 | /** |
745 | * find_bus - locate bus by name. | 758 | * find_bus - locate bus by name. |
746 | * @name: name of bus. | 759 | * @name: name of bus. |
@@ -808,6 +821,17 @@ static void klist_devices_put(struct klist_node *n) | |||
808 | put_device(dev); | 821 | put_device(dev); |
809 | } | 822 | } |
810 | 823 | ||
824 | static ssize_t bus_uevent_store(struct bus_type *bus, | ||
825 | const char *buf, size_t count) | ||
826 | { | ||
827 | enum kobject_action action; | ||
828 | |||
829 | if (kobject_action_type(buf, count, &action) == 0) | ||
830 | kobject_uevent(&bus->subsys.kobj, action); | ||
831 | return count; | ||
832 | } | ||
833 | static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); | ||
834 | |||
811 | /** | 835 | /** |
812 | * bus_register - register a bus with the system. | 836 | * bus_register - register a bus with the system. |
813 | * @bus: bus. | 837 | * @bus: bus. |
@@ -826,11 +850,16 @@ int bus_register(struct bus_type * bus) | |||
826 | if (retval) | 850 | if (retval) |
827 | goto out; | 851 | goto out; |
828 | 852 | ||
829 | subsys_set_kset(bus, bus_subsys); | 853 | bus->subsys.kobj.kset = &bus_subsys; |
854 | |||
830 | retval = subsystem_register(&bus->subsys); | 855 | retval = subsystem_register(&bus->subsys); |
831 | if (retval) | 856 | if (retval) |
832 | goto out; | 857 | goto out; |
833 | 858 | ||
859 | retval = bus_create_file(bus, &bus_attr_uevent); | ||
860 | if (retval) | ||
861 | goto bus_uevent_fail; | ||
862 | |||
834 | kobject_set_name(&bus->devices.kobj, "devices"); | 863 | kobject_set_name(&bus->devices.kobj, "devices"); |
835 | bus->devices.kobj.parent = &bus->subsys.kobj; | 864 | bus->devices.kobj.parent = &bus->subsys.kobj; |
836 | retval = kset_register(&bus->devices); | 865 | retval = kset_register(&bus->devices); |
@@ -839,7 +868,7 @@ int bus_register(struct bus_type * bus) | |||
839 | 868 | ||
840 | kobject_set_name(&bus->drivers.kobj, "drivers"); | 869 | kobject_set_name(&bus->drivers.kobj, "drivers"); |
841 | bus->drivers.kobj.parent = &bus->subsys.kobj; | 870 | bus->drivers.kobj.parent = &bus->subsys.kobj; |
842 | bus->drivers.ktype = &ktype_driver; | 871 | bus->drivers.ktype = &driver_ktype; |
843 | retval = kset_register(&bus->drivers); | 872 | retval = kset_register(&bus->drivers); |
844 | if (retval) | 873 | if (retval) |
845 | goto bus_drivers_fail; | 874 | goto bus_drivers_fail; |
@@ -866,6 +895,8 @@ bus_probe_files_fail: | |||
866 | bus_drivers_fail: | 895 | bus_drivers_fail: |
867 | kset_unregister(&bus->devices); | 896 | kset_unregister(&bus->devices); |
868 | bus_devices_fail: | 897 | bus_devices_fail: |
898 | bus_remove_file(bus, &bus_attr_uevent); | ||
899 | bus_uevent_fail: | ||
869 | subsystem_unregister(&bus->subsys); | 900 | subsystem_unregister(&bus->subsys); |
870 | out: | 901 | out: |
871 | return retval; | 902 | return retval; |
@@ -876,7 +907,7 @@ out: | |||
876 | * @bus: bus. | 907 | * @bus: bus. |
877 | * | 908 | * |
878 | * Unregister the child subsystems and the bus itself. | 909 | * Unregister the child subsystems and the bus itself. |
879 | * Finally, we call put_bus() to release the refcount | 910 | * Finally, we call bus_put() to release the refcount |
880 | */ | 911 | */ |
881 | void bus_unregister(struct bus_type * bus) | 912 | void bus_unregister(struct bus_type * bus) |
882 | { | 913 | { |
@@ -885,6 +916,7 @@ void bus_unregister(struct bus_type * bus) | |||
885 | remove_probe_files(bus); | 916 | remove_probe_files(bus); |
886 | kset_unregister(&bus->drivers); | 917 | kset_unregister(&bus->drivers); |
887 | kset_unregister(&bus->devices); | 918 | kset_unregister(&bus->devices); |
919 | bus_remove_file(bus, &bus_attr_uevent); | ||
888 | subsystem_unregister(&bus->subsys); | 920 | subsystem_unregister(&bus->subsys); |
889 | } | 921 | } |
890 | 922 | ||