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 | ||
