diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2009-01-11 00:01:00 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-01-15 13:29:21 -0500 |
commit | a73f30916ee524437253739eacc682f6fb0f3ea8 (patch) | |
tree | 82005ee460486436207106f0c5b906ac5137f271 /drivers/platform/x86 | |
parent | e0b36fc5efd610a208b6b80e821a49302ca424ab (diff) |
ACPI: thinkpad-acpi: debug facility to emulate the rf switches
This code is required to keep the thinkpad-acpi maintainer sane, and
it is disabled by default.
Add a debug facility to simulate an rfkill hardware rocker switch, a
bluetooth rfkill soft-switch, a WWAN rfkill soft-switch on thinkpads.
The simulated switches obviously do not kill any radios in hardware or
firmware (unlike the real one). They also don't issue deprecated proc
events.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r-- | drivers/platform/x86/Kconfig | 11 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 190 |
2 files changed, 201 insertions, 0 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index e65448e99b48..431772b8a1d0 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -192,6 +192,17 @@ config THINKPAD_ACPI | |||
192 | 192 | ||
193 | If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. | 193 | If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. |
194 | 194 | ||
195 | config THINKPAD_ACPI_DEBUGFACILITIES | ||
196 | bool "Maintainer debug facilities" | ||
197 | depends on THINKPAD_ACPI | ||
198 | default n | ||
199 | ---help--- | ||
200 | Enables extra stuff in the thinkpad-acpi which is completely useless | ||
201 | for normal use. Read the driver source to find out what it does. | ||
202 | |||
203 | Say N here, unless you were told by a kernel maintainer to do | ||
204 | otherwise. | ||
205 | |||
195 | config THINKPAD_ACPI_DEBUG | 206 | config THINKPAD_ACPI_DEBUG |
196 | bool "Verbose debug mode" | 207 | bool "Verbose debug mode" |
197 | depends on THINKPAD_ACPI | 208 | depends on THINKPAD_ACPI |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index ee3fa007f312..a086ce8ed4eb 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -288,6 +288,16 @@ struct tpacpi_led_classdev { | |||
288 | unsigned int led; | 288 | unsigned int led; |
289 | }; | 289 | }; |
290 | 290 | ||
291 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
292 | static int dbg_wlswemul; | ||
293 | static int tpacpi_wlsw_emulstate; | ||
294 | static int dbg_bluetoothemul; | ||
295 | static int tpacpi_bluetooth_emulstate; | ||
296 | static int dbg_wwanemul; | ||
297 | static int tpacpi_wwan_emulstate; | ||
298 | #endif | ||
299 | |||
300 | |||
291 | /**************************************************************************** | 301 | /**************************************************************************** |
292 | **************************************************************************** | 302 | **************************************************************************** |
293 | * | 303 | * |
@@ -1006,6 +1016,94 @@ static DRIVER_ATTR(version, S_IRUGO, | |||
1006 | 1016 | ||
1007 | /* --------------------------------------------------------------------- */ | 1017 | /* --------------------------------------------------------------------- */ |
1008 | 1018 | ||
1019 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
1020 | |||
1021 | static void tpacpi_send_radiosw_update(void); | ||
1022 | |||
1023 | /* wlsw_emulstate ------------------------------------------------------ */ | ||
1024 | static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, | ||
1025 | char *buf) | ||
1026 | { | ||
1027 | return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wlsw_emulstate); | ||
1028 | } | ||
1029 | |||
1030 | static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv, | ||
1031 | const char *buf, size_t count) | ||
1032 | { | ||
1033 | unsigned long t; | ||
1034 | |||
1035 | if (parse_strtoul(buf, 1, &t)) | ||
1036 | return -EINVAL; | ||
1037 | |||
1038 | if (tpacpi_wlsw_emulstate != t) { | ||
1039 | tpacpi_wlsw_emulstate = !!t; | ||
1040 | tpacpi_send_radiosw_update(); | ||
1041 | } else | ||
1042 | tpacpi_wlsw_emulstate = !!t; | ||
1043 | |||
1044 | return count; | ||
1045 | } | ||
1046 | |||
1047 | static DRIVER_ATTR(wlsw_emulstate, S_IWUSR | S_IRUGO, | ||
1048 | tpacpi_driver_wlsw_emulstate_show, | ||
1049 | tpacpi_driver_wlsw_emulstate_store); | ||
1050 | |||
1051 | /* bluetooth_emulstate ------------------------------------------------- */ | ||
1052 | static ssize_t tpacpi_driver_bluetooth_emulstate_show( | ||
1053 | struct device_driver *drv, | ||
1054 | char *buf) | ||
1055 | { | ||
1056 | return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_bluetooth_emulstate); | ||
1057 | } | ||
1058 | |||
1059 | static ssize_t tpacpi_driver_bluetooth_emulstate_store( | ||
1060 | struct device_driver *drv, | ||
1061 | const char *buf, size_t count) | ||
1062 | { | ||
1063 | unsigned long t; | ||
1064 | |||
1065 | if (parse_strtoul(buf, 1, &t)) | ||
1066 | return -EINVAL; | ||
1067 | |||
1068 | tpacpi_bluetooth_emulstate = !!t; | ||
1069 | |||
1070 | return count; | ||
1071 | } | ||
1072 | |||
1073 | static DRIVER_ATTR(bluetooth_emulstate, S_IWUSR | S_IRUGO, | ||
1074 | tpacpi_driver_bluetooth_emulstate_show, | ||
1075 | tpacpi_driver_bluetooth_emulstate_store); | ||
1076 | |||
1077 | /* wwan_emulstate ------------------------------------------------- */ | ||
1078 | static ssize_t tpacpi_driver_wwan_emulstate_show( | ||
1079 | struct device_driver *drv, | ||
1080 | char *buf) | ||
1081 | { | ||
1082 | return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_wwan_emulstate); | ||
1083 | } | ||
1084 | |||
1085 | static ssize_t tpacpi_driver_wwan_emulstate_store( | ||
1086 | struct device_driver *drv, | ||
1087 | const char *buf, size_t count) | ||
1088 | { | ||
1089 | unsigned long t; | ||
1090 | |||
1091 | if (parse_strtoul(buf, 1, &t)) | ||
1092 | return -EINVAL; | ||
1093 | |||
1094 | tpacpi_wwan_emulstate = !!t; | ||
1095 | |||
1096 | return count; | ||
1097 | } | ||
1098 | |||
1099 | static DRIVER_ATTR(wwan_emulstate, S_IWUSR | S_IRUGO, | ||
1100 | tpacpi_driver_wwan_emulstate_show, | ||
1101 | tpacpi_driver_wwan_emulstate_store); | ||
1102 | |||
1103 | #endif | ||
1104 | |||
1105 | /* --------------------------------------------------------------------- */ | ||
1106 | |||
1009 | static struct driver_attribute *tpacpi_driver_attributes[] = { | 1107 | static struct driver_attribute *tpacpi_driver_attributes[] = { |
1010 | &driver_attr_debug_level, &driver_attr_version, | 1108 | &driver_attr_debug_level, &driver_attr_version, |
1011 | &driver_attr_interface_version, | 1109 | &driver_attr_interface_version, |
@@ -1022,6 +1120,15 @@ static int __init tpacpi_create_driver_attributes(struct device_driver *drv) | |||
1022 | i++; | 1120 | i++; |
1023 | } | 1121 | } |
1024 | 1122 | ||
1123 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
1124 | if (!res && dbg_wlswemul) | ||
1125 | res = driver_create_file(drv, &driver_attr_wlsw_emulstate); | ||
1126 | if (!res && dbg_bluetoothemul) | ||
1127 | res = driver_create_file(drv, &driver_attr_bluetooth_emulstate); | ||
1128 | if (!res && dbg_wwanemul) | ||
1129 | res = driver_create_file(drv, &driver_attr_wwan_emulstate); | ||
1130 | #endif | ||
1131 | |||
1025 | return res; | 1132 | return res; |
1026 | } | 1133 | } |
1027 | 1134 | ||
@@ -1031,6 +1138,12 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) | |||
1031 | 1138 | ||
1032 | for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) | 1139 | for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++) |
1033 | driver_remove_file(drv, tpacpi_driver_attributes[i]); | 1140 | driver_remove_file(drv, tpacpi_driver_attributes[i]); |
1141 | |||
1142 | #ifdef THINKPAD_ACPI_DEBUGFACILITIES | ||
1143 | driver_remove_file(drv, &driver_attr_wlsw_emulstate); | ||
1144 | driver_remove_file(drv, &driver_attr_bluetooth_emulstate); | ||
1145 | driver_remove_file(drv, &driver_attr_wwan_emulstate); | ||
1146 | #endif | ||
1034 | } | 1147 | } |
1035 | 1148 | ||
1036 | /**************************************************************************** | 1149 | /**************************************************************************** |
@@ -1216,6 +1329,12 @@ static struct attribute_set *hotkey_dev_attributes; | |||
1216 | 1329 | ||
1217 | static int hotkey_get_wlsw(int *status) | 1330 | static int hotkey_get_wlsw(int *status) |
1218 | { | 1331 | { |
1332 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
1333 | if (dbg_wlswemul) { | ||
1334 | *status = !!tpacpi_wlsw_emulstate; | ||
1335 | return 0; | ||
1336 | } | ||
1337 | #endif | ||
1219 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) | 1338 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) |
1220 | return -EIO; | 1339 | return -EIO; |
1221 | return 0; | 1340 | return 0; |
@@ -2222,6 +2341,13 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
2222 | hotkey_source_mask, hotkey_poll_freq); | 2341 | hotkey_source_mask, hotkey_poll_freq); |
2223 | #endif | 2342 | #endif |
2224 | 2343 | ||
2344 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
2345 | if (dbg_wlswemul) { | ||
2346 | tp_features.hotkey_wlsw = 1; | ||
2347 | printk(TPACPI_INFO | ||
2348 | "radio switch emulation enabled\n"); | ||
2349 | } else | ||
2350 | #endif | ||
2225 | /* Not all thinkpads have a hardware radio switch */ | 2351 | /* Not all thinkpads have a hardware radio switch */ |
2226 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { | 2352 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { |
2227 | tp_features.hotkey_wlsw = 1; | 2353 | tp_features.hotkey_wlsw = 1; |
@@ -2656,6 +2782,12 @@ static int bluetooth_get_radiosw(void) | |||
2656 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | 2782 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) |
2657 | return RFKILL_STATE_HARD_BLOCKED; | 2783 | return RFKILL_STATE_HARD_BLOCKED; |
2658 | 2784 | ||
2785 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
2786 | if (dbg_bluetoothemul) | ||
2787 | return (tpacpi_bluetooth_emulstate) ? | ||
2788 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | ||
2789 | #endif | ||
2790 | |||
2659 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 2791 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) |
2660 | return -EIO; | 2792 | return -EIO; |
2661 | 2793 | ||
@@ -2689,6 +2821,15 @@ static int bluetooth_set_radiosw(int radio_on, int update_rfk) | |||
2689 | && radio_on) | 2821 | && radio_on) |
2690 | return -EPERM; | 2822 | return -EPERM; |
2691 | 2823 | ||
2824 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
2825 | if (dbg_bluetoothemul) { | ||
2826 | tpacpi_bluetooth_emulstate = !!radio_on; | ||
2827 | if (update_rfk) | ||
2828 | bluetooth_update_rfk(); | ||
2829 | return 0; | ||
2830 | } | ||
2831 | #endif | ||
2832 | |||
2692 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) | 2833 | if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) |
2693 | return -EIO; | 2834 | return -EIO; |
2694 | if (radio_on) | 2835 | if (radio_on) |
@@ -2792,6 +2933,13 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
2792 | str_supported(tp_features.bluetooth), | 2933 | str_supported(tp_features.bluetooth), |
2793 | status); | 2934 | status); |
2794 | 2935 | ||
2936 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
2937 | if (dbg_bluetoothemul) { | ||
2938 | tp_features.bluetooth = 1; | ||
2939 | printk(TPACPI_INFO | ||
2940 | "bluetooth switch emulation enabled\n"); | ||
2941 | } else | ||
2942 | #endif | ||
2795 | if (tp_features.bluetooth && | 2943 | if (tp_features.bluetooth && |
2796 | !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { | 2944 | !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { |
2797 | /* no bluetooth hardware present in system */ | 2945 | /* no bluetooth hardware present in system */ |
@@ -2890,6 +3038,12 @@ static int wan_get_radiosw(void) | |||
2890 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) | 3038 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status) |
2891 | return RFKILL_STATE_HARD_BLOCKED; | 3039 | return RFKILL_STATE_HARD_BLOCKED; |
2892 | 3040 | ||
3041 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
3042 | if (dbg_wwanemul) | ||
3043 | return (tpacpi_wwan_emulstate) ? | ||
3044 | RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; | ||
3045 | #endif | ||
3046 | |||
2893 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) | 3047 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) |
2894 | return -EIO; | 3048 | return -EIO; |
2895 | 3049 | ||
@@ -2923,6 +3077,15 @@ static int wan_set_radiosw(int radio_on, int update_rfk) | |||
2923 | && radio_on) | 3077 | && radio_on) |
2924 | return -EPERM; | 3078 | return -EPERM; |
2925 | 3079 | ||
3080 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
3081 | if (dbg_wwanemul) { | ||
3082 | tpacpi_wwan_emulstate = !!radio_on; | ||
3083 | if (update_rfk) | ||
3084 | wan_update_rfk(); | ||
3085 | return 0; | ||
3086 | } | ||
3087 | #endif | ||
3088 | |||
2926 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) | 3089 | if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) |
2927 | return -EIO; | 3090 | return -EIO; |
2928 | if (radio_on) | 3091 | if (radio_on) |
@@ -3024,6 +3187,13 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
3024 | str_supported(tp_features.wan), | 3187 | str_supported(tp_features.wan), |
3025 | status); | 3188 | status); |
3026 | 3189 | ||
3190 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
3191 | if (dbg_wwanemul) { | ||
3192 | tp_features.wan = 1; | ||
3193 | printk(TPACPI_INFO | ||
3194 | "wwan switch emulation enabled\n"); | ||
3195 | } else | ||
3196 | #endif | ||
3027 | if (tp_features.wan && | 3197 | if (tp_features.wan && |
3028 | !(status & TP_ACPI_WANCARD_HWPRESENT)) { | 3198 | !(status & TP_ACPI_WANCARD_HWPRESENT)) { |
3029 | /* no wan hardware present in system */ | 3199 | /* no wan hardware present in system */ |
@@ -6701,6 +6871,26 @@ TPACPI_PARAM(brightness); | |||
6701 | TPACPI_PARAM(volume); | 6871 | TPACPI_PARAM(volume); |
6702 | TPACPI_PARAM(fan); | 6872 | TPACPI_PARAM(fan); |
6703 | 6873 | ||
6874 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | ||
6875 | module_param(dbg_wlswemul, uint, 0); | ||
6876 | MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation"); | ||
6877 | module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0); | ||
6878 | MODULE_PARM_DESC(wlsw_state, | ||
6879 | "Initial state of the emulated WLSW switch"); | ||
6880 | |||
6881 | module_param(dbg_bluetoothemul, uint, 0); | ||
6882 | MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation"); | ||
6883 | module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0); | ||
6884 | MODULE_PARM_DESC(bluetooth_state, | ||
6885 | "Initial state of the emulated bluetooth switch"); | ||
6886 | |||
6887 | module_param(dbg_wwanemul, uint, 0); | ||
6888 | MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation"); | ||
6889 | module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0); | ||
6890 | MODULE_PARM_DESC(wwan_state, | ||
6891 | "Initial state of the emulated WWAN switch"); | ||
6892 | #endif | ||
6893 | |||
6704 | static void thinkpad_acpi_module_exit(void) | 6894 | static void thinkpad_acpi_module_exit(void) |
6705 | { | 6895 | { |
6706 | struct ibm_struct *ibm, *itmp; | 6896 | struct ibm_struct *ibm, *itmp; |