diff options
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/Kconfig | 8 | ||||
-rw-r--r-- | drivers/base/base.h | 2 | ||||
-rw-r--r-- | drivers/base/bus.c | 116 | ||||
-rw-r--r-- | drivers/base/class.c | 60 | ||||
-rw-r--r-- | drivers/base/core.c | 108 | ||||
-rw-r--r-- | drivers/base/firmware_class.c | 14 | ||||
-rw-r--r-- | drivers/base/memory.c | 3 | ||||
-rw-r--r-- | drivers/base/platform.c | 26 | ||||
-rw-r--r-- | drivers/base/power/Makefile | 2 | ||||
-rw-r--r-- | drivers/base/power/main.c | 344 | ||||
-rw-r--r-- | drivers/base/power/power.h | 38 | ||||
-rw-r--r-- | drivers/base/power/resume.c | 149 | ||||
-rw-r--r-- | drivers/base/power/suspend.c | 210 | ||||
-rw-r--r-- | drivers/base/sys.c | 73 |
14 files changed, 503 insertions, 650 deletions
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index 5d6312e33490..d7da109c24fd 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig | |||
@@ -1,5 +1,13 @@ | |||
1 | menu "Generic Driver Options" | 1 | menu "Generic Driver Options" |
2 | 2 | ||
3 | config UEVENT_HELPER_PATH | ||
4 | string "path to uevent helper" | ||
5 | depends on HOTPLUG | ||
6 | default "/sbin/hotplug" | ||
7 | help | ||
8 | Path to uevent helper program forked by the kernel for | ||
9 | every uevent. | ||
10 | |||
3 | config STANDALONE | 11 | config STANDALONE |
4 | bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL | 12 | bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL |
5 | default y | 13 | default y |
diff --git a/drivers/base/base.h b/drivers/base/base.h index 47eb02d9f1af..10b2fb6c9ce6 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h | |||
@@ -18,8 +18,6 @@ extern int attribute_container_init(void); | |||
18 | extern int bus_add_device(struct device * dev); | 18 | extern int bus_add_device(struct device * dev); |
19 | extern void bus_attach_device(struct device * dev); | 19 | extern void bus_attach_device(struct device * dev); |
20 | extern void bus_remove_device(struct device * dev); | 20 | extern void bus_remove_device(struct device * dev); |
21 | extern struct bus_type *get_bus(struct bus_type * bus); | ||
22 | extern void put_bus(struct bus_type * bus); | ||
23 | 21 | ||
24 | extern int bus_add_driver(struct device_driver *); | 22 | extern int bus_add_driver(struct device_driver *); |
25 | extern void bus_remove_driver(struct device_driver *); | 23 | extern void bus_remove_driver(struct device_driver *); |
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 | ||
diff --git a/drivers/base/class.c b/drivers/base/class.c index 4d2222618b78..a863bb091e11 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c | |||
@@ -65,13 +65,13 @@ static struct sysfs_ops class_sysfs_ops = { | |||
65 | .store = class_attr_store, | 65 | .store = class_attr_store, |
66 | }; | 66 | }; |
67 | 67 | ||
68 | static struct kobj_type ktype_class = { | 68 | static struct kobj_type class_ktype = { |
69 | .sysfs_ops = &class_sysfs_ops, | 69 | .sysfs_ops = &class_sysfs_ops, |
70 | .release = class_release, | 70 | .release = class_release, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | /* Hotplug events for classes go to the class_obj subsys */ | 73 | /* Hotplug events for classes go to the class_obj subsys */ |
74 | static decl_subsys(class, &ktype_class, NULL); | 74 | static decl_subsys(class, &class_ktype, NULL); |
75 | 75 | ||
76 | 76 | ||
77 | int class_create_file(struct class * cls, const struct class_attribute * attr) | 77 | int class_create_file(struct class * cls, const struct class_attribute * attr) |
@@ -93,14 +93,14 @@ void class_remove_file(struct class * cls, const struct class_attribute * attr) | |||
93 | static struct class *class_get(struct class *cls) | 93 | static struct class *class_get(struct class *cls) |
94 | { | 94 | { |
95 | if (cls) | 95 | if (cls) |
96 | return container_of(subsys_get(&cls->subsys), struct class, subsys); | 96 | return container_of(kset_get(&cls->subsys), struct class, subsys); |
97 | return NULL; | 97 | return NULL; |
98 | } | 98 | } |
99 | 99 | ||
100 | static void class_put(struct class * cls) | 100 | static void class_put(struct class * cls) |
101 | { | 101 | { |
102 | if (cls) | 102 | if (cls) |
103 | subsys_put(&cls->subsys); | 103 | kset_put(&cls->subsys); |
104 | } | 104 | } |
105 | 105 | ||
106 | 106 | ||
@@ -149,7 +149,7 @@ int class_register(struct class * cls) | |||
149 | if (error) | 149 | if (error) |
150 | return error; | 150 | return error; |
151 | 151 | ||
152 | subsys_set_kset(cls, class_subsys); | 152 | cls->subsys.kobj.kset = &class_subsys; |
153 | 153 | ||
154 | error = subsystem_register(&cls->subsys); | 154 | error = subsystem_register(&cls->subsys); |
155 | if (!error) { | 155 | if (!error) { |
@@ -180,8 +180,7 @@ static void class_device_create_release(struct class_device *class_dev) | |||
180 | 180 | ||
181 | /* needed to allow these devices to have parent class devices */ | 181 | /* needed to allow these devices to have parent class devices */ |
182 | static int class_device_create_uevent(struct class_device *class_dev, | 182 | static int class_device_create_uevent(struct class_device *class_dev, |
183 | char **envp, int num_envp, | 183 | struct kobj_uevent_env *env) |
184 | char *buffer, int buffer_size) | ||
185 | { | 184 | { |
186 | pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); | 185 | pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id); |
187 | return 0; | 186 | return 0; |
@@ -324,7 +323,7 @@ static void class_dev_release(struct kobject * kobj) | |||
324 | } | 323 | } |
325 | } | 324 | } |
326 | 325 | ||
327 | static struct kobj_type ktype_class_device = { | 326 | static struct kobj_type class_device_ktype = { |
328 | .sysfs_ops = &class_dev_sysfs_ops, | 327 | .sysfs_ops = &class_dev_sysfs_ops, |
329 | .release = class_dev_release, | 328 | .release = class_dev_release, |
330 | }; | 329 | }; |
@@ -333,7 +332,7 @@ static int class_uevent_filter(struct kset *kset, struct kobject *kobj) | |||
333 | { | 332 | { |
334 | struct kobj_type *ktype = get_ktype(kobj); | 333 | struct kobj_type *ktype = get_ktype(kobj); |
335 | 334 | ||
336 | if (ktype == &ktype_class_device) { | 335 | if (ktype == &class_device_ktype) { |
337 | struct class_device *class_dev = to_class_dev(kobj); | 336 | struct class_device *class_dev = to_class_dev(kobj); |
338 | if (class_dev->class) | 337 | if (class_dev->class) |
339 | return 1; | 338 | return 1; |
@@ -403,64 +402,43 @@ static void remove_deprecated_class_device_links(struct class_device *cd) | |||
403 | { } | 402 | { } |
404 | #endif | 403 | #endif |
405 | 404 | ||
406 | static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 405 | static int class_uevent(struct kset *kset, struct kobject *kobj, |
407 | int num_envp, char *buffer, int buffer_size) | 406 | struct kobj_uevent_env *env) |
408 | { | 407 | { |
409 | struct class_device *class_dev = to_class_dev(kobj); | 408 | struct class_device *class_dev = to_class_dev(kobj); |
410 | struct device *dev = class_dev->dev; | 409 | struct device *dev = class_dev->dev; |
411 | int i = 0; | ||
412 | int length = 0; | ||
413 | int retval = 0; | 410 | int retval = 0; |
414 | 411 | ||
415 | pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); | 412 | pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id); |
416 | 413 | ||
417 | if (MAJOR(class_dev->devt)) { | 414 | if (MAJOR(class_dev->devt)) { |
418 | add_uevent_var(envp, num_envp, &i, | 415 | add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt)); |
419 | buffer, buffer_size, &length, | ||
420 | "MAJOR=%u", MAJOR(class_dev->devt)); | ||
421 | 416 | ||
422 | add_uevent_var(envp, num_envp, &i, | 417 | add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt)); |
423 | buffer, buffer_size, &length, | ||
424 | "MINOR=%u", MINOR(class_dev->devt)); | ||
425 | } | 418 | } |
426 | 419 | ||
427 | if (dev) { | 420 | if (dev) { |
428 | const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); | 421 | const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); |
429 | if (path) { | 422 | if (path) { |
430 | add_uevent_var(envp, num_envp, &i, | 423 | add_uevent_var(env, "PHYSDEVPATH=%s", path); |
431 | buffer, buffer_size, &length, | ||
432 | "PHYSDEVPATH=%s", path); | ||
433 | kfree(path); | 424 | kfree(path); |
434 | } | 425 | } |
435 | 426 | ||
436 | if (dev->bus) | 427 | if (dev->bus) |
437 | add_uevent_var(envp, num_envp, &i, | 428 | add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); |
438 | buffer, buffer_size, &length, | ||
439 | "PHYSDEVBUS=%s", dev->bus->name); | ||
440 | 429 | ||
441 | if (dev->driver) | 430 | if (dev->driver) |
442 | add_uevent_var(envp, num_envp, &i, | 431 | add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); |
443 | buffer, buffer_size, &length, | ||
444 | "PHYSDEVDRIVER=%s", dev->driver->name); | ||
445 | } | 432 | } |
446 | 433 | ||
447 | /* terminate, set to next free slot, shrink available space */ | ||
448 | envp[i] = NULL; | ||
449 | envp = &envp[i]; | ||
450 | num_envp -= i; | ||
451 | buffer = &buffer[length]; | ||
452 | buffer_size -= length; | ||
453 | |||
454 | if (class_dev->uevent) { | 434 | if (class_dev->uevent) { |
455 | /* have the class device specific function add its stuff */ | 435 | /* have the class device specific function add its stuff */ |
456 | retval = class_dev->uevent(class_dev, envp, num_envp, | 436 | retval = class_dev->uevent(class_dev, env); |
457 | buffer, buffer_size); | ||
458 | if (retval) | 437 | if (retval) |
459 | pr_debug("class_dev->uevent() returned %d\n", retval); | 438 | pr_debug("class_dev->uevent() returned %d\n", retval); |
460 | } else if (class_dev->class->uevent) { | 439 | } else if (class_dev->class->uevent) { |
461 | /* have the class specific function add its stuff */ | 440 | /* have the class specific function add its stuff */ |
462 | retval = class_dev->class->uevent(class_dev, envp, num_envp, | 441 | retval = class_dev->class->uevent(class_dev, env); |
463 | buffer, buffer_size); | ||
464 | if (retval) | 442 | if (retval) |
465 | pr_debug("class->uevent() returned %d\n", retval); | 443 | pr_debug("class->uevent() returned %d\n", retval); |
466 | } | 444 | } |
@@ -474,7 +452,7 @@ static struct kset_uevent_ops class_uevent_ops = { | |||
474 | .uevent = class_uevent, | 452 | .uevent = class_uevent, |
475 | }; | 453 | }; |
476 | 454 | ||
477 | static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops); | 455 | static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops); |
478 | 456 | ||
479 | 457 | ||
480 | static int class_device_add_attrs(struct class_device * cd) | 458 | static int class_device_add_attrs(struct class_device * cd) |
@@ -883,7 +861,7 @@ int __init classes_init(void) | |||
883 | 861 | ||
884 | /* ick, this is ugly, the things we go through to keep from showing up | 862 | /* ick, this is ugly, the things we go through to keep from showing up |
885 | * in sysfs... */ | 863 | * in sysfs... */ |
886 | subsystem_init(&class_obj_subsys); | 864 | kset_init(&class_obj_subsys); |
887 | if (!class_obj_subsys.kobj.parent) | 865 | if (!class_obj_subsys.kobj.parent) |
888 | class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; | 866 | class_obj_subsys.kobj.parent = &class_obj_subsys.kobj; |
889 | return 0; | 867 | return 0; |
diff --git a/drivers/base/core.c b/drivers/base/core.c index ec86d6fc2360..c1343414d285 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -108,7 +108,7 @@ static void device_release(struct kobject * kobj) | |||
108 | } | 108 | } |
109 | } | 109 | } |
110 | 110 | ||
111 | static struct kobj_type ktype_device = { | 111 | static struct kobj_type device_ktype = { |
112 | .release = device_release, | 112 | .release = device_release, |
113 | .sysfs_ops = &dev_sysfs_ops, | 113 | .sysfs_ops = &dev_sysfs_ops, |
114 | }; | 114 | }; |
@@ -118,7 +118,7 @@ static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) | |||
118 | { | 118 | { |
119 | struct kobj_type *ktype = get_ktype(kobj); | 119 | struct kobj_type *ktype = get_ktype(kobj); |
120 | 120 | ||
121 | if (ktype == &ktype_device) { | 121 | if (ktype == &device_ktype) { |
122 | struct device *dev = to_dev(kobj); | 122 | struct device *dev = to_dev(kobj); |
123 | if (dev->uevent_suppress) | 123 | if (dev->uevent_suppress) |
124 | return 0; | 124 | return 0; |
@@ -141,33 +141,23 @@ static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) | |||
141 | return NULL; | 141 | return NULL; |
142 | } | 142 | } |
143 | 143 | ||
144 | static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 144 | static int dev_uevent(struct kset *kset, struct kobject *kobj, |
145 | int num_envp, char *buffer, int buffer_size) | 145 | struct kobj_uevent_env *env) |
146 | { | 146 | { |
147 | struct device *dev = to_dev(kobj); | 147 | struct device *dev = to_dev(kobj); |
148 | int i = 0; | ||
149 | int length = 0; | ||
150 | int retval = 0; | 148 | int retval = 0; |
151 | 149 | ||
152 | /* add the major/minor if present */ | 150 | /* add the major/minor if present */ |
153 | if (MAJOR(dev->devt)) { | 151 | if (MAJOR(dev->devt)) { |
154 | add_uevent_var(envp, num_envp, &i, | 152 | add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); |
155 | buffer, buffer_size, &length, | 153 | add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); |
156 | "MAJOR=%u", MAJOR(dev->devt)); | ||
157 | add_uevent_var(envp, num_envp, &i, | ||
158 | buffer, buffer_size, &length, | ||
159 | "MINOR=%u", MINOR(dev->devt)); | ||
160 | } | 154 | } |
161 | 155 | ||
162 | if (dev->type && dev->type->name) | 156 | if (dev->type && dev->type->name) |
163 | add_uevent_var(envp, num_envp, &i, | 157 | add_uevent_var(env, "DEVTYPE=%s", dev->type->name); |
164 | buffer, buffer_size, &length, | ||
165 | "DEVTYPE=%s", dev->type->name); | ||
166 | 158 | ||
167 | if (dev->driver) | 159 | if (dev->driver) |
168 | add_uevent_var(envp, num_envp, &i, | 160 | add_uevent_var(env, "DRIVER=%s", dev->driver->name); |
169 | buffer, buffer_size, &length, | ||
170 | "DRIVER=%s", dev->driver->name); | ||
171 | 161 | ||
172 | #ifdef CONFIG_SYSFS_DEPRECATED | 162 | #ifdef CONFIG_SYSFS_DEPRECATED |
173 | if (dev->class) { | 163 | if (dev->class) { |
@@ -181,59 +171,43 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp, | |||
181 | 171 | ||
182 | path = kobject_get_path(&parent->kobj, GFP_KERNEL); | 172 | path = kobject_get_path(&parent->kobj, GFP_KERNEL); |
183 | if (path) { | 173 | if (path) { |
184 | add_uevent_var(envp, num_envp, &i, | 174 | add_uevent_var(env, "PHYSDEVPATH=%s", path); |
185 | buffer, buffer_size, &length, | ||
186 | "PHYSDEVPATH=%s", path); | ||
187 | kfree(path); | 175 | kfree(path); |
188 | } | 176 | } |
189 | 177 | ||
190 | add_uevent_var(envp, num_envp, &i, | 178 | add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name); |
191 | buffer, buffer_size, &length, | ||
192 | "PHYSDEVBUS=%s", parent->bus->name); | ||
193 | 179 | ||
194 | if (parent->driver) | 180 | if (parent->driver) |
195 | add_uevent_var(envp, num_envp, &i, | 181 | add_uevent_var(env, "PHYSDEVDRIVER=%s", |
196 | buffer, buffer_size, &length, | 182 | parent->driver->name); |
197 | "PHYSDEVDRIVER=%s", parent->driver->name); | ||
198 | } | 183 | } |
199 | } else if (dev->bus) { | 184 | } else if (dev->bus) { |
200 | add_uevent_var(envp, num_envp, &i, | 185 | add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name); |
201 | buffer, buffer_size, &length, | ||
202 | "PHYSDEVBUS=%s", dev->bus->name); | ||
203 | 186 | ||
204 | if (dev->driver) | 187 | if (dev->driver) |
205 | add_uevent_var(envp, num_envp, &i, | 188 | add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name); |
206 | buffer, buffer_size, &length, | ||
207 | "PHYSDEVDRIVER=%s", dev->driver->name); | ||
208 | } | 189 | } |
209 | #endif | 190 | #endif |
210 | 191 | ||
211 | /* terminate, set to next free slot, shrink available space */ | 192 | /* have the bus specific function add its stuff */ |
212 | envp[i] = NULL; | ||
213 | envp = &envp[i]; | ||
214 | num_envp -= i; | ||
215 | buffer = &buffer[length]; | ||
216 | buffer_size -= length; | ||
217 | |||
218 | if (dev->bus && dev->bus->uevent) { | 193 | if (dev->bus && dev->bus->uevent) { |
219 | /* have the bus specific function add its stuff */ | 194 | retval = dev->bus->uevent(dev, env); |
220 | retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size); | ||
221 | if (retval) | 195 | if (retval) |
222 | pr_debug ("%s: bus uevent() returned %d\n", | 196 | pr_debug ("%s: bus uevent() returned %d\n", |
223 | __FUNCTION__, retval); | 197 | __FUNCTION__, retval); |
224 | } | 198 | } |
225 | 199 | ||
200 | /* have the class specific function add its stuff */ | ||
226 | if (dev->class && dev->class->dev_uevent) { | 201 | if (dev->class && dev->class->dev_uevent) { |
227 | /* have the class specific function add its stuff */ | 202 | retval = dev->class->dev_uevent(dev, env); |
228 | retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size); | ||
229 | if (retval) | 203 | if (retval) |
230 | pr_debug("%s: class uevent() returned %d\n", | 204 | pr_debug("%s: class uevent() returned %d\n", |
231 | __FUNCTION__, retval); | 205 | __FUNCTION__, retval); |
232 | } | 206 | } |
233 | 207 | ||
208 | /* have the device type specific fuction add its stuff */ | ||
234 | if (dev->type && dev->type->uevent) { | 209 | if (dev->type && dev->type->uevent) { |
235 | /* have the device type specific fuction add its stuff */ | 210 | retval = dev->type->uevent(dev, env); |
236 | retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size); | ||
237 | if (retval) | 211 | if (retval) |
238 | pr_debug("%s: dev_type uevent() returned %d\n", | 212 | pr_debug("%s: dev_type uevent() returned %d\n", |
239 | __FUNCTION__, retval); | 213 | __FUNCTION__, retval); |
@@ -253,22 +227,18 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, | |||
253 | { | 227 | { |
254 | struct kobject *top_kobj; | 228 | struct kobject *top_kobj; |
255 | struct kset *kset; | 229 | struct kset *kset; |
256 | char *envp[32]; | 230 | struct kobj_uevent_env *env = NULL; |
257 | char *data = NULL; | ||
258 | char *pos; | ||
259 | int i; | 231 | int i; |
260 | size_t count = 0; | 232 | size_t count = 0; |
261 | int retval; | 233 | int retval; |
262 | 234 | ||
263 | /* search the kset, the device belongs to */ | 235 | /* search the kset, the device belongs to */ |
264 | top_kobj = &dev->kobj; | 236 | top_kobj = &dev->kobj; |
265 | if (!top_kobj->kset && top_kobj->parent) { | 237 | while (!top_kobj->kset && top_kobj->parent) |
266 | do { | 238 | top_kobj = top_kobj->parent; |
267 | top_kobj = top_kobj->parent; | ||
268 | } while (!top_kobj->kset && top_kobj->parent); | ||
269 | } | ||
270 | if (!top_kobj->kset) | 239 | if (!top_kobj->kset) |
271 | goto out; | 240 | goto out; |
241 | |||
272 | kset = top_kobj->kset; | 242 | kset = top_kobj->kset; |
273 | if (!kset->uevent_ops || !kset->uevent_ops->uevent) | 243 | if (!kset->uevent_ops || !kset->uevent_ops->uevent) |
274 | goto out; | 244 | goto out; |
@@ -278,43 +248,29 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr, | |||
278 | if (!kset->uevent_ops->filter(kset, &dev->kobj)) | 248 | if (!kset->uevent_ops->filter(kset, &dev->kobj)) |
279 | goto out; | 249 | goto out; |
280 | 250 | ||
281 | data = (char *)get_zeroed_page(GFP_KERNEL); | 251 | env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); |
282 | if (!data) | 252 | if (!env) |
283 | return -ENOMEM; | 253 | return -ENOMEM; |
284 | 254 | ||
285 | /* let the kset specific function add its keys */ | 255 | /* let the kset specific function add its keys */ |
286 | pos = data; | 256 | retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); |
287 | memset(envp, 0, sizeof(envp)); | ||
288 | retval = kset->uevent_ops->uevent(kset, &dev->kobj, | ||
289 | envp, ARRAY_SIZE(envp), | ||
290 | pos, PAGE_SIZE); | ||
291 | if (retval) | 257 | if (retval) |
292 | goto out; | 258 | goto out; |
293 | 259 | ||
294 | /* copy keys to file */ | 260 | /* copy keys to file */ |
295 | for (i = 0; envp[i]; i++) { | 261 | for (i = 0; i < env->envp_idx; i++) |
296 | pos = &buf[count]; | 262 | count += sprintf(&buf[count], "%s\n", env->envp[i]); |
297 | count += sprintf(pos, "%s\n", envp[i]); | ||
298 | } | ||
299 | out: | 263 | out: |
300 | free_page((unsigned long)data); | 264 | kfree(env); |
301 | return count; | 265 | return count; |
302 | } | 266 | } |
303 | 267 | ||
304 | static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, | 268 | static ssize_t store_uevent(struct device *dev, struct device_attribute *attr, |
305 | const char *buf, size_t count) | 269 | const char *buf, size_t count) |
306 | { | 270 | { |
307 | size_t len = count; | ||
308 | enum kobject_action action; | 271 | enum kobject_action action; |
309 | 272 | ||
310 | if (len && buf[len-1] == '\n') | 273 | if (kobject_action_type(buf, count, &action) == 0) { |
311 | len--; | ||
312 | |||
313 | for (action = 0; action < KOBJ_MAX; action++) { | ||
314 | if (strncmp(kobject_actions[action], buf, len) != 0) | ||
315 | continue; | ||
316 | if (kobject_actions[action][len] != '\0') | ||
317 | continue; | ||
318 | kobject_uevent(&dev->kobj, action); | 274 | kobject_uevent(&dev->kobj, action); |
319 | goto out; | 275 | goto out; |
320 | } | 276 | } |
@@ -449,7 +405,7 @@ static struct device_attribute devt_attr = | |||
449 | * devices_subsys - structure to be registered with kobject core. | 405 | * devices_subsys - structure to be registered with kobject core. |
450 | */ | 406 | */ |
451 | 407 | ||
452 | decl_subsys(devices, &ktype_device, &device_uevent_ops); | 408 | decl_subsys(devices, &device_ktype, &device_uevent_ops); |
453 | 409 | ||
454 | 410 | ||
455 | /** | 411 | /** |
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index b24efd4e3e3d..0295855a3eef 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c | |||
@@ -88,19 +88,14 @@ static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store); | |||
88 | 88 | ||
89 | static void fw_dev_release(struct device *dev); | 89 | static void fw_dev_release(struct device *dev); |
90 | 90 | ||
91 | static int firmware_uevent(struct device *dev, char **envp, int num_envp, | 91 | static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) |
92 | char *buffer, int buffer_size) | ||
93 | { | 92 | { |
94 | struct firmware_priv *fw_priv = dev_get_drvdata(dev); | 93 | struct firmware_priv *fw_priv = dev_get_drvdata(dev); |
95 | int i = 0, len = 0; | ||
96 | 94 | ||
97 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | 95 | if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id)) |
98 | "FIRMWARE=%s", fw_priv->fw_id)) | ||
99 | return -ENOMEM; | 96 | return -ENOMEM; |
100 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len, | 97 | if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) |
101 | "TIMEOUT=%i", loading_timeout)) | ||
102 | return -ENOMEM; | 98 | return -ENOMEM; |
103 | envp[i] = NULL; | ||
104 | 99 | ||
105 | return 0; | 100 | return 0; |
106 | } | 101 | } |
@@ -297,8 +292,7 @@ firmware_class_timeout(u_long data) | |||
297 | 292 | ||
298 | static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) | 293 | static inline void fw_setup_device_id(struct device *f_dev, struct device *dev) |
299 | { | 294 | { |
300 | /* XXX warning we should watch out for name collisions */ | 295 | snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id); |
301 | strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE); | ||
302 | } | 296 | } |
303 | 297 | ||
304 | static int fw_register_device(struct device **dev_p, const char *fw_name, | 298 | static int fw_register_device(struct device **dev_p, const char *fw_name, |
diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 74b96795d2f5..cb99daeae936 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c | |||
@@ -34,8 +34,7 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj) | |||
34 | return MEMORY_CLASS_NAME; | 34 | return MEMORY_CLASS_NAME; |
35 | } | 35 | } |
36 | 36 | ||
37 | static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp, | 37 | static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env) |
38 | int num_envp, char *buffer, int buffer_size) | ||
39 | { | 38 | { |
40 | int retval = 0; | 39 | int retval = 0; |
41 | 40 | ||
diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 869ff8c00146..fb5609241482 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c | |||
@@ -160,13 +160,8 @@ static void platform_device_release(struct device *dev) | |||
160 | * | 160 | * |
161 | * Create a platform device object which can have other objects attached | 161 | * Create a platform device object which can have other objects attached |
162 | * to it, and which will have attached objects freed when it is released. | 162 | * to it, and which will have attached objects freed when it is released. |
163 | * | ||
164 | * This device will be marked as not supporting hotpluggable drivers; no | ||
165 | * device add/remove uevents will be generated. In the unusual case that | ||
166 | * the device isn't being dynamically allocated as a legacy "probe the | ||
167 | * hardware" driver, infrastructure code should reverse this marking. | ||
168 | */ | 163 | */ |
169 | struct platform_device *platform_device_alloc(const char *name, unsigned int id) | 164 | struct platform_device *platform_device_alloc(const char *name, int id) |
170 | { | 165 | { |
171 | struct platform_object *pa; | 166 | struct platform_object *pa; |
172 | 167 | ||
@@ -177,12 +172,6 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id) | |||
177 | pa->pdev.id = id; | 172 | pa->pdev.id = id; |
178 | device_initialize(&pa->pdev.dev); | 173 | device_initialize(&pa->pdev.dev); |
179 | pa->pdev.dev.release = platform_device_release; | 174 | pa->pdev.dev.release = platform_device_release; |
180 | |||
181 | /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in | ||
182 | * legacy probe-the-hardware drivers, which don't properly split | ||
183 | * out device enumeration logic from drivers. | ||
184 | */ | ||
185 | pa->pdev.dev.uevent_suppress = 1; | ||
186 | } | 175 | } |
187 | 176 | ||
188 | return pa ? &pa->pdev : NULL; | 177 | return pa ? &pa->pdev : NULL; |
@@ -256,7 +245,8 @@ int platform_device_add(struct platform_device *pdev) | |||
256 | pdev->dev.bus = &platform_bus_type; | 245 | pdev->dev.bus = &platform_bus_type; |
257 | 246 | ||
258 | if (pdev->id != -1) | 247 | if (pdev->id != -1) |
259 | snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id); | 248 | snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name, |
249 | pdev->id); | ||
260 | else | 250 | else |
261 | strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); | 251 | strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE); |
262 | 252 | ||
@@ -370,7 +360,7 @@ EXPORT_SYMBOL_GPL(platform_device_unregister); | |||
370 | * the Linux driver model. In particular, when such drivers are built | 360 | * the Linux driver model. In particular, when such drivers are built |
371 | * as modules, they can't be "hotplugged". | 361 | * as modules, they can't be "hotplugged". |
372 | */ | 362 | */ |
373 | struct platform_device *platform_device_register_simple(char *name, unsigned int id, | 363 | struct platform_device *platform_device_register_simple(char *name, int id, |
374 | struct resource *res, unsigned int num) | 364 | struct resource *res, unsigned int num) |
375 | { | 365 | { |
376 | struct platform_device *pdev; | 366 | struct platform_device *pdev; |
@@ -530,7 +520,7 @@ static ssize_t | |||
530 | modalias_show(struct device *dev, struct device_attribute *a, char *buf) | 520 | modalias_show(struct device *dev, struct device_attribute *a, char *buf) |
531 | { | 521 | { |
532 | struct platform_device *pdev = to_platform_device(dev); | 522 | struct platform_device *pdev = to_platform_device(dev); |
533 | int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name); | 523 | int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); |
534 | 524 | ||
535 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; | 525 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; |
536 | } | 526 | } |
@@ -540,13 +530,11 @@ static struct device_attribute platform_dev_attrs[] = { | |||
540 | __ATTR_NULL, | 530 | __ATTR_NULL, |
541 | }; | 531 | }; |
542 | 532 | ||
543 | static int platform_uevent(struct device *dev, char **envp, int num_envp, | 533 | static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) |
544 | char *buffer, int buffer_size) | ||
545 | { | 534 | { |
546 | struct platform_device *pdev = to_platform_device(dev); | 535 | struct platform_device *pdev = to_platform_device(dev); |
547 | 536 | ||
548 | envp[0] = buffer; | 537 | add_uevent_var(env, "MODALIAS=platform:%s", pdev->name); |
549 | snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name); | ||
550 | return 0; | 538 | return 0; |
551 | } | 539 | } |
552 | 540 | ||
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 9caeaea753a3..a803733c839e 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-y := shutdown.o | 1 | obj-y := shutdown.o |
2 | obj-$(CONFIG_PM_SLEEP) += main.o suspend.o resume.o sysfs.o | 2 | obj-$(CONFIG_PM_SLEEP) += main.o sysfs.o |
3 | obj-$(CONFIG_PM_TRACE) += trace.o | 3 | obj-$(CONFIG_PM_TRACE) += trace.o |
4 | 4 | ||
5 | ifeq ($(CONFIG_DEBUG_DRIVER),y) | 5 | ifeq ($(CONFIG_DEBUG_DRIVER),y) |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index eb9f38d0aa58..0ab4ab21f564 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -20,19 +20,24 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/device.h> | 22 | #include <linux/device.h> |
23 | #include <linux/kallsyms.h> | ||
23 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/pm.h> | ||
26 | #include <linux/resume-trace.h> | ||
24 | 27 | ||
28 | #include "../base.h" | ||
25 | #include "power.h" | 29 | #include "power.h" |
26 | 30 | ||
27 | LIST_HEAD(dpm_active); | 31 | LIST_HEAD(dpm_active); |
28 | LIST_HEAD(dpm_off); | 32 | static LIST_HEAD(dpm_off); |
29 | LIST_HEAD(dpm_off_irq); | 33 | static LIST_HEAD(dpm_off_irq); |
30 | 34 | ||
31 | DEFINE_MUTEX(dpm_mtx); | 35 | static DEFINE_MUTEX(dpm_mtx); |
32 | DEFINE_MUTEX(dpm_list_mtx); | 36 | static DEFINE_MUTEX(dpm_list_mtx); |
33 | 37 | ||
34 | int (*platform_enable_wakeup)(struct device *dev, int is_on); | 38 | int (*platform_enable_wakeup)(struct device *dev, int is_on); |
35 | 39 | ||
40 | |||
36 | int device_pm_add(struct device *dev) | 41 | int device_pm_add(struct device *dev) |
37 | { | 42 | { |
38 | int error; | 43 | int error; |
@@ -61,3 +66,334 @@ void device_pm_remove(struct device *dev) | |||
61 | } | 66 | } |
62 | 67 | ||
63 | 68 | ||
69 | /*------------------------- Resume routines -------------------------*/ | ||
70 | |||
71 | /** | ||
72 | * resume_device - Restore state for one device. | ||
73 | * @dev: Device. | ||
74 | * | ||
75 | */ | ||
76 | |||
77 | static int resume_device(struct device * dev) | ||
78 | { | ||
79 | int error = 0; | ||
80 | |||
81 | TRACE_DEVICE(dev); | ||
82 | TRACE_RESUME(0); | ||
83 | |||
84 | down(&dev->sem); | ||
85 | |||
86 | if (dev->bus && dev->bus->resume) { | ||
87 | dev_dbg(dev,"resuming\n"); | ||
88 | error = dev->bus->resume(dev); | ||
89 | } | ||
90 | |||
91 | if (!error && dev->type && dev->type->resume) { | ||
92 | dev_dbg(dev,"resuming\n"); | ||
93 | error = dev->type->resume(dev); | ||
94 | } | ||
95 | |||
96 | if (!error && dev->class && dev->class->resume) { | ||
97 | dev_dbg(dev,"class resume\n"); | ||
98 | error = dev->class->resume(dev); | ||
99 | } | ||
100 | |||
101 | up(&dev->sem); | ||
102 | |||
103 | TRACE_RESUME(error); | ||
104 | return error; | ||
105 | } | ||
106 | |||
107 | |||
108 | static int resume_device_early(struct device * dev) | ||
109 | { | ||
110 | int error = 0; | ||
111 | |||
112 | TRACE_DEVICE(dev); | ||
113 | TRACE_RESUME(0); | ||
114 | if (dev->bus && dev->bus->resume_early) { | ||
115 | dev_dbg(dev,"EARLY resume\n"); | ||
116 | error = dev->bus->resume_early(dev); | ||
117 | } | ||
118 | TRACE_RESUME(error); | ||
119 | return error; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Resume the devices that have either not gone through | ||
124 | * the late suspend, or that did go through it but also | ||
125 | * went through the early resume | ||
126 | */ | ||
127 | static void dpm_resume(void) | ||
128 | { | ||
129 | mutex_lock(&dpm_list_mtx); | ||
130 | while(!list_empty(&dpm_off)) { | ||
131 | struct list_head * entry = dpm_off.next; | ||
132 | struct device * dev = to_device(entry); | ||
133 | |||
134 | get_device(dev); | ||
135 | list_move_tail(entry, &dpm_active); | ||
136 | |||
137 | mutex_unlock(&dpm_list_mtx); | ||
138 | resume_device(dev); | ||
139 | mutex_lock(&dpm_list_mtx); | ||
140 | put_device(dev); | ||
141 | } | ||
142 | mutex_unlock(&dpm_list_mtx); | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * device_resume - Restore state of each device in system. | ||
148 | * | ||
149 | * Walk the dpm_off list, remove each entry, resume the device, | ||
150 | * then add it to the dpm_active list. | ||
151 | */ | ||
152 | |||
153 | void device_resume(void) | ||
154 | { | ||
155 | might_sleep(); | ||
156 | mutex_lock(&dpm_mtx); | ||
157 | dpm_resume(); | ||
158 | mutex_unlock(&dpm_mtx); | ||
159 | } | ||
160 | |||
161 | EXPORT_SYMBOL_GPL(device_resume); | ||
162 | |||
163 | |||
164 | /** | ||
165 | * dpm_power_up - Power on some devices. | ||
166 | * | ||
167 | * Walk the dpm_off_irq list and power each device up. This | ||
168 | * is used for devices that required they be powered down with | ||
169 | * interrupts disabled. As devices are powered on, they are moved | ||
170 | * to the dpm_active list. | ||
171 | * | ||
172 | * Interrupts must be disabled when calling this. | ||
173 | */ | ||
174 | |||
175 | static void dpm_power_up(void) | ||
176 | { | ||
177 | while(!list_empty(&dpm_off_irq)) { | ||
178 | struct list_head * entry = dpm_off_irq.next; | ||
179 | struct device * dev = to_device(entry); | ||
180 | |||
181 | list_move_tail(entry, &dpm_off); | ||
182 | resume_device_early(dev); | ||
183 | } | ||
184 | } | ||
185 | |||
186 | |||
187 | /** | ||
188 | * device_power_up - Turn on all devices that need special attention. | ||
189 | * | ||
190 | * Power on system devices then devices that required we shut them down | ||
191 | * with interrupts disabled. | ||
192 | * Called with interrupts disabled. | ||
193 | */ | ||
194 | |||
195 | void device_power_up(void) | ||
196 | { | ||
197 | sysdev_resume(); | ||
198 | dpm_power_up(); | ||
199 | } | ||
200 | |||
201 | EXPORT_SYMBOL_GPL(device_power_up); | ||
202 | |||
203 | |||
204 | /*------------------------- Suspend routines -------------------------*/ | ||
205 | |||
206 | /* | ||
207 | * The entries in the dpm_active list are in a depth first order, simply | ||
208 | * because children are guaranteed to be discovered after parents, and | ||
209 | * are inserted at the back of the list on discovery. | ||
210 | * | ||
211 | * All list on the suspend path are done in reverse order, so we operate | ||
212 | * on the leaves of the device tree (or forests, depending on how you want | ||
213 | * to look at it ;) first. As nodes are removed from the back of the list, | ||
214 | * they are inserted into the front of their destintation lists. | ||
215 | * | ||
216 | * Things are the reverse on the resume path - iterations are done in | ||
217 | * forward order, and nodes are inserted at the back of their destination | ||
218 | * lists. This way, the ancestors will be accessed before their descendents. | ||
219 | */ | ||
220 | |||
221 | static inline char *suspend_verb(u32 event) | ||
222 | { | ||
223 | switch (event) { | ||
224 | case PM_EVENT_SUSPEND: return "suspend"; | ||
225 | case PM_EVENT_FREEZE: return "freeze"; | ||
226 | case PM_EVENT_PRETHAW: return "prethaw"; | ||
227 | default: return "(unknown suspend event)"; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | |||
232 | static void | ||
233 | suspend_device_dbg(struct device *dev, pm_message_t state, char *info) | ||
234 | { | ||
235 | dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), | ||
236 | ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? | ||
237 | ", may wakeup" : ""); | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * suspend_device - Save state of one device. | ||
242 | * @dev: Device. | ||
243 | * @state: Power state device is entering. | ||
244 | */ | ||
245 | |||
246 | static int suspend_device(struct device * dev, pm_message_t state) | ||
247 | { | ||
248 | int error = 0; | ||
249 | |||
250 | down(&dev->sem); | ||
251 | if (dev->power.power_state.event) { | ||
252 | dev_dbg(dev, "PM: suspend %d-->%d\n", | ||
253 | dev->power.power_state.event, state.event); | ||
254 | } | ||
255 | |||
256 | if (dev->class && dev->class->suspend) { | ||
257 | suspend_device_dbg(dev, state, "class "); | ||
258 | error = dev->class->suspend(dev, state); | ||
259 | suspend_report_result(dev->class->suspend, error); | ||
260 | } | ||
261 | |||
262 | if (!error && dev->type && dev->type->suspend) { | ||
263 | suspend_device_dbg(dev, state, "type "); | ||
264 | error = dev->type->suspend(dev, state); | ||
265 | suspend_report_result(dev->type->suspend, error); | ||
266 | } | ||
267 | |||
268 | if (!error && dev->bus && dev->bus->suspend) { | ||
269 | suspend_device_dbg(dev, state, ""); | ||
270 | error = dev->bus->suspend(dev, state); | ||
271 | suspend_report_result(dev->bus->suspend, error); | ||
272 | } | ||
273 | up(&dev->sem); | ||
274 | return error; | ||
275 | } | ||
276 | |||
277 | |||
278 | /* | ||
279 | * This is called with interrupts off, only a single CPU | ||
280 | * running. We can't acquire a mutex or semaphore (and we don't | ||
281 | * need the protection) | ||
282 | */ | ||
283 | static int suspend_device_late(struct device *dev, pm_message_t state) | ||
284 | { | ||
285 | int error = 0; | ||
286 | |||
287 | if (dev->bus && dev->bus->suspend_late) { | ||
288 | suspend_device_dbg(dev, state, "LATE "); | ||
289 | error = dev->bus->suspend_late(dev, state); | ||
290 | suspend_report_result(dev->bus->suspend_late, error); | ||
291 | } | ||
292 | return error; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * device_suspend - Save state and stop all devices in system. | ||
297 | * @state: Power state to put each device in. | ||
298 | * | ||
299 | * Walk the dpm_active list, call ->suspend() for each device, and move | ||
300 | * it to the dpm_off list. | ||
301 | * | ||
302 | * (For historical reasons, if it returns -EAGAIN, that used to mean | ||
303 | * that the device would be called again with interrupts disabled. | ||
304 | * These days, we use the "suspend_late()" callback for that, so we | ||
305 | * print a warning and consider it an error). | ||
306 | * | ||
307 | * If we get a different error, try and back out. | ||
308 | * | ||
309 | * If we hit a failure with any of the devices, call device_resume() | ||
310 | * above to bring the suspended devices back to life. | ||
311 | * | ||
312 | */ | ||
313 | |||
314 | int device_suspend(pm_message_t state) | ||
315 | { | ||
316 | int error = 0; | ||
317 | |||
318 | might_sleep(); | ||
319 | mutex_lock(&dpm_mtx); | ||
320 | mutex_lock(&dpm_list_mtx); | ||
321 | while (!list_empty(&dpm_active) && error == 0) { | ||
322 | struct list_head * entry = dpm_active.prev; | ||
323 | struct device * dev = to_device(entry); | ||
324 | |||
325 | get_device(dev); | ||
326 | mutex_unlock(&dpm_list_mtx); | ||
327 | |||
328 | error = suspend_device(dev, state); | ||
329 | |||
330 | mutex_lock(&dpm_list_mtx); | ||
331 | |||
332 | /* Check if the device got removed */ | ||
333 | if (!list_empty(&dev->power.entry)) { | ||
334 | /* Move it to the dpm_off list */ | ||
335 | if (!error) | ||
336 | list_move(&dev->power.entry, &dpm_off); | ||
337 | } | ||
338 | if (error) | ||
339 | printk(KERN_ERR "Could not suspend device %s: " | ||
340 | "error %d%s\n", | ||
341 | kobject_name(&dev->kobj), error, | ||
342 | error == -EAGAIN ? " (please convert to suspend_late)" : ""); | ||
343 | put_device(dev); | ||
344 | } | ||
345 | mutex_unlock(&dpm_list_mtx); | ||
346 | if (error) | ||
347 | dpm_resume(); | ||
348 | |||
349 | mutex_unlock(&dpm_mtx); | ||
350 | return error; | ||
351 | } | ||
352 | |||
353 | EXPORT_SYMBOL_GPL(device_suspend); | ||
354 | |||
355 | /** | ||
356 | * device_power_down - Shut down special devices. | ||
357 | * @state: Power state to enter. | ||
358 | * | ||
359 | * Walk the dpm_off_irq list, calling ->power_down() for each device that | ||
360 | * couldn't power down the device with interrupts enabled. When we're | ||
361 | * done, power down system devices. | ||
362 | */ | ||
363 | |||
364 | int device_power_down(pm_message_t state) | ||
365 | { | ||
366 | int error = 0; | ||
367 | struct device * dev; | ||
368 | |||
369 | while (!list_empty(&dpm_off)) { | ||
370 | struct list_head * entry = dpm_off.prev; | ||
371 | |||
372 | dev = to_device(entry); | ||
373 | error = suspend_device_late(dev, state); | ||
374 | if (error) | ||
375 | goto Error; | ||
376 | list_move(&dev->power.entry, &dpm_off_irq); | ||
377 | } | ||
378 | |||
379 | error = sysdev_suspend(state); | ||
380 | Done: | ||
381 | return error; | ||
382 | Error: | ||
383 | printk(KERN_ERR "Could not power down device %s: " | ||
384 | "error %d\n", kobject_name(&dev->kobj), error); | ||
385 | dpm_power_up(); | ||
386 | goto Done; | ||
387 | } | ||
388 | |||
389 | EXPORT_SYMBOL_GPL(device_power_down); | ||
390 | |||
391 | void __suspend_report_result(const char *function, void *fn, int ret) | ||
392 | { | ||
393 | if (ret) { | ||
394 | printk(KERN_ERR "%s(): ", function); | ||
395 | print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); | ||
396 | printk("%d\n", ret); | ||
397 | } | ||
398 | } | ||
399 | EXPORT_SYMBOL_GPL(__suspend_report_result); | ||
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 8ba0830cbc03..5c4efd493fa5 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
@@ -11,32 +11,11 @@ extern void device_shutdown(void); | |||
11 | * main.c | 11 | * main.c |
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* | 14 | extern struct list_head dpm_active; /* The active device list */ |
15 | * Used to synchronize global power management operations. | ||
16 | */ | ||
17 | extern struct mutex dpm_mtx; | ||
18 | |||
19 | /* | ||
20 | * Used to serialize changes to the dpm_* lists. | ||
21 | */ | ||
22 | extern struct mutex dpm_list_mtx; | ||
23 | |||
24 | /* | ||
25 | * The PM lists. | ||
26 | */ | ||
27 | extern struct list_head dpm_active; | ||
28 | extern struct list_head dpm_off; | ||
29 | extern struct list_head dpm_off_irq; | ||
30 | |||
31 | |||
32 | static inline struct dev_pm_info * to_pm_info(struct list_head * entry) | ||
33 | { | ||
34 | return container_of(entry, struct dev_pm_info, entry); | ||
35 | } | ||
36 | 15 | ||
37 | static inline struct device * to_device(struct list_head * entry) | 16 | static inline struct device * to_device(struct list_head * entry) |
38 | { | 17 | { |
39 | return container_of(to_pm_info(entry), struct device, power); | 18 | return container_of(entry, struct device, power.entry); |
40 | } | 19 | } |
41 | 20 | ||
42 | extern int device_pm_add(struct device *); | 21 | extern int device_pm_add(struct device *); |
@@ -49,19 +28,6 @@ extern void device_pm_remove(struct device *); | |||
49 | extern int dpm_sysfs_add(struct device *); | 28 | extern int dpm_sysfs_add(struct device *); |
50 | extern void dpm_sysfs_remove(struct device *); | 29 | extern void dpm_sysfs_remove(struct device *); |
51 | 30 | ||
52 | /* | ||
53 | * resume.c | ||
54 | */ | ||
55 | |||
56 | extern void dpm_resume(void); | ||
57 | extern void dpm_power_up(void); | ||
58 | extern int resume_device(struct device *); | ||
59 | |||
60 | /* | ||
61 | * suspend.c | ||
62 | */ | ||
63 | extern int suspend_device(struct device *, pm_message_t); | ||
64 | |||
65 | #else /* CONFIG_PM_SLEEP */ | 31 | #else /* CONFIG_PM_SLEEP */ |
66 | 32 | ||
67 | 33 | ||
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c deleted file mode 100644 index 00fd84ae6e66..000000000000 --- a/drivers/base/power/resume.c +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
1 | /* | ||
2 | * resume.c - Functions for waking devices up. | ||
3 | * | ||
4 | * Copyright (c) 2003 Patrick Mochel | ||
5 | * Copyright (c) 2003 Open Source Development Labs | ||
6 | * | ||
7 | * This file is released under the GPLv2 | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/device.h> | ||
12 | #include <linux/resume-trace.h> | ||
13 | #include "../base.h" | ||
14 | #include "power.h" | ||
15 | |||
16 | |||
17 | /** | ||
18 | * resume_device - Restore state for one device. | ||
19 | * @dev: Device. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | int resume_device(struct device * dev) | ||
24 | { | ||
25 | int error = 0; | ||
26 | |||
27 | TRACE_DEVICE(dev); | ||
28 | TRACE_RESUME(0); | ||
29 | |||
30 | down(&dev->sem); | ||
31 | |||
32 | if (dev->bus && dev->bus->resume) { | ||
33 | dev_dbg(dev,"resuming\n"); | ||
34 | error = dev->bus->resume(dev); | ||
35 | } | ||
36 | |||
37 | if (!error && dev->type && dev->type->resume) { | ||
38 | dev_dbg(dev,"resuming\n"); | ||
39 | error = dev->type->resume(dev); | ||
40 | } | ||
41 | |||
42 | if (!error && dev->class && dev->class->resume) { | ||
43 | dev_dbg(dev,"class resume\n"); | ||
44 | error = dev->class->resume(dev); | ||
45 | } | ||
46 | |||
47 | up(&dev->sem); | ||
48 | |||
49 | TRACE_RESUME(error); | ||
50 | return error; | ||
51 | } | ||
52 | |||
53 | |||
54 | static int resume_device_early(struct device * dev) | ||
55 | { | ||
56 | int error = 0; | ||
57 | |||
58 | TRACE_DEVICE(dev); | ||
59 | TRACE_RESUME(0); | ||
60 | if (dev->bus && dev->bus->resume_early) { | ||
61 | dev_dbg(dev,"EARLY resume\n"); | ||
62 | error = dev->bus->resume_early(dev); | ||
63 | } | ||
64 | TRACE_RESUME(error); | ||
65 | return error; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Resume the devices that have either not gone through | ||
70 | * the late suspend, or that did go through it but also | ||
71 | * went through the early resume | ||
72 | */ | ||
73 | void dpm_resume(void) | ||
74 | { | ||
75 | mutex_lock(&dpm_list_mtx); | ||
76 | while(!list_empty(&dpm_off)) { | ||
77 | struct list_head * entry = dpm_off.next; | ||
78 | struct device * dev = to_device(entry); | ||
79 | |||
80 | get_device(dev); | ||
81 | list_move_tail(entry, &dpm_active); | ||
82 | |||
83 | mutex_unlock(&dpm_list_mtx); | ||
84 | resume_device(dev); | ||
85 | mutex_lock(&dpm_list_mtx); | ||
86 | put_device(dev); | ||
87 | } | ||
88 | mutex_unlock(&dpm_list_mtx); | ||
89 | } | ||
90 | |||
91 | |||
92 | /** | ||
93 | * device_resume - Restore state of each device in system. | ||
94 | * | ||
95 | * Walk the dpm_off list, remove each entry, resume the device, | ||
96 | * then add it to the dpm_active list. | ||
97 | */ | ||
98 | |||
99 | void device_resume(void) | ||
100 | { | ||
101 | might_sleep(); | ||
102 | mutex_lock(&dpm_mtx); | ||
103 | dpm_resume(); | ||
104 | mutex_unlock(&dpm_mtx); | ||
105 | } | ||
106 | |||
107 | EXPORT_SYMBOL_GPL(device_resume); | ||
108 | |||
109 | |||
110 | /** | ||
111 | * dpm_power_up - Power on some devices. | ||
112 | * | ||
113 | * Walk the dpm_off_irq list and power each device up. This | ||
114 | * is used for devices that required they be powered down with | ||
115 | * interrupts disabled. As devices are powered on, they are moved | ||
116 | * to the dpm_active list. | ||
117 | * | ||
118 | * Interrupts must be disabled when calling this. | ||
119 | */ | ||
120 | |||
121 | void dpm_power_up(void) | ||
122 | { | ||
123 | while(!list_empty(&dpm_off_irq)) { | ||
124 | struct list_head * entry = dpm_off_irq.next; | ||
125 | struct device * dev = to_device(entry); | ||
126 | |||
127 | list_move_tail(entry, &dpm_off); | ||
128 | resume_device_early(dev); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | |||
133 | /** | ||
134 | * device_power_up - Turn on all devices that need special attention. | ||
135 | * | ||
136 | * Power on system devices then devices that required we shut them down | ||
137 | * with interrupts disabled. | ||
138 | * Called with interrupts disabled. | ||
139 | */ | ||
140 | |||
141 | void device_power_up(void) | ||
142 | { | ||
143 | sysdev_resume(); | ||
144 | dpm_power_up(); | ||
145 | } | ||
146 | |||
147 | EXPORT_SYMBOL_GPL(device_power_up); | ||
148 | |||
149 | |||
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c deleted file mode 100644 index 26df9b231737..000000000000 --- a/drivers/base/power/suspend.c +++ /dev/null | |||
@@ -1,210 +0,0 @@ | |||
1 | /* | ||
2 | * suspend.c - Functions for putting devices to sleep. | ||
3 | * | ||
4 | * Copyright (c) 2003 Patrick Mochel | ||
5 | * Copyright (c) 2003 Open Source Development Labs | ||
6 | * | ||
7 | * This file is released under the GPLv2 | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/device.h> | ||
12 | #include <linux/kallsyms.h> | ||
13 | #include <linux/pm.h> | ||
14 | #include "../base.h" | ||
15 | #include "power.h" | ||
16 | |||
17 | /* | ||
18 | * The entries in the dpm_active list are in a depth first order, simply | ||
19 | * because children are guaranteed to be discovered after parents, and | ||
20 | * are inserted at the back of the list on discovery. | ||
21 | * | ||
22 | * All list on the suspend path are done in reverse order, so we operate | ||
23 | * on the leaves of the device tree (or forests, depending on how you want | ||
24 | * to look at it ;) first. As nodes are removed from the back of the list, | ||
25 | * they are inserted into the front of their destintation lists. | ||
26 | * | ||
27 | * Things are the reverse on the resume path - iterations are done in | ||
28 | * forward order, and nodes are inserted at the back of their destination | ||
29 | * lists. This way, the ancestors will be accessed before their descendents. | ||
30 | */ | ||
31 | |||
32 | static inline char *suspend_verb(u32 event) | ||
33 | { | ||
34 | switch (event) { | ||
35 | case PM_EVENT_SUSPEND: return "suspend"; | ||
36 | case PM_EVENT_FREEZE: return "freeze"; | ||
37 | case PM_EVENT_PRETHAW: return "prethaw"; | ||
38 | default: return "(unknown suspend event)"; | ||
39 | } | ||
40 | } | ||
41 | |||
42 | |||
43 | static void | ||
44 | suspend_device_dbg(struct device *dev, pm_message_t state, char *info) | ||
45 | { | ||
46 | dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event), | ||
47 | ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ? | ||
48 | ", may wakeup" : ""); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * suspend_device - Save state of one device. | ||
53 | * @dev: Device. | ||
54 | * @state: Power state device is entering. | ||
55 | */ | ||
56 | |||
57 | int suspend_device(struct device * dev, pm_message_t state) | ||
58 | { | ||
59 | int error = 0; | ||
60 | |||
61 | down(&dev->sem); | ||
62 | if (dev->power.power_state.event) { | ||
63 | dev_dbg(dev, "PM: suspend %d-->%d\n", | ||
64 | dev->power.power_state.event, state.event); | ||
65 | } | ||
66 | |||
67 | if (dev->class && dev->class->suspend) { | ||
68 | suspend_device_dbg(dev, state, "class "); | ||
69 | error = dev->class->suspend(dev, state); | ||
70 | suspend_report_result(dev->class->suspend, error); | ||
71 | } | ||
72 | |||
73 | if (!error && dev->type && dev->type->suspend) { | ||
74 | suspend_device_dbg(dev, state, "type "); | ||
75 | error = dev->type->suspend(dev, state); | ||
76 | suspend_report_result(dev->type->suspend, error); | ||
77 | } | ||
78 | |||
79 | if (!error && dev->bus && dev->bus->suspend) { | ||
80 | suspend_device_dbg(dev, state, ""); | ||
81 | error = dev->bus->suspend(dev, state); | ||
82 | suspend_report_result(dev->bus->suspend, error); | ||
83 | } | ||
84 | up(&dev->sem); | ||
85 | return error; | ||
86 | } | ||
87 | |||
88 | |||
89 | /* | ||
90 | * This is called with interrupts off, only a single CPU | ||
91 | * running. We can't acquire a mutex or semaphore (and we don't | ||
92 | * need the protection) | ||
93 | */ | ||
94 | static int suspend_device_late(struct device *dev, pm_message_t state) | ||
95 | { | ||
96 | int error = 0; | ||
97 | |||
98 | if (dev->bus && dev->bus->suspend_late) { | ||
99 | suspend_device_dbg(dev, state, "LATE "); | ||
100 | error = dev->bus->suspend_late(dev, state); | ||
101 | suspend_report_result(dev->bus->suspend_late, error); | ||
102 | } | ||
103 | return error; | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * device_suspend - Save state and stop all devices in system. | ||
108 | * @state: Power state to put each device in. | ||
109 | * | ||
110 | * Walk the dpm_active list, call ->suspend() for each device, and move | ||
111 | * it to the dpm_off list. | ||
112 | * | ||
113 | * (For historical reasons, if it returns -EAGAIN, that used to mean | ||
114 | * that the device would be called again with interrupts disabled. | ||
115 | * These days, we use the "suspend_late()" callback for that, so we | ||
116 | * print a warning and consider it an error). | ||
117 | * | ||
118 | * If we get a different error, try and back out. | ||
119 | * | ||
120 | * If we hit a failure with any of the devices, call device_resume() | ||
121 | * above to bring the suspended devices back to life. | ||
122 | * | ||
123 | */ | ||
124 | |||
125 | int device_suspend(pm_message_t state) | ||
126 | { | ||
127 | int error = 0; | ||
128 | |||
129 | might_sleep(); | ||
130 | mutex_lock(&dpm_mtx); | ||
131 | mutex_lock(&dpm_list_mtx); | ||
132 | while (!list_empty(&dpm_active) && error == 0) { | ||
133 | struct list_head * entry = dpm_active.prev; | ||
134 | struct device * dev = to_device(entry); | ||
135 | |||
136 | get_device(dev); | ||
137 | mutex_unlock(&dpm_list_mtx); | ||
138 | |||
139 | error = suspend_device(dev, state); | ||
140 | |||
141 | mutex_lock(&dpm_list_mtx); | ||
142 | |||
143 | /* Check if the device got removed */ | ||
144 | if (!list_empty(&dev->power.entry)) { | ||
145 | /* Move it to the dpm_off list */ | ||
146 | if (!error) | ||
147 | list_move(&dev->power.entry, &dpm_off); | ||
148 | } | ||
149 | if (error) | ||
150 | printk(KERN_ERR "Could not suspend device %s: " | ||
151 | "error %d%s\n", | ||
152 | kobject_name(&dev->kobj), error, | ||
153 | error == -EAGAIN ? " (please convert to suspend_late)" : ""); | ||
154 | put_device(dev); | ||
155 | } | ||
156 | mutex_unlock(&dpm_list_mtx); | ||
157 | if (error) | ||
158 | dpm_resume(); | ||
159 | |||
160 | mutex_unlock(&dpm_mtx); | ||
161 | return error; | ||
162 | } | ||
163 | |||
164 | EXPORT_SYMBOL_GPL(device_suspend); | ||
165 | |||
166 | /** | ||
167 | * device_power_down - Shut down special devices. | ||
168 | * @state: Power state to enter. | ||
169 | * | ||
170 | * Walk the dpm_off_irq list, calling ->power_down() for each device that | ||
171 | * couldn't power down the device with interrupts enabled. When we're | ||
172 | * done, power down system devices. | ||
173 | */ | ||
174 | |||
175 | int device_power_down(pm_message_t state) | ||
176 | { | ||
177 | int error = 0; | ||
178 | struct device * dev; | ||
179 | |||
180 | while (!list_empty(&dpm_off)) { | ||
181 | struct list_head * entry = dpm_off.prev; | ||
182 | |||
183 | dev = to_device(entry); | ||
184 | error = suspend_device_late(dev, state); | ||
185 | if (error) | ||
186 | goto Error; | ||
187 | list_move(&dev->power.entry, &dpm_off_irq); | ||
188 | } | ||
189 | |||
190 | error = sysdev_suspend(state); | ||
191 | Done: | ||
192 | return error; | ||
193 | Error: | ||
194 | printk(KERN_ERR "Could not power down device %s: " | ||
195 | "error %d\n", kobject_name(&dev->kobj), error); | ||
196 | dpm_power_up(); | ||
197 | goto Done; | ||
198 | } | ||
199 | |||
200 | EXPORT_SYMBOL_GPL(device_power_down); | ||
201 | |||
202 | void __suspend_report_result(const char *function, void *fn, int ret) | ||
203 | { | ||
204 | if (ret) { | ||
205 | printk(KERN_ERR "%s(): ", function); | ||
206 | print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn); | ||
207 | printk("%d\n", ret); | ||
208 | } | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(__suspend_report_result); | ||
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index 18febe26caa1..ac7ff6d0c6e5 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
@@ -139,7 +139,7 @@ int sysdev_class_register(struct sysdev_class * cls) | |||
139 | kobject_name(&cls->kset.kobj)); | 139 | kobject_name(&cls->kset.kobj)); |
140 | INIT_LIST_HEAD(&cls->drivers); | 140 | INIT_LIST_HEAD(&cls->drivers); |
141 | cls->kset.kobj.parent = &system_subsys.kobj; | 141 | cls->kset.kobj.parent = &system_subsys.kobj; |
142 | kset_set_kset_s(cls, system_subsys); | 142 | cls->kset.kobj.kset = &system_subsys; |
143 | return kset_register(&cls->kset); | 143 | return kset_register(&cls->kset); |
144 | } | 144 | } |
145 | 145 | ||
@@ -153,25 +153,22 @@ void sysdev_class_unregister(struct sysdev_class * cls) | |||
153 | EXPORT_SYMBOL_GPL(sysdev_class_register); | 153 | EXPORT_SYMBOL_GPL(sysdev_class_register); |
154 | EXPORT_SYMBOL_GPL(sysdev_class_unregister); | 154 | EXPORT_SYMBOL_GPL(sysdev_class_unregister); |
155 | 155 | ||
156 | |||
157 | static LIST_HEAD(sysdev_drivers); | ||
158 | static DEFINE_MUTEX(sysdev_drivers_lock); | 156 | static DEFINE_MUTEX(sysdev_drivers_lock); |
159 | 157 | ||
160 | /** | 158 | /** |
161 | * sysdev_driver_register - Register auxillary driver | 159 | * sysdev_driver_register - Register auxillary driver |
162 | * @cls: Device class driver belongs to. | 160 | * @cls: Device class driver belongs to. |
163 | * @drv: Driver. | 161 | * @drv: Driver. |
164 | * | 162 | * |
165 | * If @cls is valid, then @drv is inserted into @cls->drivers to be | 163 | * @drv is inserted into @cls->drivers to be |
166 | * called on each operation on devices of that class. The refcount | 164 | * called on each operation on devices of that class. The refcount |
167 | * of @cls is incremented. | 165 | * of @cls is incremented. |
168 | * Otherwise, @drv is inserted into sysdev_drivers, and called for | ||
169 | * each device. | ||
170 | */ | 166 | */ |
171 | 167 | ||
172 | int sysdev_driver_register(struct sysdev_class * cls, | 168 | int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) |
173 | struct sysdev_driver * drv) | ||
174 | { | 169 | { |
170 | int err = 0; | ||
171 | |||
175 | mutex_lock(&sysdev_drivers_lock); | 172 | mutex_lock(&sysdev_drivers_lock); |
176 | if (cls && kset_get(&cls->kset)) { | 173 | if (cls && kset_get(&cls->kset)) { |
177 | list_add_tail(&drv->entry, &cls->drivers); | 174 | list_add_tail(&drv->entry, &cls->drivers); |
@@ -182,10 +179,13 @@ int sysdev_driver_register(struct sysdev_class * cls, | |||
182 | list_for_each_entry(dev, &cls->kset.list, kobj.entry) | 179 | list_for_each_entry(dev, &cls->kset.list, kobj.entry) |
183 | drv->add(dev); | 180 | drv->add(dev); |
184 | } | 181 | } |
185 | } else | 182 | } else { |
186 | list_add_tail(&drv->entry, &sysdev_drivers); | 183 | err = -EINVAL; |
184 | printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__); | ||
185 | WARN_ON(1); | ||
186 | } | ||
187 | mutex_unlock(&sysdev_drivers_lock); | 187 | mutex_unlock(&sysdev_drivers_lock); |
188 | return 0; | 188 | return err; |
189 | } | 189 | } |
190 | 190 | ||
191 | 191 | ||
@@ -251,12 +251,6 @@ int sysdev_register(struct sys_device * sysdev) | |||
251 | * code that should have called us. | 251 | * code that should have called us. |
252 | */ | 252 | */ |
253 | 253 | ||
254 | /* Notify global drivers */ | ||
255 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
256 | if (drv->add) | ||
257 | drv->add(sysdev); | ||
258 | } | ||
259 | |||
260 | /* Notify class auxillary drivers */ | 254 | /* Notify class auxillary drivers */ |
261 | list_for_each_entry(drv, &cls->drivers, entry) { | 255 | list_for_each_entry(drv, &cls->drivers, entry) { |
262 | if (drv->add) | 256 | if (drv->add) |
@@ -272,11 +266,6 @@ void sysdev_unregister(struct sys_device * sysdev) | |||
272 | struct sysdev_driver * drv; | 266 | struct sysdev_driver * drv; |
273 | 267 | ||
274 | mutex_lock(&sysdev_drivers_lock); | 268 | mutex_lock(&sysdev_drivers_lock); |
275 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
276 | if (drv->remove) | ||
277 | drv->remove(sysdev); | ||
278 | } | ||
279 | |||
280 | list_for_each_entry(drv, &sysdev->cls->drivers, entry) { | 269 | list_for_each_entry(drv, &sysdev->cls->drivers, entry) { |
281 | if (drv->remove) | 270 | if (drv->remove) |
282 | drv->remove(sysdev); | 271 | drv->remove(sysdev); |
@@ -293,7 +282,7 @@ void sysdev_unregister(struct sys_device * sysdev) | |||
293 | * | 282 | * |
294 | * Loop over each class of system devices, and the devices in each | 283 | * Loop over each class of system devices, and the devices in each |
295 | * of those classes. For each device, we call the shutdown method for | 284 | * of those classes. For each device, we call the shutdown method for |
296 | * each driver registered for the device - the globals, the auxillaries, | 285 | * each driver registered for the device - the auxillaries, |
297 | * and the class driver. | 286 | * and the class driver. |
298 | * | 287 | * |
299 | * Note: The list is iterated in reverse order, so that we shut down | 288 | * Note: The list is iterated in reverse order, so that we shut down |
@@ -320,13 +309,7 @@ void sysdev_shutdown(void) | |||
320 | struct sysdev_driver * drv; | 309 | struct sysdev_driver * drv; |
321 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | 310 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); |
322 | 311 | ||
323 | /* Call global drivers first. */ | 312 | /* Call auxillary drivers first */ |
324 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
325 | if (drv->shutdown) | ||
326 | drv->shutdown(sysdev); | ||
327 | } | ||
328 | |||
329 | /* Call auxillary drivers next. */ | ||
330 | list_for_each_entry(drv, &cls->drivers, entry) { | 313 | list_for_each_entry(drv, &cls->drivers, entry) { |
331 | if (drv->shutdown) | 314 | if (drv->shutdown) |
332 | drv->shutdown(sysdev); | 315 | drv->shutdown(sysdev); |
@@ -354,12 +337,6 @@ static void __sysdev_resume(struct sys_device *dev) | |||
354 | if (drv->resume) | 337 | if (drv->resume) |
355 | drv->resume(dev); | 338 | drv->resume(dev); |
356 | } | 339 | } |
357 | |||
358 | /* Call global drivers. */ | ||
359 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
360 | if (drv->resume) | ||
361 | drv->resume(dev); | ||
362 | } | ||
363 | } | 340 | } |
364 | 341 | ||
365 | /** | 342 | /** |
@@ -393,16 +370,7 @@ int sysdev_suspend(pm_message_t state) | |||
393 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { | 370 | list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) { |
394 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); | 371 | pr_debug(" %s\n", kobject_name(&sysdev->kobj)); |
395 | 372 | ||
396 | /* Call global drivers first. */ | 373 | /* Call auxillary drivers first */ |
397 | list_for_each_entry(drv, &sysdev_drivers, entry) { | ||
398 | if (drv->suspend) { | ||
399 | ret = drv->suspend(sysdev, state); | ||
400 | if (ret) | ||
401 | goto gbl_driver; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | /* Call auxillary drivers next. */ | ||
406 | list_for_each_entry(drv, &cls->drivers, entry) { | 374 | list_for_each_entry(drv, &cls->drivers, entry) { |
407 | if (drv->suspend) { | 375 | if (drv->suspend) { |
408 | ret = drv->suspend(sysdev, state); | 376 | ret = drv->suspend(sysdev, state); |
@@ -436,18 +404,7 @@ aux_driver: | |||
436 | if (err_drv->resume) | 404 | if (err_drv->resume) |
437 | err_drv->resume(sysdev); | 405 | err_drv->resume(sysdev); |
438 | } | 406 | } |
439 | drv = NULL; | ||
440 | 407 | ||
441 | gbl_driver: | ||
442 | if (drv) | ||
443 | printk(KERN_ERR "sysdev driver suspend failed for %s\n", | ||
444 | kobject_name(&sysdev->kobj)); | ||
445 | list_for_each_entry(err_drv, &sysdev_drivers, entry) { | ||
446 | if (err_drv == drv) | ||
447 | break; | ||
448 | if (err_drv->resume) | ||
449 | err_drv->resume(sysdev); | ||
450 | } | ||
451 | /* resume other sysdevs in current class */ | 408 | /* resume other sysdevs in current class */ |
452 | list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { | 409 | list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) { |
453 | if (err_dev == sysdev) | 410 | if (err_dev == sysdev) |