diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2008-01-08 10:02:45 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-02-01 22:26:07 -0500 |
commit | b21a15f6d065e837076cf417720afe1c3d6ed10d (patch) | |
tree | c6271b56ee4a6a5964b71df44ae30e7dd00815e6 /drivers/misc/thinkpad_acpi.c | |
parent | f74a27d4bda42ee779940adaa34c5c196dda5d32 (diff) |
ACPI: thinkpad-acpi: spring cleanup part 3
Reorder code in the file to get rid of more of the forward declarations,
and to make things cleaner and more organized.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 1493 |
1 files changed, 734 insertions, 759 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index e435b554a004..b6293a40132e 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -113,28 +113,6 @@ | |||
113 | 113 | ||
114 | #include <linux/pci_ids.h> | 114 | #include <linux/pci_ids.h> |
115 | 115 | ||
116 | /**************************************************************************** | ||
117 | * Main driver | ||
118 | */ | ||
119 | |||
120 | #define IBM_NAME "thinkpad" | ||
121 | #define IBM_DESC "ThinkPad ACPI Extras" | ||
122 | #define IBM_FILE IBM_NAME "_acpi" | ||
123 | #define IBM_URL "http://ibm-acpi.sf.net/" | ||
124 | #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" | ||
125 | |||
126 | #define IBM_PROC_DIR "ibm" | ||
127 | #define IBM_ACPI_EVENT_PREFIX "ibm" | ||
128 | #define IBM_DRVR_NAME IBM_FILE | ||
129 | #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" | ||
130 | |||
131 | #define IBM_LOG IBM_FILE ": " | ||
132 | #define IBM_ERR KERN_ERR IBM_LOG | ||
133 | #define IBM_NOTICE KERN_NOTICE IBM_LOG | ||
134 | #define IBM_INFO KERN_INFO IBM_LOG | ||
135 | #define IBM_DEBUG KERN_DEBUG IBM_LOG | ||
136 | |||
137 | #define IBM_MAX_ACPI_ARGS 3 | ||
138 | 116 | ||
139 | /* ThinkPad CMOS commands */ | 117 | /* ThinkPad CMOS commands */ |
140 | #define TP_CMOS_VOLUME_DOWN 0 | 118 | #define TP_CMOS_VOLUME_DOWN 0 |
@@ -169,11 +147,70 @@ enum { | |||
169 | TP_NVRAM_POS_LEVEL_VOLUME = 0, | 147 | TP_NVRAM_POS_LEVEL_VOLUME = 0, |
170 | }; | 148 | }; |
171 | 149 | ||
172 | #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") | 150 | /* ACPI HIDs */ |
173 | #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") | 151 | #define IBM_HKEY_HID "IBM0068" |
174 | #define strlencmp(a,b) (strncmp((a), (b), strlen(b))) | 152 | |
153 | /* Input IDs */ | ||
154 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ | ||
155 | #define TPACPI_HKEY_INPUT_VERSION 0x4101 | ||
156 | |||
157 | |||
158 | /**************************************************************************** | ||
159 | * Main driver | ||
160 | */ | ||
161 | |||
162 | /* Module */ | ||
163 | #define IBM_NAME "thinkpad" | ||
164 | #define IBM_DESC "ThinkPad ACPI Extras" | ||
165 | #define IBM_FILE IBM_NAME "_acpi" | ||
166 | #define IBM_URL "http://ibm-acpi.sf.net/" | ||
167 | #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" | ||
168 | |||
169 | #define IBM_PROC_DIR "ibm" | ||
170 | #define IBM_ACPI_EVENT_PREFIX "ibm" | ||
171 | #define IBM_DRVR_NAME IBM_FILE | ||
172 | #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" | ||
173 | |||
174 | #define IBM_MAX_ACPI_ARGS 3 | ||
175 | |||
176 | MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); | ||
177 | MODULE_DESCRIPTION(IBM_DESC); | ||
178 | MODULE_VERSION(IBM_VERSION); | ||
179 | MODULE_LICENSE("GPL"); | ||
180 | |||
181 | /* Please remove this in year 2009 */ | ||
182 | MODULE_ALIAS("ibm_acpi"); | ||
183 | |||
184 | /* | ||
185 | * DMI matching for module autoloading | ||
186 | * | ||
187 | * See http://thinkwiki.org/wiki/List_of_DMI_IDs | ||
188 | * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads | ||
189 | * | ||
190 | * Only models listed in thinkwiki will be supported, so add yours | ||
191 | * if it is not there yet. | ||
192 | */ | ||
193 | #define IBM_BIOS_MODULE_ALIAS(__type) \ | ||
194 | MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") | ||
195 | |||
196 | /* Non-ancient thinkpads */ | ||
197 | MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); | ||
198 | MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); | ||
199 | |||
200 | /* Ancient thinkpad BIOSes have to be identified by | ||
201 | * BIOS type or model number, and there are far less | ||
202 | * BIOS types than model numbers... */ | ||
203 | IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); | ||
204 | IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); | ||
205 | IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); | ||
175 | 206 | ||
176 | /* Debugging */ | 207 | /* Debugging */ |
208 | #define IBM_LOG IBM_FILE ": " | ||
209 | #define IBM_ERR KERN_ERR IBM_LOG | ||
210 | #define IBM_NOTICE KERN_NOTICE IBM_LOG | ||
211 | #define IBM_INFO KERN_INFO IBM_LOG | ||
212 | #define IBM_DEBUG KERN_DEBUG IBM_LOG | ||
213 | |||
177 | #define TPACPI_DBG_ALL 0xffff | 214 | #define TPACPI_DBG_ALL 0xffff |
178 | #define TPACPI_DBG_ALL 0xffff | 215 | #define TPACPI_DBG_ALL 0xffff |
179 | #define TPACPI_DBG_INIT 0x0001 | 216 | #define TPACPI_DBG_INIT 0x0001 |
@@ -189,33 +226,13 @@ static const char *str_supported(int is_supported); | |||
189 | #define vdbg_printk(a_dbg_level, format, arg...) | 226 | #define vdbg_printk(a_dbg_level, format, arg...) |
190 | #endif | 227 | #endif |
191 | 228 | ||
192 | /* Input IDs */ | 229 | #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") |
193 | #define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM | 230 | #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") |
194 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ | 231 | #define strlencmp(a,b) (strncmp((a), (b), strlen(b))) |
195 | #define TPACPI_HKEY_INPUT_VERSION 0x4101 | ||
196 | |||
197 | /* ACPI HIDs */ | ||
198 | #define IBM_HKEY_HID "IBM0068" | ||
199 | |||
200 | /* sysfs support */ | ||
201 | struct attribute_set { | ||
202 | unsigned int members, max_members; | ||
203 | struct attribute_group group; | ||
204 | }; | ||
205 | |||
206 | /* Helpers */ | ||
207 | static int parse_strtoul(const char *buf, unsigned long max, | ||
208 | unsigned long *value); | ||
209 | |||
210 | /* Module */ | ||
211 | static int experimental; | ||
212 | static u32 dbg_level; | ||
213 | static int force_load; | ||
214 | static unsigned int hotkey_report_mode; | ||
215 | 232 | ||
216 | 233 | ||
217 | /**************************************************************************** | 234 | /**************************************************************************** |
218 | * Subdrivers | 235 | * Driver-wide structs and misc. variables |
219 | */ | 236 | */ |
220 | 237 | ||
221 | struct ibm_struct; | 238 | struct ibm_struct; |
@@ -297,39 +314,6 @@ struct thinkpad_id_data { | |||
297 | }; | 314 | }; |
298 | static struct thinkpad_id_data thinkpad_id; | 315 | static struct thinkpad_id_data thinkpad_id; |
299 | 316 | ||
300 | static LIST_HEAD(tpacpi_all_drivers); | ||
301 | |||
302 | MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh"); | ||
303 | MODULE_DESCRIPTION(IBM_DESC); | ||
304 | MODULE_VERSION(IBM_VERSION); | ||
305 | MODULE_LICENSE("GPL"); | ||
306 | |||
307 | /* Please remove this in year 2009 */ | ||
308 | MODULE_ALIAS("ibm_acpi"); | ||
309 | |||
310 | /* | ||
311 | * DMI matching for module autoloading | ||
312 | * | ||
313 | * See http://thinkwiki.org/wiki/List_of_DMI_IDs | ||
314 | * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads | ||
315 | * | ||
316 | * Only models listed in thinkwiki will be supported, so add yours | ||
317 | * if it is not there yet. | ||
318 | */ | ||
319 | #define IBM_BIOS_MODULE_ALIAS(__type) \ | ||
320 | MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") | ||
321 | |||
322 | /* Non-ancient thinkpads */ | ||
323 | MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); | ||
324 | MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); | ||
325 | |||
326 | /* Ancient thinkpad BIOSes have to be identified by | ||
327 | * BIOS type or model number, and there are far less | ||
328 | * BIOS types than model numbers... */ | ||
329 | IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); | ||
330 | IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); | ||
331 | IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); | ||
332 | |||
333 | #define __unused __attribute__ ((unused)) | 317 | #define __unused __attribute__ ((unused)) |
334 | 318 | ||
335 | static enum { | 319 | static enum { |
@@ -338,6 +322,9 @@ static enum { | |||
338 | TPACPI_LIFE_EXITING, | 322 | TPACPI_LIFE_EXITING, |
339 | } tpacpi_lifecycle; | 323 | } tpacpi_lifecycle; |
340 | 324 | ||
325 | static int experimental; | ||
326 | static u32 dbg_level; | ||
327 | |||
341 | /**************************************************************************** | 328 | /**************************************************************************** |
342 | **************************************************************************** | 329 | **************************************************************************** |
343 | * | 330 | * |
@@ -370,11 +357,6 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ | |||
370 | IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ | 357 | IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ |
371 | IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ | 358 | IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ |
372 | 359 | ||
373 | |||
374 | /************************************************************************* | ||
375 | * Misc ACPI handles | ||
376 | */ | ||
377 | |||
378 | IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ | 360 | IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ |
379 | "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ | 361 | "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ |
380 | "\\CMS", /* R40, R40e */ | 362 | "\\CMS", /* R40, R40e */ |
@@ -749,7 +731,7 @@ static struct platform_device *tpacpi_sensors_pdev; | |||
749 | static struct device *tpacpi_hwmon; | 731 | static struct device *tpacpi_hwmon; |
750 | static struct input_dev *tpacpi_inputdev; | 732 | static struct input_dev *tpacpi_inputdev; |
751 | static struct mutex tpacpi_inputdev_send_mutex; | 733 | static struct mutex tpacpi_inputdev_send_mutex; |
752 | 734 | static LIST_HEAD(tpacpi_all_drivers); | |
753 | 735 | ||
754 | static int tpacpi_resume_handler(struct platform_device *pdev) | 736 | static int tpacpi_resume_handler(struct platform_device *pdev) |
755 | { | 737 | { |
@@ -781,86 +763,14 @@ static struct platform_driver tpacpi_hwmon_pdriver = { | |||
781 | }; | 763 | }; |
782 | 764 | ||
783 | /************************************************************************* | 765 | /************************************************************************* |
784 | * thinkpad-acpi driver attributes | 766 | * sysfs support helpers |
785 | */ | 767 | */ |
786 | 768 | ||
787 | /* interface_version --------------------------------------------------- */ | 769 | struct attribute_set { |
788 | static ssize_t tpacpi_driver_interface_version_show( | 770 | unsigned int members, max_members; |
789 | struct device_driver *drv, | 771 | struct attribute_group group; |
790 | char *buf) | ||
791 | { | ||
792 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); | ||
793 | } | ||
794 | |||
795 | static DRIVER_ATTR(interface_version, S_IRUGO, | ||
796 | tpacpi_driver_interface_version_show, NULL); | ||
797 | |||
798 | /* debug_level --------------------------------------------------------- */ | ||
799 | static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, | ||
800 | char *buf) | ||
801 | { | ||
802 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); | ||
803 | } | ||
804 | |||
805 | static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, | ||
806 | const char *buf, size_t count) | ||
807 | { | ||
808 | unsigned long t; | ||
809 | |||
810 | if (parse_strtoul(buf, 0xffff, &t)) | ||
811 | return -EINVAL; | ||
812 | |||
813 | dbg_level = t; | ||
814 | |||
815 | return count; | ||
816 | } | ||
817 | |||
818 | static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, | ||
819 | tpacpi_driver_debug_show, tpacpi_driver_debug_store); | ||
820 | |||
821 | /* version ------------------------------------------------------------- */ | ||
822 | static ssize_t tpacpi_driver_version_show(struct device_driver *drv, | ||
823 | char *buf) | ||
824 | { | ||
825 | return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION); | ||
826 | } | ||
827 | |||
828 | static DRIVER_ATTR(version, S_IRUGO, | ||
829 | tpacpi_driver_version_show, NULL); | ||
830 | |||
831 | /* --------------------------------------------------------------------- */ | ||
832 | |||
833 | static struct driver_attribute* tpacpi_driver_attributes[] = { | ||
834 | &driver_attr_debug_level, &driver_attr_version, | ||
835 | &driver_attr_interface_version, | ||
836 | }; | 772 | }; |
837 | 773 | ||
838 | static int __init tpacpi_create_driver_attributes(struct device_driver *drv) | ||
839 | { | ||
840 | int i, res; | ||
841 | |||
842 | i = 0; | ||
843 | res = 0; | ||
844 | while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { | ||
845 | res = driver_create_file(drv, tpacpi_driver_attributes[i]); | ||
846 | i++; | ||
847 | } | ||
848 | |||
849 | return res; | ||
850 | } | ||
851 | |||
852 | static void tpacpi_remove_driver_attributes(struct device_driver *drv) | ||
853 | { | ||
854 | int i; | ||
855 | |||
856 | for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) | ||
857 | driver_remove_file(drv, tpacpi_driver_attributes[i]); | ||
858 | } | ||
859 | |||
860 | /************************************************************************* | ||
861 | * sysfs support helpers | ||
862 | */ | ||
863 | |||
864 | struct attribute_set_obj { | 774 | struct attribute_set_obj { |
865 | struct attribute_set s; | 775 | struct attribute_set s; |
866 | struct attribute *a; | 776 | struct attribute *a; |
@@ -945,6 +855,83 @@ static int parse_strtoul(const char *buf, | |||
945 | return 0; | 855 | return 0; |
946 | } | 856 | } |
947 | 857 | ||
858 | /************************************************************************* | ||
859 | * thinkpad-acpi driver attributes | ||
860 | */ | ||
861 | |||
862 | /* interface_version --------------------------------------------------- */ | ||
863 | static ssize_t tpacpi_driver_interface_version_show( | ||
864 | struct device_driver *drv, | ||
865 | char *buf) | ||
866 | { | ||
867 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION); | ||
868 | } | ||
869 | |||
870 | static DRIVER_ATTR(interface_version, S_IRUGO, | ||
871 | tpacpi_driver_interface_version_show, NULL); | ||
872 | |||
873 | /* debug_level --------------------------------------------------------- */ | ||
874 | static ssize_t tpacpi_driver_debug_show(struct device_driver *drv, | ||
875 | char *buf) | ||
876 | { | ||
877 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level); | ||
878 | } | ||
879 | |||
880 | static ssize_t tpacpi_driver_debug_store(struct device_driver *drv, | ||
881 | const char *buf, size_t count) | ||
882 | { | ||
883 | unsigned long t; | ||
884 | |||
885 | if (parse_strtoul(buf, 0xffff, &t)) | ||
886 | return -EINVAL; | ||
887 | |||
888 | dbg_level = t; | ||
889 | |||
890 | return count; | ||
891 | } | ||
892 | |||
893 | static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, | ||
894 | tpacpi_driver_debug_show, tpacpi_driver_debug_store); | ||
895 | |||
896 | /* version ------------------------------------------------------------- */ | ||
897 | static ssize_t tpacpi_driver_version_show(struct device_driver *drv, | ||
898 | char *buf) | ||
899 | { | ||
900 | return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION); | ||
901 | } | ||
902 | |||
903 | static DRIVER_ATTR(version, S_IRUGO, | ||
904 | tpacpi_driver_version_show, NULL); | ||
905 | |||
906 | /* --------------------------------------------------------------------- */ | ||
907 | |||
908 | static struct driver_attribute* tpacpi_driver_attributes[] = { | ||
909 | &driver_attr_debug_level, &driver_attr_version, | ||
910 | &driver_attr_interface_version, | ||
911 | }; | ||
912 | |||
913 | static int __init tpacpi_create_driver_attributes(struct device_driver *drv) | ||
914 | { | ||
915 | int i, res; | ||
916 | |||
917 | i = 0; | ||
918 | res = 0; | ||
919 | while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) { | ||
920 | res = driver_create_file(drv, tpacpi_driver_attributes[i]); | ||
921 | i++; | ||
922 | } | ||
923 | |||
924 | return res; | ||
925 | } | ||
926 | |||
927 | static void tpacpi_remove_driver_attributes(struct device_driver *drv) | ||
928 | { | ||
929 | int i; | ||
930 | |||
931 | for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) | ||
932 | driver_remove_file(drv, tpacpi_driver_attributes[i]); | ||
933 | } | ||
934 | |||
948 | /**************************************************************************** | 935 | /**************************************************************************** |
949 | **************************************************************************** | 936 | **************************************************************************** |
950 | * | 937 | * |
@@ -1094,6 +1081,8 @@ static u32 hotkey_all_mask; | |||
1094 | static u32 hotkey_reserved_mask; | 1081 | static u32 hotkey_reserved_mask; |
1095 | static u32 hotkey_mask; | 1082 | static u32 hotkey_mask; |
1096 | 1083 | ||
1084 | static unsigned int hotkey_report_mode; | ||
1085 | |||
1097 | static u16 *hotkey_keycode_map; | 1086 | static u16 *hotkey_keycode_map; |
1098 | 1087 | ||
1099 | static struct attribute_set *hotkey_dev_attributes; | 1088 | static struct attribute_set *hotkey_dev_attributes; |
@@ -3637,8 +3626,87 @@ struct ibm_thermal_sensors_struct { | |||
3637 | 3626 | ||
3638 | static enum thermal_access_mode thermal_read_mode; | 3627 | static enum thermal_access_mode thermal_read_mode; |
3639 | 3628 | ||
3640 | static int thermal_get_sensor(int idx, s32 *value); | 3629 | /* idx is zero-based */ |
3641 | static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); | 3630 | static int thermal_get_sensor(int idx, s32 *value) |
3631 | { | ||
3632 | int t; | ||
3633 | s8 tmp; | ||
3634 | char tmpi[5]; | ||
3635 | |||
3636 | t = TP_EC_THERMAL_TMP0; | ||
3637 | |||
3638 | switch (thermal_read_mode) { | ||
3639 | #if TPACPI_MAX_THERMAL_SENSORS >= 16 | ||
3640 | case TPACPI_THERMAL_TPEC_16: | ||
3641 | if (idx >= 8 && idx <= 15) { | ||
3642 | t = TP_EC_THERMAL_TMP8; | ||
3643 | idx -= 8; | ||
3644 | } | ||
3645 | /* fallthrough */ | ||
3646 | #endif | ||
3647 | case TPACPI_THERMAL_TPEC_8: | ||
3648 | if (idx <= 7) { | ||
3649 | if (!acpi_ec_read(t + idx, &tmp)) | ||
3650 | return -EIO; | ||
3651 | *value = tmp * 1000; | ||
3652 | return 0; | ||
3653 | } | ||
3654 | break; | ||
3655 | |||
3656 | case TPACPI_THERMAL_ACPI_UPDT: | ||
3657 | if (idx <= 7) { | ||
3658 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); | ||
3659 | if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) | ||
3660 | return -EIO; | ||
3661 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | ||
3662 | return -EIO; | ||
3663 | *value = (t - 2732) * 100; | ||
3664 | return 0; | ||
3665 | } | ||
3666 | break; | ||
3667 | |||
3668 | case TPACPI_THERMAL_ACPI_TMP07: | ||
3669 | if (idx <= 7) { | ||
3670 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); | ||
3671 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | ||
3672 | return -EIO; | ||
3673 | if (t > 127 || t < -127) | ||
3674 | t = TP_EC_THERMAL_TMP_NA; | ||
3675 | *value = t * 1000; | ||
3676 | return 0; | ||
3677 | } | ||
3678 | break; | ||
3679 | |||
3680 | case TPACPI_THERMAL_NONE: | ||
3681 | default: | ||
3682 | return -ENOSYS; | ||
3683 | } | ||
3684 | |||
3685 | return -EINVAL; | ||
3686 | } | ||
3687 | |||
3688 | static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) | ||
3689 | { | ||
3690 | int res, i; | ||
3691 | int n; | ||
3692 | |||
3693 | n = 8; | ||
3694 | i = 0; | ||
3695 | |||
3696 | if (!s) | ||
3697 | return -EINVAL; | ||
3698 | |||
3699 | if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) | ||
3700 | n = 16; | ||
3701 | |||
3702 | for(i = 0 ; i < n; i++) { | ||
3703 | res = thermal_get_sensor(i, &s->temp[i]); | ||
3704 | if (res) | ||
3705 | return res; | ||
3706 | } | ||
3707 | |||
3708 | return n; | ||
3709 | } | ||
3642 | 3710 | ||
3643 | /* sysfs temp##_input -------------------------------------------------- */ | 3711 | /* sysfs temp##_input -------------------------------------------------- */ |
3644 | 3712 | ||
@@ -3830,88 +3898,6 @@ static void thermal_exit(void) | |||
3830 | } | 3898 | } |
3831 | } | 3899 | } |
3832 | 3900 | ||
3833 | /* idx is zero-based */ | ||
3834 | static int thermal_get_sensor(int idx, s32 *value) | ||
3835 | { | ||
3836 | int t; | ||
3837 | s8 tmp; | ||
3838 | char tmpi[5]; | ||
3839 | |||
3840 | t = TP_EC_THERMAL_TMP0; | ||
3841 | |||
3842 | switch (thermal_read_mode) { | ||
3843 | #if TPACPI_MAX_THERMAL_SENSORS >= 16 | ||
3844 | case TPACPI_THERMAL_TPEC_16: | ||
3845 | if (idx >= 8 && idx <= 15) { | ||
3846 | t = TP_EC_THERMAL_TMP8; | ||
3847 | idx -= 8; | ||
3848 | } | ||
3849 | /* fallthrough */ | ||
3850 | #endif | ||
3851 | case TPACPI_THERMAL_TPEC_8: | ||
3852 | if (idx <= 7) { | ||
3853 | if (!acpi_ec_read(t + idx, &tmp)) | ||
3854 | return -EIO; | ||
3855 | *value = tmp * 1000; | ||
3856 | return 0; | ||
3857 | } | ||
3858 | break; | ||
3859 | |||
3860 | case TPACPI_THERMAL_ACPI_UPDT: | ||
3861 | if (idx <= 7) { | ||
3862 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); | ||
3863 | if (!acpi_evalf(ec_handle, NULL, "UPDT", "v")) | ||
3864 | return -EIO; | ||
3865 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | ||
3866 | return -EIO; | ||
3867 | *value = (t - 2732) * 100; | ||
3868 | return 0; | ||
3869 | } | ||
3870 | break; | ||
3871 | |||
3872 | case TPACPI_THERMAL_ACPI_TMP07: | ||
3873 | if (idx <= 7) { | ||
3874 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); | ||
3875 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | ||
3876 | return -EIO; | ||
3877 | if (t > 127 || t < -127) | ||
3878 | t = TP_EC_THERMAL_TMP_NA; | ||
3879 | *value = t * 1000; | ||
3880 | return 0; | ||
3881 | } | ||
3882 | break; | ||
3883 | |||
3884 | case TPACPI_THERMAL_NONE: | ||
3885 | default: | ||
3886 | return -ENOSYS; | ||
3887 | } | ||
3888 | |||
3889 | return -EINVAL; | ||
3890 | } | ||
3891 | |||
3892 | static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) | ||
3893 | { | ||
3894 | int res, i; | ||
3895 | int n; | ||
3896 | |||
3897 | n = 8; | ||
3898 | i = 0; | ||
3899 | |||
3900 | if (!s) | ||
3901 | return -EINVAL; | ||
3902 | |||
3903 | if (thermal_read_mode == TPACPI_THERMAL_TPEC_16) | ||
3904 | n = 16; | ||
3905 | |||
3906 | for(i = 0 ; i < n; i++) { | ||
3907 | res = thermal_get_sensor(i, &s->temp[i]); | ||
3908 | if (res) | ||
3909 | return res; | ||
3910 | } | ||
3911 | |||
3912 | return n; | ||
3913 | } | ||
3914 | |||
3915 | static int thermal_read(char *p) | 3901 | static int thermal_read(char *p) |
3916 | { | 3902 | { |
3917 | int len = 0; | 3903 | int len = 0; |
@@ -4021,16 +4007,103 @@ static int brightness_offset = 0x31; | |||
4021 | static int brightness_mode; | 4007 | static int brightness_mode; |
4022 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ | 4008 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ |
4023 | 4009 | ||
4024 | static int brightness_get(struct backlight_device *bd); | 4010 | static struct mutex brightness_mutex; |
4025 | static int brightness_set(int value); | 4011 | |
4026 | static int brightness_update_status(struct backlight_device *bd); | 4012 | /* |
4013 | * ThinkPads can read brightness from two places: EC 0x31, or | ||
4014 | * CMOS NVRAM byte 0x5E, bits 0-3. | ||
4015 | */ | ||
4016 | static int brightness_get(struct backlight_device *bd) | ||
4017 | { | ||
4018 | u8 lec = 0, lcmos = 0, level = 0; | ||
4019 | |||
4020 | if (brightness_mode & 1) { | ||
4021 | if (!acpi_ec_read(brightness_offset, &lec)) | ||
4022 | return -EIO; | ||
4023 | lec &= (tp_features.bright_16levels)? 0x0f : 0x07; | ||
4024 | level = lec; | ||
4025 | }; | ||
4026 | if (brightness_mode & 2) { | ||
4027 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | ||
4028 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | ||
4029 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | ||
4030 | lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; | ||
4031 | level = lcmos; | ||
4032 | } | ||
4033 | |||
4034 | if (brightness_mode == 3 && lec != lcmos) { | ||
4035 | printk(IBM_ERR | ||
4036 | "CMOS NVRAM (%u) and EC (%u) do not agree " | ||
4037 | "on display brightness level\n", | ||
4038 | (unsigned int) lcmos, | ||
4039 | (unsigned int) lec); | ||
4040 | return -EIO; | ||
4041 | } | ||
4042 | |||
4043 | return level; | ||
4044 | } | ||
4045 | |||
4046 | /* May return EINTR which can always be mapped to ERESTARTSYS */ | ||
4047 | static int brightness_set(int value) | ||
4048 | { | ||
4049 | int cmos_cmd, inc, i, res; | ||
4050 | int current_value; | ||
4051 | |||
4052 | if (value > ((tp_features.bright_16levels)? 15 : 7)) | ||
4053 | return -EINVAL; | ||
4054 | |||
4055 | res = mutex_lock_interruptible(&brightness_mutex); | ||
4056 | if (res < 0) | ||
4057 | return res; | ||
4058 | |||
4059 | current_value = brightness_get(NULL); | ||
4060 | if (current_value < 0) { | ||
4061 | res = current_value; | ||
4062 | goto errout; | ||
4063 | } | ||
4064 | |||
4065 | cmos_cmd = value > current_value ? | ||
4066 | TP_CMOS_BRIGHTNESS_UP : | ||
4067 | TP_CMOS_BRIGHTNESS_DOWN; | ||
4068 | inc = (value > current_value)? 1 : -1; | ||
4069 | |||
4070 | res = 0; | ||
4071 | for (i = current_value; i != value; i += inc) { | ||
4072 | if ((brightness_mode & 2) && | ||
4073 | issue_thinkpad_cmos_command(cmos_cmd)) { | ||
4074 | res = -EIO; | ||
4075 | goto errout; | ||
4076 | } | ||
4077 | if ((brightness_mode & 1) && | ||
4078 | !acpi_ec_write(brightness_offset, i + inc)) { | ||
4079 | res = -EIO; | ||
4080 | goto errout;; | ||
4081 | } | ||
4082 | } | ||
4083 | |||
4084 | errout: | ||
4085 | mutex_unlock(&brightness_mutex); | ||
4086 | return res; | ||
4087 | } | ||
4088 | |||
4089 | /* sysfs backlight class ----------------------------------------------- */ | ||
4090 | |||
4091 | static int brightness_update_status(struct backlight_device *bd) | ||
4092 | { | ||
4093 | /* it is the backlight class's job (caller) to handle | ||
4094 | * EINTR and other errors properly */ | ||
4095 | return brightness_set( | ||
4096 | (bd->props.fb_blank == FB_BLANK_UNBLANK && | ||
4097 | bd->props.power == FB_BLANK_UNBLANK) ? | ||
4098 | bd->props.brightness : 0); | ||
4099 | } | ||
4027 | 4100 | ||
4028 | static struct backlight_ops ibm_backlight_data = { | 4101 | static struct backlight_ops ibm_backlight_data = { |
4029 | .get_brightness = brightness_get, | 4102 | .get_brightness = brightness_get, |
4030 | .update_status = brightness_update_status, | 4103 | .update_status = brightness_update_status, |
4031 | }; | 4104 | }; |
4032 | 4105 | ||
4033 | static struct mutex brightness_mutex; | 4106 | /* --------------------------------------------------------------------- */ |
4034 | 4107 | ||
4035 | static int __init tpacpi_query_bcll_levels(acpi_handle handle) | 4108 | static int __init tpacpi_query_bcll_levels(acpi_handle handle) |
4036 | { | 4109 | { |
@@ -4196,93 +4269,6 @@ static void brightness_exit(void) | |||
4196 | } | 4269 | } |
4197 | } | 4270 | } |
4198 | 4271 | ||
4199 | static int brightness_update_status(struct backlight_device *bd) | ||
4200 | { | ||
4201 | /* it is the backlight class's job (caller) to handle | ||
4202 | * EINTR and other errors properly */ | ||
4203 | return brightness_set( | ||
4204 | (bd->props.fb_blank == FB_BLANK_UNBLANK && | ||
4205 | bd->props.power == FB_BLANK_UNBLANK) ? | ||
4206 | bd->props.brightness : 0); | ||
4207 | } | ||
4208 | |||
4209 | /* | ||
4210 | * ThinkPads can read brightness from two places: EC 0x31, or | ||
4211 | * CMOS NVRAM byte 0x5E, bits 0-3. | ||
4212 | */ | ||
4213 | static int brightness_get(struct backlight_device *bd) | ||
4214 | { | ||
4215 | u8 lec = 0, lcmos = 0, level = 0; | ||
4216 | |||
4217 | if (brightness_mode & 1) { | ||
4218 | if (!acpi_ec_read(brightness_offset, &lec)) | ||
4219 | return -EIO; | ||
4220 | lec &= (tp_features.bright_16levels)? 0x0f : 0x07; | ||
4221 | level = lec; | ||
4222 | }; | ||
4223 | if (brightness_mode & 2) { | ||
4224 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | ||
4225 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | ||
4226 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | ||
4227 | lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; | ||
4228 | level = lcmos; | ||
4229 | } | ||
4230 | |||
4231 | if (brightness_mode == 3 && lec != lcmos) { | ||
4232 | printk(IBM_ERR | ||
4233 | "CMOS NVRAM (%u) and EC (%u) do not agree " | ||
4234 | "on display brightness level\n", | ||
4235 | (unsigned int) lcmos, | ||
4236 | (unsigned int) lec); | ||
4237 | return -EIO; | ||
4238 | } | ||
4239 | |||
4240 | return level; | ||
4241 | } | ||
4242 | |||
4243 | /* May return EINTR which can always be mapped to ERESTARTSYS */ | ||
4244 | static int brightness_set(int value) | ||
4245 | { | ||
4246 | int cmos_cmd, inc, i, res; | ||
4247 | int current_value; | ||
4248 | |||
4249 | if (value > ((tp_features.bright_16levels)? 15 : 7)) | ||
4250 | return -EINVAL; | ||
4251 | |||
4252 | res = mutex_lock_interruptible(&brightness_mutex); | ||
4253 | if (res < 0) | ||
4254 | return res; | ||
4255 | |||
4256 | current_value = brightness_get(NULL); | ||
4257 | if (current_value < 0) { | ||
4258 | res = current_value; | ||
4259 | goto errout; | ||
4260 | } | ||
4261 | |||
4262 | cmos_cmd = value > current_value ? | ||
4263 | TP_CMOS_BRIGHTNESS_UP : | ||
4264 | TP_CMOS_BRIGHTNESS_DOWN; | ||
4265 | inc = (value > current_value)? 1 : -1; | ||
4266 | |||
4267 | res = 0; | ||
4268 | for (i = current_value; i != value; i += inc) { | ||
4269 | if ((brightness_mode & 2) && | ||
4270 | issue_thinkpad_cmos_command(cmos_cmd)) { | ||
4271 | res = -EIO; | ||
4272 | goto errout; | ||
4273 | } | ||
4274 | if ((brightness_mode & 1) && | ||
4275 | !acpi_ec_write(brightness_offset, i + inc)) { | ||
4276 | res = -EIO; | ||
4277 | goto errout;; | ||
4278 | } | ||
4279 | } | ||
4280 | |||
4281 | errout: | ||
4282 | mutex_unlock(&brightness_mutex); | ||
4283 | return res; | ||
4284 | } | ||
4285 | |||
4286 | static int brightness_read(char *p) | 4272 | static int brightness_read(char *p) |
4287 | { | 4273 | { |
4288 | int len = 0; | 4274 | int len = 0; |
@@ -4581,16 +4567,7 @@ static int fan_watchdog_maxinterval; | |||
4581 | 4567 | ||
4582 | static struct mutex fan_mutex; | 4568 | static struct mutex fan_mutex; |
4583 | 4569 | ||
4584 | static int fan_get_status(u8 *status); | ||
4585 | static int fan_get_status_safe(u8 *status); | ||
4586 | static int fan_get_speed(unsigned int *speed); | ||
4587 | static void fan_update_desired_level(u8 status); | ||
4588 | static void fan_watchdog_fire(struct work_struct *ignored); | 4570 | static void fan_watchdog_fire(struct work_struct *ignored); |
4589 | static void fan_watchdog_reset(void); | ||
4590 | static int fan_set_level(int level); | ||
4591 | static int fan_set_level_safe(int level); | ||
4592 | static int fan_set_enable(void); | ||
4593 | |||
4594 | static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); | 4571 | static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); |
4595 | 4572 | ||
4596 | IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ | 4573 | IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ |
@@ -4602,6 +4579,321 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ | |||
4602 | ); /* all others */ | 4579 | ); /* all others */ |
4603 | 4580 | ||
4604 | /* | 4581 | /* |
4582 | * Call with fan_mutex held | ||
4583 | */ | ||
4584 | static void fan_update_desired_level(u8 status) | ||
4585 | { | ||
4586 | if ((status & | ||
4587 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { | ||
4588 | if (status > 7) | ||
4589 | fan_control_desired_level = 7; | ||
4590 | else | ||
4591 | fan_control_desired_level = status; | ||
4592 | } | ||
4593 | } | ||
4594 | |||
4595 | static int fan_get_status(u8 *status) | ||
4596 | { | ||
4597 | u8 s; | ||
4598 | |||
4599 | /* TODO: | ||
4600 | * Add TPACPI_FAN_RD_ACPI_FANS ? */ | ||
4601 | |||
4602 | switch (fan_status_access_mode) { | ||
4603 | case TPACPI_FAN_RD_ACPI_GFAN: | ||
4604 | /* 570, 600e/x, 770e, 770x */ | ||
4605 | |||
4606 | if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) | ||
4607 | return -EIO; | ||
4608 | |||
4609 | if (likely(status)) | ||
4610 | *status = s & 0x07; | ||
4611 | |||
4612 | break; | ||
4613 | |||
4614 | case TPACPI_FAN_RD_TPEC: | ||
4615 | /* all except 570, 600e/x, 770e, 770x */ | ||
4616 | if (unlikely(!acpi_ec_read(fan_status_offset, &s))) | ||
4617 | return -EIO; | ||
4618 | |||
4619 | if (likely(status)) | ||
4620 | *status = s; | ||
4621 | |||
4622 | break; | ||
4623 | |||
4624 | default: | ||
4625 | return -ENXIO; | ||
4626 | } | ||
4627 | |||
4628 | return 0; | ||
4629 | } | ||
4630 | |||
4631 | static int fan_get_status_safe(u8 *status) | ||
4632 | { | ||
4633 | int rc; | ||
4634 | u8 s; | ||
4635 | |||
4636 | if (mutex_lock_interruptible(&fan_mutex)) | ||
4637 | return -ERESTARTSYS; | ||
4638 | rc = fan_get_status(&s); | ||
4639 | if (!rc) | ||
4640 | fan_update_desired_level(s); | ||
4641 | mutex_unlock(&fan_mutex); | ||
4642 | |||
4643 | if (status) | ||
4644 | *status = s; | ||
4645 | |||
4646 | return rc; | ||
4647 | } | ||
4648 | |||
4649 | static int fan_get_speed(unsigned int *speed) | ||
4650 | { | ||
4651 | u8 hi, lo; | ||
4652 | |||
4653 | switch (fan_status_access_mode) { | ||
4654 | case TPACPI_FAN_RD_TPEC: | ||
4655 | /* all except 570, 600e/x, 770e, 770x */ | ||
4656 | if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || | ||
4657 | !acpi_ec_read(fan_rpm_offset + 1, &hi))) | ||
4658 | return -EIO; | ||
4659 | |||
4660 | if (likely(speed)) | ||
4661 | *speed = (hi << 8) | lo; | ||
4662 | |||
4663 | break; | ||
4664 | |||
4665 | default: | ||
4666 | return -ENXIO; | ||
4667 | } | ||
4668 | |||
4669 | return 0; | ||
4670 | } | ||
4671 | |||
4672 | static int fan_set_level(int level) | ||
4673 | { | ||
4674 | if (!fan_control_allowed) | ||
4675 | return -EPERM; | ||
4676 | |||
4677 | switch (fan_control_access_mode) { | ||
4678 | case TPACPI_FAN_WR_ACPI_SFAN: | ||
4679 | if (level >= 0 && level <= 7) { | ||
4680 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) | ||
4681 | return -EIO; | ||
4682 | } else | ||
4683 | return -EINVAL; | ||
4684 | break; | ||
4685 | |||
4686 | case TPACPI_FAN_WR_ACPI_FANS: | ||
4687 | case TPACPI_FAN_WR_TPEC: | ||
4688 | if ((level != TP_EC_FAN_AUTO) && | ||
4689 | (level != TP_EC_FAN_FULLSPEED) && | ||
4690 | ((level < 0) || (level > 7))) | ||
4691 | return -EINVAL; | ||
4692 | |||
4693 | /* safety net should the EC not support AUTO | ||
4694 | * or FULLSPEED mode bits and just ignore them */ | ||
4695 | if (level & TP_EC_FAN_FULLSPEED) | ||
4696 | level |= 7; /* safety min speed 7 */ | ||
4697 | else if (level & TP_EC_FAN_FULLSPEED) | ||
4698 | level |= 4; /* safety min speed 4 */ | ||
4699 | |||
4700 | if (!acpi_ec_write(fan_status_offset, level)) | ||
4701 | return -EIO; | ||
4702 | else | ||
4703 | tp_features.fan_ctrl_status_undef = 0; | ||
4704 | break; | ||
4705 | |||
4706 | default: | ||
4707 | return -ENXIO; | ||
4708 | } | ||
4709 | return 0; | ||
4710 | } | ||
4711 | |||
4712 | static int fan_set_level_safe(int level) | ||
4713 | { | ||
4714 | int rc; | ||
4715 | |||
4716 | if (!fan_control_allowed) | ||
4717 | return -EPERM; | ||
4718 | |||
4719 | if (mutex_lock_interruptible(&fan_mutex)) | ||
4720 | return -ERESTARTSYS; | ||
4721 | |||
4722 | if (level == TPACPI_FAN_LAST_LEVEL) | ||
4723 | level = fan_control_desired_level; | ||
4724 | |||
4725 | rc = fan_set_level(level); | ||
4726 | if (!rc) | ||
4727 | fan_update_desired_level(level); | ||
4728 | |||
4729 | mutex_unlock(&fan_mutex); | ||
4730 | return rc; | ||
4731 | } | ||
4732 | |||
4733 | static int fan_set_enable(void) | ||
4734 | { | ||
4735 | u8 s; | ||
4736 | int rc; | ||
4737 | |||
4738 | if (!fan_control_allowed) | ||
4739 | return -EPERM; | ||
4740 | |||
4741 | if (mutex_lock_interruptible(&fan_mutex)) | ||
4742 | return -ERESTARTSYS; | ||
4743 | |||
4744 | switch (fan_control_access_mode) { | ||
4745 | case TPACPI_FAN_WR_ACPI_FANS: | ||
4746 | case TPACPI_FAN_WR_TPEC: | ||
4747 | rc = fan_get_status(&s); | ||
4748 | if (rc < 0) | ||
4749 | break; | ||
4750 | |||
4751 | /* Don't go out of emergency fan mode */ | ||
4752 | if (s != 7) { | ||
4753 | s &= 0x07; | ||
4754 | s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */ | ||
4755 | } | ||
4756 | |||
4757 | if (!acpi_ec_write(fan_status_offset, s)) | ||
4758 | rc = -EIO; | ||
4759 | else { | ||
4760 | tp_features.fan_ctrl_status_undef = 0; | ||
4761 | rc = 0; | ||
4762 | } | ||
4763 | break; | ||
4764 | |||
4765 | case TPACPI_FAN_WR_ACPI_SFAN: | ||
4766 | rc = fan_get_status(&s); | ||
4767 | if (rc < 0) | ||
4768 | break; | ||
4769 | |||
4770 | s &= 0x07; | ||
4771 | |||
4772 | /* Set fan to at least level 4 */ | ||
4773 | s |= 4; | ||
4774 | |||
4775 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) | ||
4776 | rc= -EIO; | ||
4777 | else | ||
4778 | rc = 0; | ||
4779 | break; | ||
4780 | |||
4781 | default: | ||
4782 | rc = -ENXIO; | ||
4783 | } | ||
4784 | |||
4785 | mutex_unlock(&fan_mutex); | ||
4786 | return rc; | ||
4787 | } | ||
4788 | |||
4789 | static int fan_set_disable(void) | ||
4790 | { | ||
4791 | int rc; | ||
4792 | |||
4793 | if (!fan_control_allowed) | ||
4794 | return -EPERM; | ||
4795 | |||
4796 | if (mutex_lock_interruptible(&fan_mutex)) | ||
4797 | return -ERESTARTSYS; | ||
4798 | |||
4799 | rc = 0; | ||
4800 | switch (fan_control_access_mode) { | ||
4801 | case TPACPI_FAN_WR_ACPI_FANS: | ||
4802 | case TPACPI_FAN_WR_TPEC: | ||
4803 | if (!acpi_ec_write(fan_status_offset, 0x00)) | ||
4804 | rc = -EIO; | ||
4805 | else { | ||
4806 | fan_control_desired_level = 0; | ||
4807 | tp_features.fan_ctrl_status_undef = 0; | ||
4808 | } | ||
4809 | break; | ||
4810 | |||
4811 | case TPACPI_FAN_WR_ACPI_SFAN: | ||
4812 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) | ||
4813 | rc = -EIO; | ||
4814 | else | ||
4815 | fan_control_desired_level = 0; | ||
4816 | break; | ||
4817 | |||
4818 | default: | ||
4819 | rc = -ENXIO; | ||
4820 | } | ||
4821 | |||
4822 | |||
4823 | mutex_unlock(&fan_mutex); | ||
4824 | return rc; | ||
4825 | } | ||
4826 | |||
4827 | static int fan_set_speed(int speed) | ||
4828 | { | ||
4829 | int rc; | ||
4830 | |||
4831 | if (!fan_control_allowed) | ||
4832 | return -EPERM; | ||
4833 | |||
4834 | if (mutex_lock_interruptible(&fan_mutex)) | ||
4835 | return -ERESTARTSYS; | ||
4836 | |||
4837 | rc = 0; | ||
4838 | switch (fan_control_access_mode) { | ||
4839 | case TPACPI_FAN_WR_ACPI_FANS: | ||
4840 | if (speed >= 0 && speed <= 65535) { | ||
4841 | if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", | ||
4842 | speed, speed, speed)) | ||
4843 | rc = -EIO; | ||
4844 | } else | ||
4845 | rc = -EINVAL; | ||
4846 | break; | ||
4847 | |||
4848 | default: | ||
4849 | rc = -ENXIO; | ||
4850 | } | ||
4851 | |||
4852 | mutex_unlock(&fan_mutex); | ||
4853 | return rc; | ||
4854 | } | ||
4855 | |||
4856 | static void fan_watchdog_reset(void) | ||
4857 | { | ||
4858 | static int fan_watchdog_active; | ||
4859 | |||
4860 | if (fan_control_access_mode == TPACPI_FAN_WR_NONE) | ||
4861 | return; | ||
4862 | |||
4863 | if (fan_watchdog_active) | ||
4864 | cancel_delayed_work(&fan_watchdog_task); | ||
4865 | |||
4866 | if (fan_watchdog_maxinterval > 0 && | ||
4867 | tpacpi_lifecycle != TPACPI_LIFE_EXITING) { | ||
4868 | fan_watchdog_active = 1; | ||
4869 | if (!schedule_delayed_work(&fan_watchdog_task, | ||
4870 | msecs_to_jiffies(fan_watchdog_maxinterval | ||
4871 | * 1000))) { | ||
4872 | printk(IBM_ERR "failed to schedule the fan watchdog, " | ||
4873 | "watchdog will not trigger\n"); | ||
4874 | } | ||
4875 | } else | ||
4876 | fan_watchdog_active = 0; | ||
4877 | } | ||
4878 | |||
4879 | static void fan_watchdog_fire(struct work_struct *ignored) | ||
4880 | { | ||
4881 | int rc; | ||
4882 | |||
4883 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | ||
4884 | return; | ||
4885 | |||
4886 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); | ||
4887 | rc = fan_set_enable(); | ||
4888 | if (rc < 0) { | ||
4889 | printk(IBM_ERR "fan watchdog: error %d while enabling fan, " | ||
4890 | "will try again later...\n", -rc); | ||
4891 | /* reschedule for later */ | ||
4892 | fan_watchdog_reset(); | ||
4893 | } | ||
4894 | } | ||
4895 | |||
4896 | /* | ||
4605 | * SYSFS fan layout: hwmon compatible (device) | 4897 | * SYSFS fan layout: hwmon compatible (device) |
4606 | * | 4898 | * |
4607 | * pwm*_enable: | 4899 | * pwm*_enable: |
@@ -4936,74 +5228,6 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
4936 | return 1; | 5228 | return 1; |
4937 | } | 5229 | } |
4938 | 5230 | ||
4939 | /* | ||
4940 | * Call with fan_mutex held | ||
4941 | */ | ||
4942 | static void fan_update_desired_level(u8 status) | ||
4943 | { | ||
4944 | if ((status & | ||
4945 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { | ||
4946 | if (status > 7) | ||
4947 | fan_control_desired_level = 7; | ||
4948 | else | ||
4949 | fan_control_desired_level = status; | ||
4950 | } | ||
4951 | } | ||
4952 | |||
4953 | static int fan_get_status(u8 *status) | ||
4954 | { | ||
4955 | u8 s; | ||
4956 | |||
4957 | /* TODO: | ||
4958 | * Add TPACPI_FAN_RD_ACPI_FANS ? */ | ||
4959 | |||
4960 | switch (fan_status_access_mode) { | ||
4961 | case TPACPI_FAN_RD_ACPI_GFAN: | ||
4962 | /* 570, 600e/x, 770e, 770x */ | ||
4963 | |||
4964 | if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d"))) | ||
4965 | return -EIO; | ||
4966 | |||
4967 | if (likely(status)) | ||
4968 | *status = s & 0x07; | ||
4969 | |||
4970 | break; | ||
4971 | |||
4972 | case TPACPI_FAN_RD_TPEC: | ||
4973 | /* all except 570, 600e/x, 770e, 770x */ | ||
4974 | if (unlikely(!acpi_ec_read(fan_status_offset, &s))) | ||
4975 | return -EIO; | ||
4976 | |||
4977 | if (likely(status)) | ||
4978 | *status = s; | ||
4979 | |||
4980 | break; | ||
4981 | |||
4982 | default: | ||
4983 | return -ENXIO; | ||
4984 | } | ||
4985 | |||
4986 | return 0; | ||
4987 | } | ||
4988 | |||
4989 | static int fan_get_status_safe(u8 *status) | ||
4990 | { | ||
4991 | int rc; | ||
4992 | u8 s; | ||
4993 | |||
4994 | if (mutex_lock_interruptible(&fan_mutex)) | ||
4995 | return -ERESTARTSYS; | ||
4996 | rc = fan_get_status(&s); | ||
4997 | if (!rc) | ||
4998 | fan_update_desired_level(s); | ||
4999 | mutex_unlock(&fan_mutex); | ||
5000 | |||
5001 | if (status) | ||
5002 | *status = s; | ||
5003 | |||
5004 | return rc; | ||
5005 | } | ||
5006 | |||
5007 | static void fan_exit(void) | 5231 | static void fan_exit(void) |
5008 | { | 5232 | { |
5009 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); | 5233 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); |
@@ -5016,253 +5240,6 @@ static void fan_exit(void) | |||
5016 | flush_scheduled_work(); | 5240 | flush_scheduled_work(); |
5017 | } | 5241 | } |
5018 | 5242 | ||
5019 | static int fan_get_speed(unsigned int *speed) | ||
5020 | { | ||
5021 | u8 hi, lo; | ||
5022 | |||
5023 | switch (fan_status_access_mode) { | ||
5024 | case TPACPI_FAN_RD_TPEC: | ||
5025 | /* all except 570, 600e/x, 770e, 770x */ | ||
5026 | if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) || | ||
5027 | !acpi_ec_read(fan_rpm_offset + 1, &hi))) | ||
5028 | return -EIO; | ||
5029 | |||
5030 | if (likely(speed)) | ||
5031 | *speed = (hi << 8) | lo; | ||
5032 | |||
5033 | break; | ||
5034 | |||
5035 | default: | ||
5036 | return -ENXIO; | ||
5037 | } | ||
5038 | |||
5039 | return 0; | ||
5040 | } | ||
5041 | |||
5042 | static void fan_watchdog_fire(struct work_struct *ignored) | ||
5043 | { | ||
5044 | int rc; | ||
5045 | |||
5046 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | ||
5047 | return; | ||
5048 | |||
5049 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); | ||
5050 | rc = fan_set_enable(); | ||
5051 | if (rc < 0) { | ||
5052 | printk(IBM_ERR "fan watchdog: error %d while enabling fan, " | ||
5053 | "will try again later...\n", -rc); | ||
5054 | /* reschedule for later */ | ||
5055 | fan_watchdog_reset(); | ||
5056 | } | ||
5057 | } | ||
5058 | |||
5059 | static void fan_watchdog_reset(void) | ||
5060 | { | ||
5061 | static int fan_watchdog_active; | ||
5062 | |||
5063 | if (fan_control_access_mode == TPACPI_FAN_WR_NONE) | ||
5064 | return; | ||
5065 | |||
5066 | if (fan_watchdog_active) | ||
5067 | cancel_delayed_work(&fan_watchdog_task); | ||
5068 | |||
5069 | if (fan_watchdog_maxinterval > 0 && | ||
5070 | tpacpi_lifecycle != TPACPI_LIFE_EXITING) { | ||
5071 | fan_watchdog_active = 1; | ||
5072 | if (!schedule_delayed_work(&fan_watchdog_task, | ||
5073 | msecs_to_jiffies(fan_watchdog_maxinterval | ||
5074 | * 1000))) { | ||
5075 | printk(IBM_ERR "failed to schedule the fan watchdog, " | ||
5076 | "watchdog will not trigger\n"); | ||
5077 | } | ||
5078 | } else | ||
5079 | fan_watchdog_active = 0; | ||
5080 | } | ||
5081 | |||
5082 | static int fan_set_level(int level) | ||
5083 | { | ||
5084 | if (!fan_control_allowed) | ||
5085 | return -EPERM; | ||
5086 | |||
5087 | switch (fan_control_access_mode) { | ||
5088 | case TPACPI_FAN_WR_ACPI_SFAN: | ||
5089 | if (level >= 0 && level <= 7) { | ||
5090 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) | ||
5091 | return -EIO; | ||
5092 | } else | ||
5093 | return -EINVAL; | ||
5094 | break; | ||
5095 | |||
5096 | case TPACPI_FAN_WR_ACPI_FANS: | ||
5097 | case TPACPI_FAN_WR_TPEC: | ||
5098 | if ((level != TP_EC_FAN_AUTO) && | ||
5099 | (level != TP_EC_FAN_FULLSPEED) && | ||
5100 | ((level < 0) || (level > 7))) | ||
5101 | return -EINVAL; | ||
5102 | |||
5103 | /* safety net should the EC not support AUTO | ||
5104 | * or FULLSPEED mode bits and just ignore them */ | ||
5105 | if (level & TP_EC_FAN_FULLSPEED) | ||
5106 | level |= 7; /* safety min speed 7 */ | ||
5107 | else if (level & TP_EC_FAN_FULLSPEED) | ||
5108 | level |= 4; /* safety min speed 4 */ | ||
5109 | |||
5110 | if (!acpi_ec_write(fan_status_offset, level)) | ||
5111 | return -EIO; | ||
5112 | else | ||
5113 | tp_features.fan_ctrl_status_undef = 0; | ||
5114 | break; | ||
5115 | |||
5116 | default: | ||
5117 | return -ENXIO; | ||
5118 | } | ||
5119 | return 0; | ||
5120 | } | ||
5121 | |||
5122 | static int fan_set_level_safe(int level) | ||
5123 | { | ||
5124 | int rc; | ||
5125 | |||
5126 | if (!fan_control_allowed) | ||
5127 | return -EPERM; | ||
5128 | |||
5129 | if (mutex_lock_interruptible(&fan_mutex)) | ||
5130 | return -ERESTARTSYS; | ||
5131 | |||
5132 | if (level == TPACPI_FAN_LAST_LEVEL) | ||
5133 | level = fan_control_desired_level; | ||
5134 | |||
5135 | rc = fan_set_level(level); | ||
5136 | if (!rc) | ||
5137 | fan_update_desired_level(level); | ||
5138 | |||
5139 | mutex_unlock(&fan_mutex); | ||
5140 | return rc; | ||
5141 | } | ||
5142 | |||
5143 | static int fan_set_enable(void) | ||
5144 | { | ||
5145 | u8 s; | ||
5146 | int rc; | ||
5147 | |||
5148 | if (!fan_control_allowed) | ||
5149 | return -EPERM; | ||
5150 | |||
5151 | if (mutex_lock_interruptible(&fan_mutex)) | ||
5152 | return -ERESTARTSYS; | ||
5153 | |||
5154 | switch (fan_control_access_mode) { | ||
5155 | case TPACPI_FAN_WR_ACPI_FANS: | ||
5156 | case TPACPI_FAN_WR_TPEC: | ||
5157 | rc = fan_get_status(&s); | ||
5158 | if (rc < 0) | ||
5159 | break; | ||
5160 | |||
5161 | /* Don't go out of emergency fan mode */ | ||
5162 | if (s != 7) { | ||
5163 | s &= 0x07; | ||
5164 | s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */ | ||
5165 | } | ||
5166 | |||
5167 | if (!acpi_ec_write(fan_status_offset, s)) | ||
5168 | rc = -EIO; | ||
5169 | else { | ||
5170 | tp_features.fan_ctrl_status_undef = 0; | ||
5171 | rc = 0; | ||
5172 | } | ||
5173 | break; | ||
5174 | |||
5175 | case TPACPI_FAN_WR_ACPI_SFAN: | ||
5176 | rc = fan_get_status(&s); | ||
5177 | if (rc < 0) | ||
5178 | break; | ||
5179 | |||
5180 | s &= 0x07; | ||
5181 | |||
5182 | /* Set fan to at least level 4 */ | ||
5183 | s |= 4; | ||
5184 | |||
5185 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s)) | ||
5186 | rc= -EIO; | ||
5187 | else | ||
5188 | rc = 0; | ||
5189 | break; | ||
5190 | |||
5191 | default: | ||
5192 | rc = -ENXIO; | ||
5193 | } | ||
5194 | |||
5195 | mutex_unlock(&fan_mutex); | ||
5196 | return rc; | ||
5197 | } | ||
5198 | |||
5199 | static int fan_set_disable(void) | ||
5200 | { | ||
5201 | int rc; | ||
5202 | |||
5203 | if (!fan_control_allowed) | ||
5204 | return -EPERM; | ||
5205 | |||
5206 | if (mutex_lock_interruptible(&fan_mutex)) | ||
5207 | return -ERESTARTSYS; | ||
5208 | |||
5209 | rc = 0; | ||
5210 | switch (fan_control_access_mode) { | ||
5211 | case TPACPI_FAN_WR_ACPI_FANS: | ||
5212 | case TPACPI_FAN_WR_TPEC: | ||
5213 | if (!acpi_ec_write(fan_status_offset, 0x00)) | ||
5214 | rc = -EIO; | ||
5215 | else { | ||
5216 | fan_control_desired_level = 0; | ||
5217 | tp_features.fan_ctrl_status_undef = 0; | ||
5218 | } | ||
5219 | break; | ||
5220 | |||
5221 | case TPACPI_FAN_WR_ACPI_SFAN: | ||
5222 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) | ||
5223 | rc = -EIO; | ||
5224 | else | ||
5225 | fan_control_desired_level = 0; | ||
5226 | break; | ||
5227 | |||
5228 | default: | ||
5229 | rc = -ENXIO; | ||
5230 | } | ||
5231 | |||
5232 | |||
5233 | mutex_unlock(&fan_mutex); | ||
5234 | return rc; | ||
5235 | } | ||
5236 | |||
5237 | static int fan_set_speed(int speed) | ||
5238 | { | ||
5239 | int rc; | ||
5240 | |||
5241 | if (!fan_control_allowed) | ||
5242 | return -EPERM; | ||
5243 | |||
5244 | if (mutex_lock_interruptible(&fan_mutex)) | ||
5245 | return -ERESTARTSYS; | ||
5246 | |||
5247 | rc = 0; | ||
5248 | switch (fan_control_access_mode) { | ||
5249 | case TPACPI_FAN_WR_ACPI_FANS: | ||
5250 | if (speed >= 0 && speed <= 65535) { | ||
5251 | if (!acpi_evalf(fans_handle, NULL, NULL, "vddd", | ||
5252 | speed, speed, speed)) | ||
5253 | rc = -EIO; | ||
5254 | } else | ||
5255 | rc = -EINVAL; | ||
5256 | break; | ||
5257 | |||
5258 | default: | ||
5259 | rc = -ENXIO; | ||
5260 | } | ||
5261 | |||
5262 | mutex_unlock(&fan_mutex); | ||
5263 | return rc; | ||
5264 | } | ||
5265 | |||
5266 | static int fan_read(char *p) | 5243 | static int fan_read(char *p) |
5267 | { | 5244 | { |
5268 | int len = 0; | 5245 | int len = 0; |
@@ -5473,11 +5450,12 @@ static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = | |||
5473 | /* /proc support */ | 5450 | /* /proc support */ |
5474 | static struct proc_dir_entry *proc_dir; | 5451 | static struct proc_dir_entry *proc_dir; |
5475 | 5452 | ||
5476 | |||
5477 | /* | 5453 | /* |
5478 | * Module and infrastructure proble, init and exit handling | 5454 | * Module and infrastructure proble, init and exit handling |
5479 | */ | 5455 | */ |
5480 | 5456 | ||
5457 | static int force_load; | ||
5458 | |||
5481 | #ifdef CONFIG_THINKPAD_ACPI_DEBUG | 5459 | #ifdef CONFIG_THINKPAD_ACPI_DEBUG |
5482 | static const char * __init str_supported(int is_supported) | 5460 | static const char * __init str_supported(int is_supported) |
5483 | { | 5461 | { |
@@ -5487,7 +5465,47 @@ static const char * __init str_supported(int is_supported) | |||
5487 | } | 5465 | } |
5488 | #endif /* CONFIG_THINKPAD_ACPI_DEBUG */ | 5466 | #endif /* CONFIG_THINKPAD_ACPI_DEBUG */ |
5489 | 5467 | ||
5490 | static void ibm_exit(struct ibm_struct *ibm); | 5468 | static void ibm_exit(struct ibm_struct *ibm) |
5469 | { | ||
5470 | dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); | ||
5471 | |||
5472 | list_del_init(&ibm->all_drivers); | ||
5473 | |||
5474 | if (ibm->flags.acpi_notify_installed) { | ||
5475 | dbg_printk(TPACPI_DBG_EXIT, | ||
5476 | "%s: acpi_remove_notify_handler\n", ibm->name); | ||
5477 | BUG_ON(!ibm->acpi); | ||
5478 | acpi_remove_notify_handler(*ibm->acpi->handle, | ||
5479 | ibm->acpi->type, | ||
5480 | dispatch_acpi_notify); | ||
5481 | ibm->flags.acpi_notify_installed = 0; | ||
5482 | ibm->flags.acpi_notify_installed = 0; | ||
5483 | } | ||
5484 | |||
5485 | if (ibm->flags.proc_created) { | ||
5486 | dbg_printk(TPACPI_DBG_EXIT, | ||
5487 | "%s: remove_proc_entry\n", ibm->name); | ||
5488 | remove_proc_entry(ibm->name, proc_dir); | ||
5489 | ibm->flags.proc_created = 0; | ||
5490 | } | ||
5491 | |||
5492 | if (ibm->flags.acpi_driver_registered) { | ||
5493 | dbg_printk(TPACPI_DBG_EXIT, | ||
5494 | "%s: acpi_bus_unregister_driver\n", ibm->name); | ||
5495 | BUG_ON(!ibm->acpi); | ||
5496 | acpi_bus_unregister_driver(ibm->acpi->driver); | ||
5497 | kfree(ibm->acpi->driver); | ||
5498 | ibm->acpi->driver = NULL; | ||
5499 | ibm->flags.acpi_driver_registered = 0; | ||
5500 | } | ||
5501 | |||
5502 | if (ibm->flags.init_called && ibm->exit) { | ||
5503 | ibm->exit(); | ||
5504 | ibm->flags.init_called = 0; | ||
5505 | } | ||
5506 | |||
5507 | dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); | ||
5508 | } | ||
5491 | 5509 | ||
5492 | static int __init ibm_init(struct ibm_init_struct *iibm) | 5510 | static int __init ibm_init(struct ibm_init_struct *iibm) |
5493 | { | 5511 | { |
@@ -5569,48 +5587,6 @@ err_out: | |||
5569 | return (ret < 0)? ret : 0; | 5587 | return (ret < 0)? ret : 0; |
5570 | } | 5588 | } |
5571 | 5589 | ||
5572 | static void ibm_exit(struct ibm_struct *ibm) | ||
5573 | { | ||
5574 | dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name); | ||
5575 | |||
5576 | list_del_init(&ibm->all_drivers); | ||
5577 | |||
5578 | if (ibm->flags.acpi_notify_installed) { | ||
5579 | dbg_printk(TPACPI_DBG_EXIT, | ||
5580 | "%s: acpi_remove_notify_handler\n", ibm->name); | ||
5581 | BUG_ON(!ibm->acpi); | ||
5582 | acpi_remove_notify_handler(*ibm->acpi->handle, | ||
5583 | ibm->acpi->type, | ||
5584 | dispatch_acpi_notify); | ||
5585 | ibm->flags.acpi_notify_installed = 0; | ||
5586 | ibm->flags.acpi_notify_installed = 0; | ||
5587 | } | ||
5588 | |||
5589 | if (ibm->flags.proc_created) { | ||
5590 | dbg_printk(TPACPI_DBG_EXIT, | ||
5591 | "%s: remove_proc_entry\n", ibm->name); | ||
5592 | remove_proc_entry(ibm->name, proc_dir); | ||
5593 | ibm->flags.proc_created = 0; | ||
5594 | } | ||
5595 | |||
5596 | if (ibm->flags.acpi_driver_registered) { | ||
5597 | dbg_printk(TPACPI_DBG_EXIT, | ||
5598 | "%s: acpi_bus_unregister_driver\n", ibm->name); | ||
5599 | BUG_ON(!ibm->acpi); | ||
5600 | acpi_bus_unregister_driver(ibm->acpi->driver); | ||
5601 | kfree(ibm->acpi->driver); | ||
5602 | ibm->acpi->driver = NULL; | ||
5603 | ibm->flags.acpi_driver_registered = 0; | ||
5604 | } | ||
5605 | |||
5606 | if (ibm->flags.init_called && ibm->exit) { | ||
5607 | ibm->exit(); | ||
5608 | ibm->flags.init_called = 0; | ||
5609 | } | ||
5610 | |||
5611 | dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name); | ||
5612 | } | ||
5613 | |||
5614 | /* Probing */ | 5590 | /* Probing */ |
5615 | 5591 | ||
5616 | static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) | 5592 | static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) |
@@ -5839,7 +5815,57 @@ IBM_PARAM(brightness); | |||
5839 | IBM_PARAM(volume); | 5815 | IBM_PARAM(volume); |
5840 | IBM_PARAM(fan); | 5816 | IBM_PARAM(fan); |
5841 | 5817 | ||
5842 | static void thinkpad_acpi_module_exit(void); | 5818 | static void thinkpad_acpi_module_exit(void) |
5819 | { | ||
5820 | struct ibm_struct *ibm, *itmp; | ||
5821 | |||
5822 | tpacpi_lifecycle = TPACPI_LIFE_EXITING; | ||
5823 | |||
5824 | list_for_each_entry_safe_reverse(ibm, itmp, | ||
5825 | &tpacpi_all_drivers, | ||
5826 | all_drivers) { | ||
5827 | ibm_exit(ibm); | ||
5828 | } | ||
5829 | |||
5830 | dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); | ||
5831 | |||
5832 | if (tpacpi_inputdev) { | ||
5833 | if (tp_features.input_device_registered) | ||
5834 | input_unregister_device(tpacpi_inputdev); | ||
5835 | else | ||
5836 | input_free_device(tpacpi_inputdev); | ||
5837 | } | ||
5838 | |||
5839 | if (tpacpi_hwmon) | ||
5840 | hwmon_device_unregister(tpacpi_hwmon); | ||
5841 | |||
5842 | if (tp_features.sensors_pdev_attrs_registered) | ||
5843 | device_remove_file(&tpacpi_sensors_pdev->dev, | ||
5844 | &dev_attr_thinkpad_acpi_pdev_name); | ||
5845 | if (tpacpi_sensors_pdev) | ||
5846 | platform_device_unregister(tpacpi_sensors_pdev); | ||
5847 | if (tpacpi_pdev) | ||
5848 | platform_device_unregister(tpacpi_pdev); | ||
5849 | |||
5850 | if (tp_features.sensors_pdrv_attrs_registered) | ||
5851 | tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); | ||
5852 | if (tp_features.platform_drv_attrs_registered) | ||
5853 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); | ||
5854 | |||
5855 | if (tp_features.sensors_pdrv_registered) | ||
5856 | platform_driver_unregister(&tpacpi_hwmon_pdriver); | ||
5857 | |||
5858 | if (tp_features.platform_drv_registered) | ||
5859 | platform_driver_unregister(&tpacpi_pdriver); | ||
5860 | |||
5861 | if (proc_dir) | ||
5862 | remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); | ||
5863 | |||
5864 | kfree(thinkpad_id.bios_version_str); | ||
5865 | kfree(thinkpad_id.ec_version_str); | ||
5866 | kfree(thinkpad_id.model_str); | ||
5867 | } | ||
5868 | |||
5843 | 5869 | ||
5844 | static int __init thinkpad_acpi_module_init(void) | 5870 | static int __init thinkpad_acpi_module_init(void) |
5845 | { | 5871 | { |
@@ -5978,56 +6004,5 @@ static int __init thinkpad_acpi_module_init(void) | |||
5978 | return 0; | 6004 | return 0; |
5979 | } | 6005 | } |
5980 | 6006 | ||
5981 | static void thinkpad_acpi_module_exit(void) | ||
5982 | { | ||
5983 | struct ibm_struct *ibm, *itmp; | ||
5984 | |||
5985 | tpacpi_lifecycle = TPACPI_LIFE_EXITING; | ||
5986 | |||
5987 | list_for_each_entry_safe_reverse(ibm, itmp, | ||
5988 | &tpacpi_all_drivers, | ||
5989 | all_drivers) { | ||
5990 | ibm_exit(ibm); | ||
5991 | } | ||
5992 | |||
5993 | dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); | ||
5994 | |||
5995 | if (tpacpi_inputdev) { | ||
5996 | if (tp_features.input_device_registered) | ||
5997 | input_unregister_device(tpacpi_inputdev); | ||
5998 | else | ||
5999 | input_free_device(tpacpi_inputdev); | ||
6000 | } | ||
6001 | |||
6002 | if (tpacpi_hwmon) | ||
6003 | hwmon_device_unregister(tpacpi_hwmon); | ||
6004 | |||
6005 | if (tp_features.sensors_pdev_attrs_registered) | ||
6006 | device_remove_file(&tpacpi_sensors_pdev->dev, | ||
6007 | &dev_attr_thinkpad_acpi_pdev_name); | ||
6008 | if (tpacpi_sensors_pdev) | ||
6009 | platform_device_unregister(tpacpi_sensors_pdev); | ||
6010 | if (tpacpi_pdev) | ||
6011 | platform_device_unregister(tpacpi_pdev); | ||
6012 | |||
6013 | if (tp_features.sensors_pdrv_attrs_registered) | ||
6014 | tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); | ||
6015 | if (tp_features.platform_drv_attrs_registered) | ||
6016 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); | ||
6017 | |||
6018 | if (tp_features.sensors_pdrv_registered) | ||
6019 | platform_driver_unregister(&tpacpi_hwmon_pdriver); | ||
6020 | |||
6021 | if (tp_features.platform_drv_registered) | ||
6022 | platform_driver_unregister(&tpacpi_pdriver); | ||
6023 | |||
6024 | if (proc_dir) | ||
6025 | remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); | ||
6026 | |||
6027 | kfree(thinkpad_id.bios_version_str); | ||
6028 | kfree(thinkpad_id.ec_version_str); | ||
6029 | kfree(thinkpad_id.model_str); | ||
6030 | } | ||
6031 | |||
6032 | module_init(thinkpad_acpi_module_init); | 6007 | module_init(thinkpad_acpi_module_init); |
6033 | module_exit(thinkpad_acpi_module_exit); | 6008 | module_exit(thinkpad_acpi_module_exit); |