aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/thinkpad_acpi.c1493
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
176MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
177MODULE_DESCRIPTION(IBM_DESC);
178MODULE_VERSION(IBM_VERSION);
179MODULE_LICENSE("GPL");
180
181/* Please remove this in year 2009 */
182MODULE_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 */
197MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
198MODULE_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... */
203IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
204IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
205IBM_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 */
201struct attribute_set {
202 unsigned int members, max_members;
203 struct attribute_group group;
204};
205
206/* Helpers */
207static int parse_strtoul(const char *buf, unsigned long max,
208 unsigned long *value);
209
210/* Module */
211static int experimental;
212static u32 dbg_level;
213static int force_load;
214static unsigned int hotkey_report_mode;
215 232
216 233
217/**************************************************************************** 234/****************************************************************************
218 * Subdrivers 235 * Driver-wide structs and misc. variables
219 */ 236 */
220 237
221struct ibm_struct; 238struct ibm_struct;
@@ -297,39 +314,6 @@ struct thinkpad_id_data {
297}; 314};
298static struct thinkpad_id_data thinkpad_id; 315static struct thinkpad_id_data thinkpad_id;
299 316
300static LIST_HEAD(tpacpi_all_drivers);
301
302MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
303MODULE_DESCRIPTION(IBM_DESC);
304MODULE_VERSION(IBM_VERSION);
305MODULE_LICENSE("GPL");
306
307/* Please remove this in year 2009 */
308MODULE_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 */
323MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
324MODULE_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... */
329IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
330IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
331IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
332
333#define __unused __attribute__ ((unused)) 317#define __unused __attribute__ ((unused))
334 318
335static enum { 319static enum {
@@ -338,6 +322,9 @@ static enum {
338 TPACPI_LIFE_EXITING, 322 TPACPI_LIFE_EXITING,
339} tpacpi_lifecycle; 323} tpacpi_lifecycle;
340 324
325static int experimental;
326static u32 dbg_level;
327
341/**************************************************************************** 328/****************************************************************************
342 **************************************************************************** 329 ****************************************************************************
343 * 330 *
@@ -370,11 +357,6 @@ IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
370IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */ 357IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
371IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */ 358IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
372 359
373
374/*************************************************************************
375 * Misc ACPI handles
376 */
377
378IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ 360IBM_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;
749static struct device *tpacpi_hwmon; 731static struct device *tpacpi_hwmon;
750static struct input_dev *tpacpi_inputdev; 732static struct input_dev *tpacpi_inputdev;
751static struct mutex tpacpi_inputdev_send_mutex; 733static struct mutex tpacpi_inputdev_send_mutex;
752 734static LIST_HEAD(tpacpi_all_drivers);
753 735
754static int tpacpi_resume_handler(struct platform_device *pdev) 736static 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 --------------------------------------------------- */ 769struct attribute_set {
788static 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
795static DRIVER_ATTR(interface_version, S_IRUGO,
796 tpacpi_driver_interface_version_show, NULL);
797
798/* debug_level --------------------------------------------------------- */
799static 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
805static 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
818static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
819 tpacpi_driver_debug_show, tpacpi_driver_debug_store);
820
821/* version ------------------------------------------------------------- */
822static 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
828static DRIVER_ATTR(version, S_IRUGO,
829 tpacpi_driver_version_show, NULL);
830
831/* --------------------------------------------------------------------- */
832
833static struct driver_attribute* tpacpi_driver_attributes[] = {
834 &driver_attr_debug_level, &driver_attr_version,
835 &driver_attr_interface_version,
836}; 772};
837 773
838static 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
852static 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
864struct attribute_set_obj { 774struct 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 --------------------------------------------------- */
863static 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
870static DRIVER_ATTR(interface_version, S_IRUGO,
871 tpacpi_driver_interface_version_show, NULL);
872
873/* debug_level --------------------------------------------------------- */
874static 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
880static 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
893static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
894 tpacpi_driver_debug_show, tpacpi_driver_debug_store);
895
896/* version ------------------------------------------------------------- */
897static 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
903static DRIVER_ATTR(version, S_IRUGO,
904 tpacpi_driver_version_show, NULL);
905
906/* --------------------------------------------------------------------- */
907
908static struct driver_attribute* tpacpi_driver_attributes[] = {
909 &driver_attr_debug_level, &driver_attr_version,
910 &driver_attr_interface_version,
911};
912
913static 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
927static 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;
1094static u32 hotkey_reserved_mask; 1081static u32 hotkey_reserved_mask;
1095static u32 hotkey_mask; 1082static u32 hotkey_mask;
1096 1083
1084static unsigned int hotkey_report_mode;
1085
1097static u16 *hotkey_keycode_map; 1086static u16 *hotkey_keycode_map;
1098 1087
1099static struct attribute_set *hotkey_dev_attributes; 1088static struct attribute_set *hotkey_dev_attributes;
@@ -3637,8 +3626,87 @@ struct ibm_thermal_sensors_struct {
3637 3626
3638static enum thermal_access_mode thermal_read_mode; 3627static enum thermal_access_mode thermal_read_mode;
3639 3628
3640static int thermal_get_sensor(int idx, s32 *value); 3629/* idx is zero-based */
3641static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s); 3630static 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
3688static 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 */
3834static 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
3892static 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
3915static int thermal_read(char *p) 3901static int thermal_read(char *p)
3916{ 3902{
3917 int len = 0; 3903 int len = 0;
@@ -4021,16 +4007,103 @@ static int brightness_offset = 0x31;
4021static int brightness_mode; 4007static int brightness_mode;
4022static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ 4008static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
4023 4009
4024static int brightness_get(struct backlight_device *bd); 4010static struct mutex brightness_mutex;
4025static int brightness_set(int value); 4011
4026static 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 */
4016static 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 */
4047static 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
4084errout:
4085 mutex_unlock(&brightness_mutex);
4086 return res;
4087}
4088
4089/* sysfs backlight class ----------------------------------------------- */
4090
4091static 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
4028static struct backlight_ops ibm_backlight_data = { 4101static 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
4033static struct mutex brightness_mutex; 4106/* --------------------------------------------------------------------- */
4034 4107
4035static int __init tpacpi_query_bcll_levels(acpi_handle handle) 4108static 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
4199static 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 */
4213static 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 */
4244static 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
4281errout:
4282 mutex_unlock(&brightness_mutex);
4283 return res;
4284}
4285
4286static int brightness_read(char *p) 4272static 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
4582static struct mutex fan_mutex; 4568static struct mutex fan_mutex;
4583 4569
4584static int fan_get_status(u8 *status);
4585static int fan_get_status_safe(u8 *status);
4586static int fan_get_speed(unsigned int *speed);
4587static void fan_update_desired_level(u8 status);
4588static void fan_watchdog_fire(struct work_struct *ignored); 4570static void fan_watchdog_fire(struct work_struct *ignored);
4589static void fan_watchdog_reset(void);
4590static int fan_set_level(int level);
4591static int fan_set_level_safe(int level);
4592static int fan_set_enable(void);
4593
4594static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire); 4571static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
4595 4572
4596IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */ 4573IBM_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 */
4584static 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
4595static 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
4631static 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
4649static 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
4672static 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
4712static 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
4733static 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
4789static 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
4827static 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
4856static 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
4879static 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 */
4942static 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
4953static 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
4989static 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
5007static void fan_exit(void) 5231static 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
5019static 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
5042static 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
5059static 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
5082static 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
5122static 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
5143static 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
5199static 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
5237static 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
5266static int fan_read(char *p) 5243static 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 */
5474static struct proc_dir_entry *proc_dir; 5451static 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
5457static int force_load;
5458
5481#ifdef CONFIG_THINKPAD_ACPI_DEBUG 5459#ifdef CONFIG_THINKPAD_ACPI_DEBUG
5482static const char * __init str_supported(int is_supported) 5460static 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
5490static void ibm_exit(struct ibm_struct *ibm); 5468static 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
5492static int __init ibm_init(struct ibm_init_struct *iibm) 5510static 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
5572static 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
5616static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) 5592static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
@@ -5839,7 +5815,57 @@ IBM_PARAM(brightness);
5839IBM_PARAM(volume); 5815IBM_PARAM(volume);
5840IBM_PARAM(fan); 5816IBM_PARAM(fan);
5841 5817
5842static void thinkpad_acpi_module_exit(void); 5818static 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
5844static int __init thinkpad_acpi_module_init(void) 5870static 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
5981static 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
6032module_init(thinkpad_acpi_module_init); 6007module_init(thinkpad_acpi_module_init);
6033module_exit(thinkpad_acpi_module_exit); 6008module_exit(thinkpad_acpi_module_exit);