diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-03-13 16:13:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-03-13 16:13:47 -0400 |
commit | 96e31022a1b6e7cb173cbb3dce1fde7ba548860a (patch) | |
tree | b50b310790cb79340a5fb67de0485a08dcf31426 /drivers/thermal/thermal.c | |
parent | f2005e1777614b65d1970924ca1b61e4caccb0d3 (diff) | |
parent | 29ea5171cbd08a7ef37e543cbf02447033f0e289 (diff) |
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (32 commits)
ACPI: thermal: show temperature in millidegree Celsius
thermal: fix generic thermal I/F for hwmon
acer-wmi: build depends on i8042
documentation: Move power-related files to Documentation/power/
ACPI: buffer array too short in drivers/acpi/system.c
acer-wmi: Add DMI quirk for mail LED support on Acer Aspire 3610/ 5610
acer-wmi: Fix DSDT path in documentation
acer-wmi: Make device detection error messages more descriptive
laptops: move laptop-mode.txt to Documentation/laptops/
ACPICA: Warn if packages with invalid references are evaluated
ACPI: add _PRT quirks to work around broken firmware
Hibernation: Fix mark_nosave_pages()
ACPI: Ignore _BQC object when registering backlight device
ACPI: WMI: Clean up handling of spec violating data blocks
acer-wmi: Don't warn if mail LED cannot be detected
acer-wmi: Rename mail LED correctly & remove hardcoded colour
ACPI: use ACPI_DEBUG_PRINT instead of printk in acpi_processor_hotplug_notify()
ACPI: button: make real parent for input devices in device tree
toshiba_acpi: Enable autoloading
ACPI: EC: Handle IRQ storm on Acer laptops
...
Diffstat (limited to 'drivers/thermal/thermal.c')
-rw-r--r-- | drivers/thermal/thermal.c | 169 |
1 files changed, 143 insertions, 26 deletions
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c index 8b86e53ccf7a..41bd4c805ace 100644 --- a/drivers/thermal/thermal.c +++ b/drivers/thermal/thermal.c | |||
@@ -30,8 +30,10 @@ | |||
30 | #include <linux/idr.h> | 30 | #include <linux/idr.h> |
31 | #include <linux/thermal.h> | 31 | #include <linux/thermal.h> |
32 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
33 | #include <linux/hwmon.h> | ||
34 | #include <linux/hwmon-sysfs.h> | ||
33 | 35 | ||
34 | MODULE_AUTHOR("Zhang Rui") | 36 | MODULE_AUTHOR("Zhang Rui"); |
35 | MODULE_DESCRIPTION("Generic thermal management sysfs support"); | 37 | MODULE_DESCRIPTION("Generic thermal management sysfs support"); |
36 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
37 | 39 | ||
@@ -56,6 +58,9 @@ static LIST_HEAD(thermal_tz_list); | |||
56 | static LIST_HEAD(thermal_cdev_list); | 58 | static LIST_HEAD(thermal_cdev_list); |
57 | static DEFINE_MUTEX(thermal_list_lock); | 59 | static DEFINE_MUTEX(thermal_list_lock); |
58 | 60 | ||
61 | static struct device *thermal_hwmon; | ||
62 | #define MAX_THERMAL_ZONES 10 | ||
63 | |||
59 | static int get_idr(struct idr *idr, struct mutex *lock, int *id) | 64 | static int get_idr(struct idr *idr, struct mutex *lock, int *id) |
60 | { | 65 | { |
61 | int err; | 66 | int err; |
@@ -87,7 +92,67 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id) | |||
87 | mutex_unlock(lock); | 92 | mutex_unlock(lock); |
88 | } | 93 | } |
89 | 94 | ||
90 | /* sys I/F for thermal zone */ | 95 | /* hwmon sys I/F*/ |
96 | static ssize_t | ||
97 | name_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
98 | { | ||
99 | return sprintf(buf, "thermal_sys_class\n"); | ||
100 | } | ||
101 | |||
102 | static ssize_t | ||
103 | temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
104 | { | ||
105 | struct thermal_zone_device *tz; | ||
106 | struct sensor_device_attribute *sensor_attr | ||
107 | = to_sensor_dev_attr(attr); | ||
108 | |||
109 | list_for_each_entry(tz, &thermal_tz_list, node) | ||
110 | if (tz->id == sensor_attr->index) | ||
111 | return tz->ops->get_temp(tz, buf); | ||
112 | |||
113 | return -ENODEV; | ||
114 | } | ||
115 | |||
116 | static ssize_t | ||
117 | temp_crit_show(struct device *dev, struct device_attribute *attr, | ||
118 | char *buf) | ||
119 | { | ||
120 | struct thermal_zone_device *tz; | ||
121 | struct sensor_device_attribute *sensor_attr | ||
122 | = to_sensor_dev_attr(attr); | ||
123 | |||
124 | list_for_each_entry(tz, &thermal_tz_list, node) | ||
125 | if (tz->id == sensor_attr->index) | ||
126 | return tz->ops->get_trip_temp(tz, 0, buf); | ||
127 | |||
128 | return -ENODEV; | ||
129 | } | ||
130 | |||
131 | static DEVICE_ATTR(name, 0444, name_show, NULL); | ||
132 | static struct sensor_device_attribute sensor_attrs[] = { | ||
133 | SENSOR_ATTR(temp1_input, 0444, temp_input_show, NULL, 0), | ||
134 | SENSOR_ATTR(temp1_crit, 0444, temp_crit_show, NULL, 0), | ||
135 | SENSOR_ATTR(temp2_input, 0444, temp_input_show, NULL, 1), | ||
136 | SENSOR_ATTR(temp2_crit, 0444, temp_crit_show, NULL, 1), | ||
137 | SENSOR_ATTR(temp3_input, 0444, temp_input_show, NULL, 2), | ||
138 | SENSOR_ATTR(temp3_crit, 0444, temp_crit_show, NULL, 2), | ||
139 | SENSOR_ATTR(temp4_input, 0444, temp_input_show, NULL, 3), | ||
140 | SENSOR_ATTR(temp4_crit, 0444, temp_crit_show, NULL, 3), | ||
141 | SENSOR_ATTR(temp5_input, 0444, temp_input_show, NULL, 4), | ||
142 | SENSOR_ATTR(temp5_crit, 0444, temp_crit_show, NULL, 4), | ||
143 | SENSOR_ATTR(temp6_input, 0444, temp_input_show, NULL, 5), | ||
144 | SENSOR_ATTR(temp6_crit, 0444, temp_crit_show, NULL, 5), | ||
145 | SENSOR_ATTR(temp7_input, 0444, temp_input_show, NULL, 6), | ||
146 | SENSOR_ATTR(temp7_crit, 0444, temp_crit_show, NULL, 6), | ||
147 | SENSOR_ATTR(temp8_input, 0444, temp_input_show, NULL, 7), | ||
148 | SENSOR_ATTR(temp8_crit, 0444, temp_crit_show, NULL, 7), | ||
149 | SENSOR_ATTR(temp9_input, 0444, temp_input_show, NULL, 8), | ||
150 | SENSOR_ATTR(temp9_crit, 0444, temp_crit_show, NULL, 8), | ||
151 | SENSOR_ATTR(temp10_input, 0444, temp_input_show, NULL, 9), | ||
152 | SENSOR_ATTR(temp10_crit, 0444, temp_crit_show, NULL, 9), | ||
153 | }; | ||
154 | |||
155 | /* thermal zone sys I/F */ | ||
91 | 156 | ||
92 | #define to_thermal_zone(_dev) \ | 157 | #define to_thermal_zone(_dev) \ |
93 | container_of(_dev, struct thermal_zone_device, device) | 158 | container_of(_dev, struct thermal_zone_device, device) |
@@ -214,7 +279,7 @@ do { \ | |||
214 | device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ | 279 | device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ |
215 | } while (0) | 280 | } while (0) |
216 | 281 | ||
217 | /* sys I/F for cooling device */ | 282 | /* cooling device sys I/F */ |
218 | #define to_cooling_device(_dev) \ | 283 | #define to_cooling_device(_dev) \ |
219 | container_of(_dev, struct thermal_cooling_device, device) | 284 | container_of(_dev, struct thermal_cooling_device, device) |
220 | 285 | ||
@@ -447,6 +512,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, | |||
447 | struct thermal_zone_device *pos; | 512 | struct thermal_zone_device *pos; |
448 | int result; | 513 | int result; |
449 | 514 | ||
515 | if (!type) | ||
516 | return ERR_PTR(-EINVAL); | ||
517 | |||
450 | if (strlen(type) >= THERMAL_NAME_LENGTH) | 518 | if (strlen(type) >= THERMAL_NAME_LENGTH) |
451 | return ERR_PTR(-EINVAL); | 519 | return ERR_PTR(-EINVAL); |
452 | 520 | ||
@@ -477,11 +545,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, | |||
477 | } | 545 | } |
478 | 546 | ||
479 | /* sys I/F */ | 547 | /* sys I/F */ |
480 | if (type) { | 548 | result = device_create_file(&cdev->device, &dev_attr_cdev_type); |
481 | result = device_create_file(&cdev->device, &dev_attr_cdev_type); | 549 | if (result) |
482 | if (result) | 550 | goto unregister; |
483 | goto unregister; | ||
484 | } | ||
485 | 551 | ||
486 | result = device_create_file(&cdev->device, &dev_attr_max_state); | 552 | result = device_create_file(&cdev->device, &dev_attr_max_state); |
487 | if (result) | 553 | if (result) |
@@ -547,8 +613,8 @@ void thermal_cooling_device_unregister(struct | |||
547 | tz->ops->unbind(tz, cdev); | 613 | tz->ops->unbind(tz, cdev); |
548 | } | 614 | } |
549 | mutex_unlock(&thermal_list_lock); | 615 | mutex_unlock(&thermal_list_lock); |
550 | if (cdev->type[0]) | 616 | |
551 | device_remove_file(&cdev->device, &dev_attr_cdev_type); | 617 | device_remove_file(&cdev->device, &dev_attr_cdev_type); |
552 | device_remove_file(&cdev->device, &dev_attr_max_state); | 618 | device_remove_file(&cdev->device, &dev_attr_max_state); |
553 | device_remove_file(&cdev->device, &dev_attr_cur_state); | 619 | device_remove_file(&cdev->device, &dev_attr_cur_state); |
554 | 620 | ||
@@ -580,6 +646,9 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, | |||
580 | int result; | 646 | int result; |
581 | int count; | 647 | int count; |
582 | 648 | ||
649 | if (!type) | ||
650 | return ERR_PTR(-EINVAL); | ||
651 | |||
583 | if (strlen(type) >= THERMAL_NAME_LENGTH) | 652 | if (strlen(type) >= THERMAL_NAME_LENGTH) |
584 | return ERR_PTR(-EINVAL); | 653 | return ERR_PTR(-EINVAL); |
585 | 654 | ||
@@ -601,6 +670,13 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, | |||
601 | kfree(tz); | 670 | kfree(tz); |
602 | return ERR_PTR(result); | 671 | return ERR_PTR(result); |
603 | } | 672 | } |
673 | if (tz->id >= MAX_THERMAL_ZONES) { | ||
674 | printk(KERN_ERR PREFIX | ||
675 | "Too many thermal zones\n"); | ||
676 | release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); | ||
677 | kfree(tz); | ||
678 | return ERR_PTR(-EINVAL); | ||
679 | } | ||
604 | 680 | ||
605 | strcpy(tz->type, type); | 681 | strcpy(tz->type, type); |
606 | tz->ops = ops; | 682 | tz->ops = ops; |
@@ -615,13 +691,28 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, | |||
615 | return ERR_PTR(result); | 691 | return ERR_PTR(result); |
616 | } | 692 | } |
617 | 693 | ||
618 | /* sys I/F */ | 694 | /* hwmon sys I/F */ |
619 | if (type) { | 695 | result = device_create_file(thermal_hwmon, |
620 | result = device_create_file(&tz->device, &dev_attr_type); | 696 | &sensor_attrs[tz->id * 2].dev_attr); |
621 | if (result) | 697 | if (result) |
622 | goto unregister; | 698 | goto unregister; |
699 | |||
700 | if (trips > 0) { | ||
701 | char buf[40]; | ||
702 | result = tz->ops->get_trip_type(tz, 0, buf); | ||
703 | if (result > 0 && !strcmp(buf, "critical\n")) { | ||
704 | result = device_create_file(thermal_hwmon, | ||
705 | &sensor_attrs[tz->id * 2 + 1].dev_attr); | ||
706 | if (result) | ||
707 | goto unregister; | ||
708 | } | ||
623 | } | 709 | } |
624 | 710 | ||
711 | /* sys I/F */ | ||
712 | result = device_create_file(&tz->device, &dev_attr_type); | ||
713 | if (result) | ||
714 | goto unregister; | ||
715 | |||
625 | result = device_create_file(&tz->device, &dev_attr_temp); | 716 | result = device_create_file(&tz->device, &dev_attr_temp); |
626 | if (result) | 717 | if (result) |
627 | goto unregister; | 718 | goto unregister; |
@@ -687,8 +778,17 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) | |||
687 | tz->ops->unbind(tz, cdev); | 778 | tz->ops->unbind(tz, cdev); |
688 | mutex_unlock(&thermal_list_lock); | 779 | mutex_unlock(&thermal_list_lock); |
689 | 780 | ||
690 | if (tz->type[0]) | 781 | device_remove_file(thermal_hwmon, |
691 | device_remove_file(&tz->device, &dev_attr_type); | 782 | &sensor_attrs[tz->id * 2].dev_attr); |
783 | if (tz->trips > 0) { | ||
784 | char buf[40]; | ||
785 | if (tz->ops->get_trip_type(tz, 0, buf) > 0) | ||
786 | if (!strcmp(buf, "critical\n")) | ||
787 | device_remove_file(thermal_hwmon, | ||
788 | &sensor_attrs[tz->id * 2 + 1].dev_attr); | ||
789 | } | ||
790 | |||
791 | device_remove_file(&tz->device, &dev_attr_type); | ||
692 | device_remove_file(&tz->device, &dev_attr_temp); | 792 | device_remove_file(&tz->device, &dev_attr_temp); |
693 | if (tz->ops->get_mode) | 793 | if (tz->ops->get_mode) |
694 | device_remove_file(&tz->device, &dev_attr_mode); | 794 | device_remove_file(&tz->device, &dev_attr_mode); |
@@ -705,6 +805,19 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) | |||
705 | 805 | ||
706 | EXPORT_SYMBOL(thermal_zone_device_unregister); | 806 | EXPORT_SYMBOL(thermal_zone_device_unregister); |
707 | 807 | ||
808 | static void thermal_exit(void) | ||
809 | { | ||
810 | if (thermal_hwmon) { | ||
811 | device_remove_file(thermal_hwmon, &dev_attr_name); | ||
812 | hwmon_device_unregister(thermal_hwmon); | ||
813 | } | ||
814 | class_unregister(&thermal_class); | ||
815 | idr_destroy(&thermal_tz_idr); | ||
816 | idr_destroy(&thermal_cdev_idr); | ||
817 | mutex_destroy(&thermal_idr_lock); | ||
818 | mutex_destroy(&thermal_list_lock); | ||
819 | } | ||
820 | |||
708 | static int __init thermal_init(void) | 821 | static int __init thermal_init(void) |
709 | { | 822 | { |
710 | int result = 0; | 823 | int result = 0; |
@@ -716,16 +829,20 @@ static int __init thermal_init(void) | |||
716 | mutex_destroy(&thermal_idr_lock); | 829 | mutex_destroy(&thermal_idr_lock); |
717 | mutex_destroy(&thermal_list_lock); | 830 | mutex_destroy(&thermal_list_lock); |
718 | } | 831 | } |
719 | return result; | ||
720 | } | ||
721 | 832 | ||
722 | static void __exit thermal_exit(void) | 833 | thermal_hwmon = hwmon_device_register(NULL); |
723 | { | 834 | if (IS_ERR(thermal_hwmon)) { |
724 | class_unregister(&thermal_class); | 835 | result = PTR_ERR(thermal_hwmon); |
725 | idr_destroy(&thermal_tz_idr); | 836 | thermal_hwmon = NULL; |
726 | idr_destroy(&thermal_cdev_idr); | 837 | printk(KERN_ERR PREFIX |
727 | mutex_destroy(&thermal_idr_lock); | 838 | "unable to register hwmon device\n"); |
728 | mutex_destroy(&thermal_list_lock); | 839 | thermal_exit(); |
840 | return result; | ||
841 | } | ||
842 | |||
843 | result = device_create_file(thermal_hwmon, &dev_attr_name); | ||
844 | |||
845 | return result; | ||
729 | } | 846 | } |
730 | 847 | ||
731 | subsys_initcall(thermal_init); | 848 | subsys_initcall(thermal_init); |