aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/thinkpad_acpi.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-06-02 07:01:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-06-03 14:06:13 -0400
commit19d337dff95cbf76edd3ad95c0cee2732c3e1ec5 (patch)
tree33326eeb09cb9664cc8427a5dc7cd2b08b5a57c3 /drivers/platform/x86/thinkpad_acpi.c
parent0f6399c4c525b518644a9b09f8d6fb125a418c4d (diff)
rfkill: rewrite
This patch completely rewrites the rfkill core to address the following deficiencies: * all rfkill drivers need to implement polling where necessary rather than having one central implementation * updating the rfkill state cannot be done from arbitrary contexts, forcing drivers to use schedule_work and requiring lots of code * rfkill drivers need to keep track of soft/hard blocked internally -- the core should do this * the rfkill API has many unexpected quirks, for example being asymmetric wrt. alloc/free and register/unregister * rfkill can call back into a driver from within a function the driver called -- this is prone to deadlocks and generally should be avoided * rfkill-input pointlessly is a separate module * drivers need to #ifdef rfkill functions (unless they want to depend on or select RFKILL) -- rfkill should provide inlines that do nothing if it isn't compiled in * the rfkill structure is not opaque -- drivers need to initialise it correctly (lots of sanity checking code required) -- instead force drivers to pass the right variables to rfkill_alloc() * the documentation is hard to read because it always assumes the reader is completely clueless and contains way TOO MANY CAPS * the rfkill code needlessly uses a lot of locks and atomic operations in locked sections * fix LED trigger to actually change the LED when the radio state changes -- this wasn't done before Tested-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk> Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad] Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/platform/x86/thinkpad_acpi.c')
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c873
1 files changed, 452 insertions, 421 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 912be65b6261..cfcafa4e9473 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -166,13 +166,6 @@ enum {
166 166
167#define TPACPI_MAX_ACPI_ARGS 3 167#define TPACPI_MAX_ACPI_ARGS 3
168 168
169/* rfkill switches */
170enum {
171 TPACPI_RFK_BLUETOOTH_SW_ID = 0,
172 TPACPI_RFK_WWAN_SW_ID,
173 TPACPI_RFK_UWB_SW_ID,
174};
175
176/* printk headers */ 169/* printk headers */
177#define TPACPI_LOG TPACPI_FILE ": " 170#define TPACPI_LOG TPACPI_FILE ": "
178#define TPACPI_EMERG KERN_EMERG TPACPI_LOG 171#define TPACPI_EMERG KERN_EMERG TPACPI_LOG
@@ -1005,67 +998,237 @@ static int __init tpacpi_check_std_acpi_brightness_support(void)
1005 return 0; 998 return 0;
1006} 999}
1007 1000
1008static int __init tpacpi_new_rfkill(const unsigned int id, 1001static void printk_deprecated_attribute(const char * const what,
1009 struct rfkill **rfk, 1002 const char * const details)
1003{
1004 tpacpi_log_usertask("deprecated sysfs attribute");
1005 printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and "
1006 "will be removed. %s\n",
1007 what, details);
1008}
1009
1010/*************************************************************************
1011 * rfkill and radio control support helpers
1012 */
1013
1014/*
1015 * ThinkPad-ACPI firmware handling model:
1016 *
1017 * WLSW (master wireless switch) is event-driven, and is common to all
1018 * firmware-controlled radios. It cannot be controlled, just monitored,
1019 * as expected. It overrides all radio state in firmware
1020 *
1021 * The kernel, a masked-off hotkey, and WLSW can change the radio state
1022 * (TODO: verify how WLSW interacts with the returned radio state).
1023 *
1024 * The only time there are shadow radio state changes, is when
1025 * masked-off hotkeys are used.
1026 */
1027
1028/*
1029 * Internal driver API for radio state:
1030 *
1031 * int: < 0 = error, otherwise enum tpacpi_rfkill_state
1032 * bool: true means radio blocked (off)
1033 */
1034enum tpacpi_rfkill_state {
1035 TPACPI_RFK_RADIO_OFF = 0,
1036 TPACPI_RFK_RADIO_ON
1037};
1038
1039/* rfkill switches */
1040enum tpacpi_rfk_id {
1041 TPACPI_RFK_BLUETOOTH_SW_ID = 0,
1042 TPACPI_RFK_WWAN_SW_ID,
1043 TPACPI_RFK_UWB_SW_ID,
1044 TPACPI_RFK_SW_MAX
1045};
1046
1047static const char *tpacpi_rfkill_names[] = {
1048 [TPACPI_RFK_BLUETOOTH_SW_ID] = "bluetooth",
1049 [TPACPI_RFK_WWAN_SW_ID] = "wwan",
1050 [TPACPI_RFK_UWB_SW_ID] = "uwb",
1051 [TPACPI_RFK_SW_MAX] = NULL
1052};
1053
1054/* ThinkPad-ACPI rfkill subdriver */
1055struct tpacpi_rfk {
1056 struct rfkill *rfkill;
1057 enum tpacpi_rfk_id id;
1058 const struct tpacpi_rfk_ops *ops;
1059};
1060
1061struct tpacpi_rfk_ops {
1062 /* firmware interface */
1063 int (*get_status)(void);
1064 int (*set_status)(const enum tpacpi_rfkill_state);
1065};
1066
1067static struct tpacpi_rfk *tpacpi_rfkill_switches[TPACPI_RFK_SW_MAX];
1068
1069/* Query FW and update rfkill sw state for a given rfkill switch */
1070static int tpacpi_rfk_update_swstate(const struct tpacpi_rfk *tp_rfk)
1071{
1072 int status;
1073
1074 if (!tp_rfk)
1075 return -ENODEV;
1076
1077 status = (tp_rfk->ops->get_status)();
1078 if (status < 0)
1079 return status;
1080
1081 rfkill_set_sw_state(tp_rfk->rfkill,
1082 (status == TPACPI_RFK_RADIO_OFF));
1083
1084 return status;
1085}
1086
1087/* Query FW and update rfkill sw state for all rfkill switches */
1088static void tpacpi_rfk_update_swstate_all(void)
1089{
1090 unsigned int i;
1091
1092 for (i = 0; i < TPACPI_RFK_SW_MAX; i++)
1093 tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[i]);
1094}
1095
1096/*
1097 * Sync the HW-blocking state of all rfkill switches,
1098 * do notice it causes the rfkill core to schedule uevents
1099 */
1100static void tpacpi_rfk_update_hwblock_state(bool blocked)
1101{
1102 unsigned int i;
1103 struct tpacpi_rfk *tp_rfk;
1104
1105 for (i = 0; i < TPACPI_RFK_SW_MAX; i++) {
1106 tp_rfk = tpacpi_rfkill_switches[i];
1107 if (tp_rfk) {
1108 if (rfkill_set_hw_state(tp_rfk->rfkill,
1109 blocked)) {
1110 /* ignore -- we track sw block */
1111 }
1112 }
1113 }
1114}
1115
1116/* Call to get the WLSW state from the firmware */
1117static int hotkey_get_wlsw(void);
1118
1119/* Call to query WLSW state and update all rfkill switches */
1120static bool tpacpi_rfk_check_hwblock_state(void)
1121{
1122 int res = hotkey_get_wlsw();
1123 int hw_blocked;
1124
1125 /* When unknown or unsupported, we have to assume it is unblocked */
1126 if (res < 0)
1127 return false;
1128
1129 hw_blocked = (res == TPACPI_RFK_RADIO_OFF);
1130 tpacpi_rfk_update_hwblock_state(hw_blocked);
1131
1132 return hw_blocked;
1133}
1134
1135static int tpacpi_rfk_hook_set_block(void *data, bool blocked)
1136{
1137 struct tpacpi_rfk *tp_rfk = data;
1138 int res;
1139
1140 dbg_printk(TPACPI_DBG_RFKILL,
1141 "request to change radio state to %s\n",
1142 blocked ? "blocked" : "unblocked");
1143
1144 /* try to set radio state */
1145 res = (tp_rfk->ops->set_status)(blocked ?
1146 TPACPI_RFK_RADIO_OFF : TPACPI_RFK_RADIO_ON);
1147
1148 /* and update the rfkill core with whatever the FW really did */
1149 tpacpi_rfk_update_swstate(tp_rfk);
1150
1151 return (res < 0) ? res : 0;
1152}
1153
1154static const struct rfkill_ops tpacpi_rfk_rfkill_ops = {
1155 .set_block = tpacpi_rfk_hook_set_block,
1156};
1157
1158static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
1159 const struct tpacpi_rfk_ops *tp_rfkops,
1010 const enum rfkill_type rfktype, 1160 const enum rfkill_type rfktype,
1011 const char *name, 1161 const char *name,
1012 const bool set_default, 1162 const bool set_default)
1013 int (*toggle_radio)(void *, enum rfkill_state),
1014 int (*get_state)(void *, enum rfkill_state *))
1015{ 1163{
1164 struct tpacpi_rfk *atp_rfk;
1016 int res; 1165 int res;
1017 enum rfkill_state initial_state = RFKILL_STATE_SOFT_BLOCKED; 1166 bool initial_sw_state = false;
1167 int initial_sw_status;
1018 1168
1019 res = get_state(NULL, &initial_state); 1169 BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]);
1020 if (res < 0) { 1170
1171 initial_sw_status = (tp_rfkops->get_status)();
1172 if (initial_sw_status < 0) {
1021 printk(TPACPI_ERR 1173 printk(TPACPI_ERR
1022 "failed to read initial state for %s, error %d; " 1174 "failed to read initial state for %s, error %d; "
1023 "will turn radio off\n", name, res); 1175 "will turn radio off\n", name, initial_sw_status);
1024 } else if (set_default) { 1176 } else {
1025 /* try to set the initial state as the default for the rfkill 1177 initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF);
1026 * type, since we ask the firmware to preserve it across S5 in 1178 if (set_default) {
1027 * NVRAM */ 1179 /* try to set the initial state as the default for the
1028 if (rfkill_set_default(rfktype, 1180 * rfkill type, since we ask the firmware to preserve
1029 (initial_state == RFKILL_STATE_UNBLOCKED) ? 1181 * it across S5 in NVRAM */
1030 RFKILL_STATE_UNBLOCKED : 1182 rfkill_set_global_sw_state(rfktype, initial_sw_state);
1031 RFKILL_STATE_SOFT_BLOCKED) == -EPERM) 1183 }
1032 vdbg_printk(TPACPI_DBG_RFKILL, 1184 }
1033 "Default state for %s cannot be changed\n", 1185
1034 name); 1186 atp_rfk = kzalloc(sizeof(struct tpacpi_rfk), GFP_KERNEL);
1035 } 1187 if (atp_rfk)
1036 1188 atp_rfk->rfkill = rfkill_alloc(name,
1037 *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); 1189 &tpacpi_pdev->dev,
1038 if (!*rfk) { 1190 rfktype,
1191 &tpacpi_rfk_rfkill_ops,
1192 atp_rfk);
1193 if (!atp_rfk || !atp_rfk->rfkill) {
1039 printk(TPACPI_ERR 1194 printk(TPACPI_ERR
1040 "failed to allocate memory for rfkill class\n"); 1195 "failed to allocate memory for rfkill class\n");
1196 kfree(atp_rfk);
1041 return -ENOMEM; 1197 return -ENOMEM;
1042 } 1198 }
1043 1199
1044 (*rfk)->name = name; 1200 atp_rfk->id = id;
1045 (*rfk)->get_state = get_state; 1201 atp_rfk->ops = tp_rfkops;
1046 (*rfk)->toggle_radio = toggle_radio; 1202
1047 (*rfk)->state = initial_state; 1203 rfkill_set_states(atp_rfk->rfkill, initial_sw_state,
1204 tpacpi_rfk_check_hwblock_state());
1048 1205
1049 res = rfkill_register(*rfk); 1206 res = rfkill_register(atp_rfk->rfkill);
1050 if (res < 0) { 1207 if (res < 0) {
1051 printk(TPACPI_ERR 1208 printk(TPACPI_ERR
1052 "failed to register %s rfkill switch: %d\n", 1209 "failed to register %s rfkill switch: %d\n",
1053 name, res); 1210 name, res);
1054 rfkill_free(*rfk); 1211 rfkill_destroy(atp_rfk->rfkill);
1055 *rfk = NULL; 1212 kfree(atp_rfk);
1056 return res; 1213 return res;
1057 } 1214 }
1058 1215
1216 tpacpi_rfkill_switches[id] = atp_rfk;
1059 return 0; 1217 return 0;
1060} 1218}
1061 1219
1062static void printk_deprecated_attribute(const char * const what, 1220static void tpacpi_destroy_rfkill(const enum tpacpi_rfk_id id)
1063 const char * const details)
1064{ 1221{
1065 tpacpi_log_usertask("deprecated sysfs attribute"); 1222 struct tpacpi_rfk *tp_rfk;
1066 printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " 1223
1067 "will be removed. %s\n", 1224 BUG_ON(id >= TPACPI_RFK_SW_MAX);
1068 what, details); 1225
1226 tp_rfk = tpacpi_rfkill_switches[id];
1227 if (tp_rfk) {
1228 rfkill_unregister(tp_rfk->rfkill);
1229 tpacpi_rfkill_switches[id] = NULL;
1230 kfree(tp_rfk);
1231 }
1069} 1232}
1070 1233
1071static void printk_deprecated_rfkill_attribute(const char * const what) 1234static void printk_deprecated_rfkill_attribute(const char * const what)
@@ -1074,6 +1237,112 @@ static void printk_deprecated_rfkill_attribute(const char * const what)
1074 "Please switch to generic rfkill before year 2010"); 1237 "Please switch to generic rfkill before year 2010");
1075} 1238}
1076 1239
1240/* sysfs <radio> enable ------------------------------------------------ */
1241static ssize_t tpacpi_rfk_sysfs_enable_show(const enum tpacpi_rfk_id id,
1242 struct device_attribute *attr,
1243 char *buf)
1244{
1245 int status;
1246
1247 printk_deprecated_rfkill_attribute(attr->attr.name);
1248
1249 /* This is in the ABI... */
1250 if (tpacpi_rfk_check_hwblock_state()) {
1251 status = TPACPI_RFK_RADIO_OFF;
1252 } else {
1253 status = tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]);
1254 if (status < 0)
1255 return status;
1256 }
1257
1258 return snprintf(buf, PAGE_SIZE, "%d\n",
1259 (status == TPACPI_RFK_RADIO_ON) ? 1 : 0);
1260}
1261
1262static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id,
1263 struct device_attribute *attr,
1264 const char *buf, size_t count)
1265{
1266 unsigned long t;
1267 int res;
1268
1269 printk_deprecated_rfkill_attribute(attr->attr.name);
1270
1271 if (parse_strtoul(buf, 1, &t))
1272 return -EINVAL;
1273
1274 tpacpi_disclose_usertask(attr->attr.name, "set to %ld\n", t);
1275
1276 /* This is in the ABI... */
1277 if (tpacpi_rfk_check_hwblock_state() && !!t)
1278 return -EPERM;
1279
1280 res = tpacpi_rfkill_switches[id]->ops->set_status((!!t) ?
1281 TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF);
1282 tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]);
1283
1284 return (res < 0) ? res : count;
1285}
1286
1287/* procfs -------------------------------------------------------------- */
1288static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p)
1289{
1290 int len = 0;
1291
1292 if (id >= TPACPI_RFK_SW_MAX)
1293 len += sprintf(p + len, "status:\t\tnot supported\n");
1294 else {
1295 int status;
1296
1297 /* This is in the ABI... */
1298 if (tpacpi_rfk_check_hwblock_state()) {
1299 status = TPACPI_RFK_RADIO_OFF;
1300 } else {
1301 status = tpacpi_rfk_update_swstate(
1302 tpacpi_rfkill_switches[id]);
1303 if (status < 0)
1304 return status;
1305 }
1306
1307 len += sprintf(p + len, "status:\t\t%s\n",
1308 (status == TPACPI_RFK_RADIO_ON) ?
1309 "enabled" : "disabled");
1310 len += sprintf(p + len, "commands:\tenable, disable\n");
1311 }
1312
1313 return len;
1314}
1315
1316static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf)
1317{
1318 char *cmd;
1319 int status = -1;
1320 int res = 0;
1321
1322 if (id >= TPACPI_RFK_SW_MAX)
1323 return -ENODEV;
1324
1325 while ((cmd = next_cmd(&buf))) {
1326 if (strlencmp(cmd, "enable") == 0)
1327 status = TPACPI_RFK_RADIO_ON;
1328 else if (strlencmp(cmd, "disable") == 0)
1329 status = TPACPI_RFK_RADIO_OFF;
1330 else
1331 return -EINVAL;
1332 }
1333
1334 if (status != -1) {
1335 tpacpi_disclose_usertask("procfs", "attempt to %s %s\n",
1336 (status == TPACPI_RFK_RADIO_ON) ?
1337 "enable" : "disable",
1338 tpacpi_rfkill_names[id]);
1339 res = (tpacpi_rfkill_switches[id]->ops->set_status)(status);
1340 tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]);
1341 }
1342
1343 return res;
1344}
1345
1077/************************************************************************* 1346/*************************************************************************
1078 * thinkpad-acpi driver attributes 1347 * thinkpad-acpi driver attributes
1079 */ 1348 */
@@ -1127,8 +1396,6 @@ static DRIVER_ATTR(version, S_IRUGO,
1127 1396
1128#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 1397#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
1129 1398
1130static void tpacpi_send_radiosw_update(void);
1131
1132/* wlsw_emulstate ------------------------------------------------------ */ 1399/* wlsw_emulstate ------------------------------------------------------ */
1133static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv, 1400static ssize_t tpacpi_driver_wlsw_emulstate_show(struct device_driver *drv,
1134 char *buf) 1401 char *buf)
@@ -1144,11 +1411,10 @@ static ssize_t tpacpi_driver_wlsw_emulstate_store(struct device_driver *drv,
1144 if (parse_strtoul(buf, 1, &t)) 1411 if (parse_strtoul(buf, 1, &t))
1145 return -EINVAL; 1412 return -EINVAL;
1146 1413
1147 if (tpacpi_wlsw_emulstate != t) { 1414 if (tpacpi_wlsw_emulstate != !!t) {
1148 tpacpi_wlsw_emulstate = !!t;
1149 tpacpi_send_radiosw_update();
1150 } else
1151 tpacpi_wlsw_emulstate = !!t; 1415 tpacpi_wlsw_emulstate = !!t;
1416 tpacpi_rfk_update_hwblock_state(!t); /* negative logic */
1417 }
1152 1418
1153 return count; 1419 return count;
1154} 1420}
@@ -1463,17 +1729,23 @@ static struct attribute_set *hotkey_dev_attributes;
1463/* HKEY.MHKG() return bits */ 1729/* HKEY.MHKG() return bits */
1464#define TP_HOTKEY_TABLET_MASK (1 << 3) 1730#define TP_HOTKEY_TABLET_MASK (1 << 3)
1465 1731
1466static int hotkey_get_wlsw(int *status) 1732static int hotkey_get_wlsw(void)
1467{ 1733{
1734 int status;
1735
1736 if (!tp_features.hotkey_wlsw)
1737 return -ENODEV;
1738
1468#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 1739#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
1469 if (dbg_wlswemul) { 1740 if (dbg_wlswemul)
1470 *status = !!tpacpi_wlsw_emulstate; 1741 return (tpacpi_wlsw_emulstate) ?
1471 return 0; 1742 TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
1472 }
1473#endif 1743#endif
1474 if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) 1744
1745 if (!acpi_evalf(hkey_handle, &status, "WLSW", "d"))
1475 return -EIO; 1746 return -EIO;
1476 return 0; 1747
1748 return (status) ? TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
1477} 1749}
1478 1750
1479static int hotkey_get_tablet_mode(int *status) 1751static int hotkey_get_tablet_mode(int *status)
@@ -2107,12 +2379,16 @@ static ssize_t hotkey_radio_sw_show(struct device *dev,
2107 struct device_attribute *attr, 2379 struct device_attribute *attr,
2108 char *buf) 2380 char *buf)
2109{ 2381{
2110 int res, s; 2382 int res;
2111 res = hotkey_get_wlsw(&s); 2383 res = hotkey_get_wlsw();
2112 if (res < 0) 2384 if (res < 0)
2113 return res; 2385 return res;
2114 2386
2115 return snprintf(buf, PAGE_SIZE, "%d\n", !!s); 2387 /* Opportunistic update */
2388 tpacpi_rfk_update_hwblock_state((res == TPACPI_RFK_RADIO_OFF));
2389
2390 return snprintf(buf, PAGE_SIZE, "%d\n",
2391 (res == TPACPI_RFK_RADIO_OFF) ? 0 : 1);
2116} 2392}
2117 2393
2118static struct device_attribute dev_attr_hotkey_radio_sw = 2394static struct device_attribute dev_attr_hotkey_radio_sw =
@@ -2223,30 +2499,52 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
2223 &dev_attr_hotkey_wakeup_hotunplug_complete.attr, 2499 &dev_attr_hotkey_wakeup_hotunplug_complete.attr,
2224}; 2500};
2225 2501
2226static void bluetooth_update_rfk(void); 2502/*
2227static void wan_update_rfk(void); 2503 * Sync both the hw and sw blocking state of all switches
2228static void uwb_update_rfk(void); 2504 */
2229static void tpacpi_send_radiosw_update(void) 2505static void tpacpi_send_radiosw_update(void)
2230{ 2506{
2231 int wlsw; 2507 int wlsw;
2232 2508
2233 /* Sync these BEFORE sending any rfkill events */ 2509 /*
2234 if (tp_features.bluetooth) 2510 * We must sync all rfkill controllers *before* issuing any
2235 bluetooth_update_rfk(); 2511 * rfkill input events, or we will race the rfkill core input
2236 if (tp_features.wan) 2512 * handler.
2237 wan_update_rfk(); 2513 *
2238 if (tp_features.uwb) 2514 * tpacpi_inputdev_send_mutex works as a syncronization point
2239 uwb_update_rfk(); 2515 * for the above.
2516 *
2517 * We optimize to avoid numerous calls to hotkey_get_wlsw.
2518 */
2240 2519
2241 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { 2520 wlsw = hotkey_get_wlsw();
2521
2522 /* Sync hw blocking state first if it is hw-blocked */
2523 if (wlsw == TPACPI_RFK_RADIO_OFF)
2524 tpacpi_rfk_update_hwblock_state(true);
2525
2526 /* Sync sw blocking state */
2527 tpacpi_rfk_update_swstate_all();
2528
2529 /* Sync hw blocking state last if it is hw-unblocked */
2530 if (wlsw == TPACPI_RFK_RADIO_ON)
2531 tpacpi_rfk_update_hwblock_state(false);
2532
2533 /* Issue rfkill input event for WLSW switch */
2534 if (!(wlsw < 0)) {
2242 mutex_lock(&tpacpi_inputdev_send_mutex); 2535 mutex_lock(&tpacpi_inputdev_send_mutex);
2243 2536
2244 input_report_switch(tpacpi_inputdev, 2537 input_report_switch(tpacpi_inputdev,
2245 SW_RFKILL_ALL, !!wlsw); 2538 SW_RFKILL_ALL, (wlsw > 0));
2246 input_sync(tpacpi_inputdev); 2539 input_sync(tpacpi_inputdev);
2247 2540
2248 mutex_unlock(&tpacpi_inputdev_send_mutex); 2541 mutex_unlock(&tpacpi_inputdev_send_mutex);
2249 } 2542 }
2543
2544 /*
2545 * this can be unconditional, as we will poll state again
2546 * if userspace uses the notify to read data
2547 */
2250 hotkey_radio_sw_notify_change(); 2548 hotkey_radio_sw_notify_change();
2251} 2549}
2252 2550
@@ -3056,8 +3354,6 @@ enum {
3056 3354
3057#define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" 3355#define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw"
3058 3356
3059static struct rfkill *tpacpi_bluetooth_rfkill;
3060
3061static void bluetooth_suspend(pm_message_t state) 3357static void bluetooth_suspend(pm_message_t state)
3062{ 3358{
3063 /* Try to make sure radio will resume powered off */ 3359 /* Try to make sure radio will resume powered off */
@@ -3067,83 +3363,47 @@ static void bluetooth_suspend(pm_message_t state)
3067 "bluetooth power down on resume request failed\n"); 3363 "bluetooth power down on resume request failed\n");
3068} 3364}
3069 3365
3070static int bluetooth_get_radiosw(void) 3366static int bluetooth_get_status(void)
3071{ 3367{
3072 int status; 3368 int status;
3073 3369
3074 if (!tp_features.bluetooth)
3075 return -ENODEV;
3076
3077 /* WLSW overrides bluetooth in firmware/hardware, reflect that */
3078 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
3079 return RFKILL_STATE_HARD_BLOCKED;
3080
3081#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 3370#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3082 if (dbg_bluetoothemul) 3371 if (dbg_bluetoothemul)
3083 return (tpacpi_bluetooth_emulstate) ? 3372 return (tpacpi_bluetooth_emulstate) ?
3084 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; 3373 TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
3085#endif 3374#endif
3086 3375
3087 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) 3376 if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
3088 return -EIO; 3377 return -EIO;
3089 3378
3090 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ? 3379 return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0) ?
3091 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; 3380 TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
3092} 3381}
3093 3382
3094static void bluetooth_update_rfk(void) 3383static int bluetooth_set_status(enum tpacpi_rfkill_state state)
3095{ 3384{
3096 int status; 3385 int status;
3097 3386
3098 if (!tpacpi_bluetooth_rfkill)
3099 return;
3100
3101 status = bluetooth_get_radiosw();
3102 if (status < 0)
3103 return;
3104 rfkill_force_state(tpacpi_bluetooth_rfkill, status);
3105
3106 vdbg_printk(TPACPI_DBG_RFKILL, 3387 vdbg_printk(TPACPI_DBG_RFKILL,
3107 "forced rfkill state to %d\n", 3388 "will attempt to %s bluetooth\n",
3108 status); 3389 (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
3109}
3110
3111static int bluetooth_set_radiosw(int radio_on, int update_rfk)
3112{
3113 int status;
3114
3115 if (!tp_features.bluetooth)
3116 return -ENODEV;
3117
3118 /* WLSW overrides bluetooth in firmware/hardware, but there is no
3119 * reason to risk weird behaviour. */
3120 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
3121 && radio_on)
3122 return -EPERM;
3123
3124 vdbg_printk(TPACPI_DBG_RFKILL,
3125 "will %s bluetooth\n", radio_on ? "enable" : "disable");
3126 3390
3127#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 3391#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3128 if (dbg_bluetoothemul) { 3392 if (dbg_bluetoothemul) {
3129 tpacpi_bluetooth_emulstate = !!radio_on; 3393 tpacpi_bluetooth_emulstate = (state == TPACPI_RFK_RADIO_ON);
3130 if (update_rfk)
3131 bluetooth_update_rfk();
3132 return 0; 3394 return 0;
3133 } 3395 }
3134#endif 3396#endif
3135 3397
3136 /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ 3398 /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */
3137 if (radio_on) 3399 if (state == TPACPI_RFK_RADIO_ON)
3138 status = TP_ACPI_BLUETOOTH_RADIOSSW; 3400 status = TP_ACPI_BLUETOOTH_RADIOSSW;
3139 else 3401 else
3140 status = 0; 3402 status = 0;
3403
3141 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) 3404 if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
3142 return -EIO; 3405 return -EIO;
3143 3406
3144 if (update_rfk)
3145 bluetooth_update_rfk();
3146
3147 return 0; 3407 return 0;
3148} 3408}
3149 3409
@@ -3152,35 +3412,16 @@ static ssize_t bluetooth_enable_show(struct device *dev,
3152 struct device_attribute *attr, 3412 struct device_attribute *attr,
3153 char *buf) 3413 char *buf)
3154{ 3414{
3155 int status; 3415 return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_BLUETOOTH_SW_ID,
3156 3416 attr, buf);
3157 printk_deprecated_rfkill_attribute("bluetooth_enable");
3158
3159 status = bluetooth_get_radiosw();
3160 if (status < 0)
3161 return status;
3162
3163 return snprintf(buf, PAGE_SIZE, "%d\n",
3164 (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0);
3165} 3417}
3166 3418
3167static ssize_t bluetooth_enable_store(struct device *dev, 3419static ssize_t bluetooth_enable_store(struct device *dev,
3168 struct device_attribute *attr, 3420 struct device_attribute *attr,
3169 const char *buf, size_t count) 3421 const char *buf, size_t count)
3170{ 3422{
3171 unsigned long t; 3423 return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_BLUETOOTH_SW_ID,
3172 int res; 3424 attr, buf, count);
3173
3174 printk_deprecated_rfkill_attribute("bluetooth_enable");
3175
3176 if (parse_strtoul(buf, 1, &t))
3177 return -EINVAL;
3178
3179 tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t);
3180
3181 res = bluetooth_set_radiosw(t, 1);
3182
3183 return (res) ? res : count;
3184} 3425}
3185 3426
3186static struct device_attribute dev_attr_bluetooth_enable = 3427static struct device_attribute dev_attr_bluetooth_enable =
@@ -3198,23 +3439,10 @@ static const struct attribute_group bluetooth_attr_group = {
3198 .attrs = bluetooth_attributes, 3439 .attrs = bluetooth_attributes,
3199}; 3440};
3200 3441
3201static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) 3442static const struct tpacpi_rfk_ops bluetooth_tprfk_ops = {
3202{ 3443 .get_status = bluetooth_get_status,
3203 int bts = bluetooth_get_radiosw(); 3444 .set_status = bluetooth_set_status,
3204 3445};
3205 if (bts < 0)
3206 return bts;
3207
3208 *state = bts;
3209 return 0;
3210}
3211
3212static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state)
3213{
3214 dbg_printk(TPACPI_DBG_RFKILL,
3215 "request to change radio state to %d\n", state);
3216 return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
3217}
3218 3446
3219static void bluetooth_shutdown(void) 3447static void bluetooth_shutdown(void)
3220{ 3448{
@@ -3230,13 +3458,12 @@ static void bluetooth_shutdown(void)
3230 3458
3231static void bluetooth_exit(void) 3459static void bluetooth_exit(void)
3232{ 3460{
3233 bluetooth_shutdown();
3234
3235 if (tpacpi_bluetooth_rfkill)
3236 rfkill_unregister(tpacpi_bluetooth_rfkill);
3237
3238 sysfs_remove_group(&tpacpi_pdev->dev.kobj, 3461 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
3239 &bluetooth_attr_group); 3462 &bluetooth_attr_group);
3463
3464 tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID);
3465
3466 bluetooth_shutdown();
3240} 3467}
3241 3468
3242static int __init bluetooth_init(struct ibm_init_struct *iibm) 3469static int __init bluetooth_init(struct ibm_init_struct *iibm)
@@ -3277,20 +3504,18 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
3277 if (!tp_features.bluetooth) 3504 if (!tp_features.bluetooth)
3278 return 1; 3505 return 1;
3279 3506
3280 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
3281 &bluetooth_attr_group);
3282 if (res)
3283 return res;
3284
3285 res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, 3507 res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID,
3286 &tpacpi_bluetooth_rfkill, 3508 &bluetooth_tprfk_ops,
3287 RFKILL_TYPE_BLUETOOTH, 3509 RFKILL_TYPE_BLUETOOTH,
3288 TPACPI_RFK_BLUETOOTH_SW_NAME, 3510 TPACPI_RFK_BLUETOOTH_SW_NAME,
3289 true, 3511 true);
3290 tpacpi_bluetooth_rfk_set, 3512 if (res)
3291 tpacpi_bluetooth_rfk_get); 3513 return res;
3514
3515 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
3516 &bluetooth_attr_group);
3292 if (res) { 3517 if (res) {
3293 bluetooth_exit(); 3518 tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID);
3294 return res; 3519 return res;
3295 } 3520 }
3296 3521
@@ -3300,46 +3525,12 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
3300/* procfs -------------------------------------------------------------- */ 3525/* procfs -------------------------------------------------------------- */
3301static int bluetooth_read(char *p) 3526static int bluetooth_read(char *p)
3302{ 3527{
3303 int len = 0; 3528 return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p);
3304 int status = bluetooth_get_radiosw();
3305
3306 if (!tp_features.bluetooth)
3307 len += sprintf(p + len, "status:\t\tnot supported\n");
3308 else {
3309 len += sprintf(p + len, "status:\t\t%s\n",
3310 (status == RFKILL_STATE_UNBLOCKED) ?
3311 "enabled" : "disabled");
3312 len += sprintf(p + len, "commands:\tenable, disable\n");
3313 }
3314
3315 return len;
3316} 3529}
3317 3530
3318static int bluetooth_write(char *buf) 3531static int bluetooth_write(char *buf)
3319{ 3532{
3320 char *cmd; 3533 return tpacpi_rfk_procfs_write(TPACPI_RFK_BLUETOOTH_SW_ID, buf);
3321 int state = -1;
3322
3323 if (!tp_features.bluetooth)
3324 return -ENODEV;
3325
3326 while ((cmd = next_cmd(&buf))) {
3327 if (strlencmp(cmd, "enable") == 0) {
3328 state = 1;
3329 } else if (strlencmp(cmd, "disable") == 0) {
3330 state = 0;
3331 } else
3332 return -EINVAL;
3333 }
3334
3335 if (state != -1) {
3336 tpacpi_disclose_usertask("procfs bluetooth",
3337 "attempt to %s\n",
3338 state ? "enable" : "disable");
3339 bluetooth_set_radiosw(state, 1);
3340 }
3341
3342 return 0;
3343} 3534}
3344 3535
3345static struct ibm_struct bluetooth_driver_data = { 3536static struct ibm_struct bluetooth_driver_data = {
@@ -3365,8 +3556,6 @@ enum {
3365 3556
3366#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" 3557#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw"
3367 3558
3368static struct rfkill *tpacpi_wan_rfkill;
3369
3370static void wan_suspend(pm_message_t state) 3559static void wan_suspend(pm_message_t state)
3371{ 3560{
3372 /* Try to make sure radio will resume powered off */ 3561 /* Try to make sure radio will resume powered off */
@@ -3376,83 +3565,47 @@ static void wan_suspend(pm_message_t state)
3376 "WWAN power down on resume request failed\n"); 3565 "WWAN power down on resume request failed\n");
3377} 3566}
3378 3567
3379static int wan_get_radiosw(void) 3568static int wan_get_status(void)
3380{ 3569{
3381 int status; 3570 int status;
3382 3571
3383 if (!tp_features.wan)
3384 return -ENODEV;
3385
3386 /* WLSW overrides WWAN in firmware/hardware, reflect that */
3387 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
3388 return RFKILL_STATE_HARD_BLOCKED;
3389
3390#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 3572#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3391 if (dbg_wwanemul) 3573 if (dbg_wwanemul)
3392 return (tpacpi_wwan_emulstate) ? 3574 return (tpacpi_wwan_emulstate) ?
3393 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; 3575 TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
3394#endif 3576#endif
3395 3577
3396 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d")) 3578 if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
3397 return -EIO; 3579 return -EIO;
3398 3580
3399 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ? 3581 return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ?
3400 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; 3582 TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
3401}
3402
3403static void wan_update_rfk(void)
3404{
3405 int status;
3406
3407 if (!tpacpi_wan_rfkill)
3408 return;
3409
3410 status = wan_get_radiosw();
3411 if (status < 0)
3412 return;
3413 rfkill_force_state(tpacpi_wan_rfkill, status);
3414
3415 vdbg_printk(TPACPI_DBG_RFKILL,
3416 "forced rfkill state to %d\n",
3417 status);
3418} 3583}
3419 3584
3420static int wan_set_radiosw(int radio_on, int update_rfk) 3585static int wan_set_status(enum tpacpi_rfkill_state state)
3421{ 3586{
3422 int status; 3587 int status;
3423 3588
3424 if (!tp_features.wan)
3425 return -ENODEV;
3426
3427 /* WLSW overrides bluetooth in firmware/hardware, but there is no
3428 * reason to risk weird behaviour. */
3429 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
3430 && radio_on)
3431 return -EPERM;
3432
3433 vdbg_printk(TPACPI_DBG_RFKILL, 3589 vdbg_printk(TPACPI_DBG_RFKILL,
3434 "will %s WWAN\n", radio_on ? "enable" : "disable"); 3590 "will attempt to %s wwan\n",
3591 (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
3435 3592
3436#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 3593#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3437 if (dbg_wwanemul) { 3594 if (dbg_wwanemul) {
3438 tpacpi_wwan_emulstate = !!radio_on; 3595 tpacpi_wwan_emulstate = (state == TPACPI_RFK_RADIO_ON);
3439 if (update_rfk)
3440 wan_update_rfk();
3441 return 0; 3596 return 0;
3442 } 3597 }
3443#endif 3598#endif
3444 3599
3445 /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ 3600 /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */
3446 if (radio_on) 3601 if (state == TPACPI_RFK_RADIO_ON)
3447 status = TP_ACPI_WANCARD_RADIOSSW; 3602 status = TP_ACPI_WANCARD_RADIOSSW;
3448 else 3603 else
3449 status = 0; 3604 status = 0;
3605
3450 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) 3606 if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
3451 return -EIO; 3607 return -EIO;
3452 3608
3453 if (update_rfk)
3454 wan_update_rfk();
3455
3456 return 0; 3609 return 0;
3457} 3610}
3458 3611
@@ -3461,35 +3614,16 @@ static ssize_t wan_enable_show(struct device *dev,
3461 struct device_attribute *attr, 3614 struct device_attribute *attr,
3462 char *buf) 3615 char *buf)
3463{ 3616{
3464 int status; 3617 return tpacpi_rfk_sysfs_enable_show(TPACPI_RFK_WWAN_SW_ID,
3465 3618 attr, buf);
3466 printk_deprecated_rfkill_attribute("wwan_enable");
3467
3468 status = wan_get_radiosw();
3469 if (status < 0)
3470 return status;
3471
3472 return snprintf(buf, PAGE_SIZE, "%d\n",
3473 (status == RFKILL_STATE_UNBLOCKED) ? 1 : 0);
3474} 3619}
3475 3620
3476static ssize_t wan_enable_store(struct device *dev, 3621static ssize_t wan_enable_store(struct device *dev,
3477 struct device_attribute *attr, 3622 struct device_attribute *attr,
3478 const char *buf, size_t count) 3623 const char *buf, size_t count)
3479{ 3624{
3480 unsigned long t; 3625 return tpacpi_rfk_sysfs_enable_store(TPACPI_RFK_WWAN_SW_ID,
3481 int res; 3626 attr, buf, count);
3482
3483 printk_deprecated_rfkill_attribute("wwan_enable");
3484
3485 if (parse_strtoul(buf, 1, &t))
3486 return -EINVAL;
3487
3488 tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t);
3489
3490 res = wan_set_radiosw(t, 1);
3491
3492 return (res) ? res : count;
3493} 3627}
3494 3628
3495static struct device_attribute dev_attr_wan_enable = 3629static struct device_attribute dev_attr_wan_enable =
@@ -3507,23 +3641,10 @@ static const struct attribute_group wan_attr_group = {
3507 .attrs = wan_attributes, 3641 .attrs = wan_attributes,
3508}; 3642};
3509 3643
3510static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) 3644static const struct tpacpi_rfk_ops wan_tprfk_ops = {
3511{ 3645 .get_status = wan_get_status,
3512 int wans = wan_get_radiosw(); 3646 .set_status = wan_set_status,
3513 3647};
3514 if (wans < 0)
3515 return wans;
3516
3517 *state = wans;
3518 return 0;
3519}
3520
3521static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state)
3522{
3523 dbg_printk(TPACPI_DBG_RFKILL,
3524 "request to change radio state to %d\n", state);
3525 return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
3526}
3527 3648
3528static void wan_shutdown(void) 3649static void wan_shutdown(void)
3529{ 3650{
@@ -3539,13 +3660,12 @@ static void wan_shutdown(void)
3539 3660
3540static void wan_exit(void) 3661static void wan_exit(void)
3541{ 3662{
3542 wan_shutdown();
3543
3544 if (tpacpi_wan_rfkill)
3545 rfkill_unregister(tpacpi_wan_rfkill);
3546
3547 sysfs_remove_group(&tpacpi_pdev->dev.kobj, 3663 sysfs_remove_group(&tpacpi_pdev->dev.kobj,
3548 &wan_attr_group); 3664 &wan_attr_group);
3665
3666 tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID);
3667
3668 wan_shutdown();
3549} 3669}
3550 3670
3551static int __init wan_init(struct ibm_init_struct *iibm) 3671static int __init wan_init(struct ibm_init_struct *iibm)
@@ -3584,20 +3704,19 @@ static int __init wan_init(struct ibm_init_struct *iibm)
3584 if (!tp_features.wan) 3704 if (!tp_features.wan)
3585 return 1; 3705 return 1;
3586 3706
3587 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
3588 &wan_attr_group);
3589 if (res)
3590 return res;
3591
3592 res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, 3707 res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID,
3593 &tpacpi_wan_rfkill, 3708 &wan_tprfk_ops,
3594 RFKILL_TYPE_WWAN, 3709 RFKILL_TYPE_WWAN,
3595 TPACPI_RFK_WWAN_SW_NAME, 3710 TPACPI_RFK_WWAN_SW_NAME,
3596 true, 3711 true);
3597 tpacpi_wan_rfk_set, 3712 if (res)
3598 tpacpi_wan_rfk_get); 3713 return res;
3714
3715 res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
3716 &wan_attr_group);
3717
3599 if (res) { 3718 if (res) {
3600 wan_exit(); 3719 tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID);
3601 return res; 3720 return res;
3602 } 3721 }
3603 3722
@@ -3607,48 +3726,12 @@ static int __init wan_init(struct ibm_init_struct *iibm)
3607/* procfs -------------------------------------------------------------- */ 3726/* procfs -------------------------------------------------------------- */
3608static int wan_read(char *p) 3727static int wan_read(char *p)
3609{ 3728{
3610 int len = 0; 3729 return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p);
3611 int status = wan_get_radiosw();
3612
3613 tpacpi_disclose_usertask("procfs wan", "read");
3614
3615 if (!tp_features.wan)
3616 len += sprintf(p + len, "status:\t\tnot supported\n");
3617 else {
3618 len += sprintf(p + len, "status:\t\t%s\n",
3619 (status == RFKILL_STATE_UNBLOCKED) ?
3620 "enabled" : "disabled");
3621 len += sprintf(p + len, "commands:\tenable, disable\n");
3622 }
3623
3624 return len;
3625} 3730}
3626 3731
3627static int wan_write(char *buf) 3732static int wan_write(char *buf)
3628{ 3733{
3629 char *cmd; 3734 return tpacpi_rfk_procfs_write(TPACPI_RFK_WWAN_SW_ID, buf);
3630 int state = -1;
3631
3632 if (!tp_features.wan)
3633 return -ENODEV;
3634
3635 while ((cmd = next_cmd(&buf))) {
3636 if (strlencmp(cmd, "enable") == 0) {
3637 state = 1;
3638 } else if (strlencmp(cmd, "disable") == 0) {
3639 state = 0;
3640 } else
3641 return -EINVAL;
3642 }
3643
3644 if (state != -1) {
3645 tpacpi_disclose_usertask("procfs wan",
3646 "attempt to %s\n",
3647 state ? "enable" : "disable");
3648 wan_set_radiosw(state, 1);
3649 }
3650
3651 return 0;
3652} 3735}
3653 3736
3654static struct ibm_struct wan_driver_data = { 3737static struct ibm_struct wan_driver_data = {
@@ -3672,108 +3755,59 @@ enum {
3672 3755
3673#define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" 3756#define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw"
3674 3757
3675static struct rfkill *tpacpi_uwb_rfkill; 3758static int uwb_get_status(void)
3676
3677static int uwb_get_radiosw(void)
3678{ 3759{
3679 int status; 3760 int status;
3680 3761
3681 if (!tp_features.uwb)
3682 return -ENODEV;
3683
3684 /* WLSW overrides UWB in firmware/hardware, reflect that */
3685 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
3686 return RFKILL_STATE_HARD_BLOCKED;
3687
3688#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 3762#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3689 if (dbg_uwbemul) 3763 if (dbg_uwbemul)
3690 return (tpacpi_uwb_emulstate) ? 3764 return (tpacpi_uwb_emulstate) ?
3691 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; 3765 TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
3692#endif 3766#endif
3693 3767
3694 if (!acpi_evalf(hkey_handle, &status, "GUWB", "d")) 3768 if (!acpi_evalf(hkey_handle, &status, "GUWB", "d"))
3695 return -EIO; 3769 return -EIO;
3696 3770
3697 return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ? 3771 return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ?
3698 RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED; 3772 TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
3699} 3773}
3700 3774
3701static void uwb_update_rfk(void) 3775static int uwb_set_status(enum tpacpi_rfkill_state state)
3702{ 3776{
3703 int status; 3777 int status;
3704 3778
3705 if (!tpacpi_uwb_rfkill)
3706 return;
3707
3708 status = uwb_get_radiosw();
3709 if (status < 0)
3710 return;
3711 rfkill_force_state(tpacpi_uwb_rfkill, status);
3712
3713 vdbg_printk(TPACPI_DBG_RFKILL, 3779 vdbg_printk(TPACPI_DBG_RFKILL,
3714 "forced rfkill state to %d\n", 3780 "will attempt to %s UWB\n",
3715 status); 3781 (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable");
3716}
3717
3718static int uwb_set_radiosw(int radio_on, int update_rfk)
3719{
3720 int status;
3721
3722 if (!tp_features.uwb)
3723 return -ENODEV;
3724
3725 /* WLSW overrides UWB in firmware/hardware, but there is no
3726 * reason to risk weird behaviour. */
3727 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
3728 && radio_on)
3729 return -EPERM;
3730
3731 vdbg_printk(TPACPI_DBG_RFKILL,
3732 "will %s UWB\n", radio_on ? "enable" : "disable");
3733 3782
3734#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES 3783#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
3735 if (dbg_uwbemul) { 3784 if (dbg_uwbemul) {
3736 tpacpi_uwb_emulstate = !!radio_on; 3785 tpacpi_uwb_emulstate = (state == TPACPI_RFK_RADIO_ON);
3737 if (update_rfk)
3738 uwb_update_rfk();
3739 return 0; 3786 return 0;
3740 } 3787 }
3741#endif 3788#endif
3742 3789
3743 status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0; 3790 if (state == TPACPI_RFK_RADIO_ON)
3791 status = TP_ACPI_UWB_RADIOSSW;
3792 else
3793 status = 0;
3794
3744 if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status)) 3795 if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status))
3745 return -EIO; 3796 return -EIO;
3746 3797
3747 if (update_rfk)
3748 uwb_update_rfk();
3749
3750 return 0; 3798 return 0;
3751} 3799}
3752 3800
3753/* --------------------------------------------------------------------- */ 3801/* --------------------------------------------------------------------- */
3754 3802
3755static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state) 3803static const struct tpacpi_rfk_ops uwb_tprfk_ops = {
3756{ 3804 .get_status = uwb_get_status,
3757 int uwbs = uwb_get_radiosw(); 3805 .set_status = uwb_set_status,
3758 3806};
3759 if (uwbs < 0)
3760 return uwbs;
3761
3762 *state = uwbs;
3763 return 0;
3764}
3765
3766static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state)
3767{
3768 dbg_printk(TPACPI_DBG_RFKILL,
3769 "request to change radio state to %d\n", state);
3770 return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
3771}
3772 3807
3773static void uwb_exit(void) 3808static void uwb_exit(void)
3774{ 3809{
3775 if (tpacpi_uwb_rfkill) 3810 tpacpi_destroy_rfkill(TPACPI_RFK_UWB_SW_ID);
3776 rfkill_unregister(tpacpi_uwb_rfkill);
3777} 3811}
3778 3812
3779static int __init uwb_init(struct ibm_init_struct *iibm) 3813static int __init uwb_init(struct ibm_init_struct *iibm)
@@ -3813,13 +3847,10 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
3813 return 1; 3847 return 1;
3814 3848
3815 res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, 3849 res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID,
3816 &tpacpi_uwb_rfkill, 3850 &uwb_tprfk_ops,
3817 RFKILL_TYPE_UWB, 3851 RFKILL_TYPE_UWB,
3818 TPACPI_RFK_UWB_SW_NAME, 3852 TPACPI_RFK_UWB_SW_NAME,
3819 false, 3853 false);
3820 tpacpi_uwb_rfk_set,
3821 tpacpi_uwb_rfk_get);
3822
3823 return res; 3854 return res;
3824} 3855}
3825 3856