ACPI: thinkpad-acpi: export to sysfs the state of the radio slider switch

Some ThinkPad models, notably the T60 and X60, have a slider switch to
enable and disable the radios.  The switch has the capability of
force-disabling the radios in hardware on most models, and it is supposed
to affect all radios (WLAN, WWAN, BlueTooth).

Export the switch state as a sysfs attribute, on ThinkPads where it is
available.

Thanks to Henning Schild for asking for this feature, and for tracking down
the EC register that holds the radio switch state.

Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Cc: Henning Schild <henning@wh9.tu-dresden.de>
Signed-off-by: Len Brown <len.brown@intel.com>
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 8c08868..3cf37bb 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -733,6 +733,13 @@
 
 static struct attribute_set *hotkey_dev_attributes;
 
+static int hotkey_get_wlsw(int *status)
+{
+	if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
+		return -EIO;
+	return 0;
+}
+
 /* sysfs hotkey enable ------------------------------------------------- */
 static ssize_t hotkey_enable_show(struct device *dev,
 			   struct device_attribute *attr,
@@ -853,6 +860,22 @@
 	__ATTR(hotkey_recommended_mask, S_IRUGO,
 		hotkey_recommended_mask_show, NULL);
 
+/* sysfs hotkey radio_sw ----------------------------------------------- */
+static ssize_t hotkey_radio_sw_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	int res, s;
+	res = hotkey_get_wlsw(&s);
+	if (res < 0)
+		return res;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_radio_sw =
+	__ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
+
 /* --------------------------------------------------------------------- */
 
 static struct attribute *hotkey_mask_attributes[] = {
@@ -866,6 +889,7 @@
 static int __init hotkey_init(struct ibm_init_struct *iibm)
 {
 	int res;
+	int status;
 
 	vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
 
@@ -879,7 +903,7 @@
 		str_supported(tp_features.hotkey));
 
 	if (tp_features.hotkey) {
-		hotkey_dev_attributes = create_attr_set(6, NULL);
+		hotkey_dev_attributes = create_attr_set(7, NULL);
 		if (!hotkey_dev_attributes)
 			return -ENOMEM;
 		res = add_to_attr_set(hotkey_dev_attributes,
@@ -908,11 +932,21 @@
 				hotkey_mask_attributes,
 				ARRAY_SIZE(hotkey_mask_attributes));
 		}
+
+		/* Not all thinkpads have a hardware radio switch */
+		if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+			tp_features.hotkey_wlsw = 1;
+			printk(IBM_INFO
+				"radio switch found; radios are %s\n",
+				enabled(status, 0));
+			res = add_to_attr_set(hotkey_dev_attributes,
+					&dev_attr_hotkey_radio_sw.attr);
+		}
+
 		if (!res)
 			res = register_attr_set_with_sysfs(
 					hotkey_dev_attributes,
 					&tpacpi_pdev->dev.kobj);
-
 		if (res)
 			return res;
 	}