Thinkpad X200s

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi folks,

I've been investigating a problem with rfkill on the X200s from Lenovo.
The problem exists in debians 2.6.30-2 kernel and persists right up to -git

I've found that the WWAN card does not behave as expected on suspend /
resume.

The problem seems to be the rfkill layer getting out of sync with ACPIs
idea of the hardware state.

If the laptop is suspended with WWAN enabled, it will wake up with it
disabled, requiring a toggle of the physical WWAN switch or a prod in
/sys to get it going again.

I wrote a little patch that "cures" this issue (attached), however it is
far from perfect.

For example, even with this patch, when the side switch is used, it
overrides the soft setting for the devices completely, so if for example
the WWAN was off, then toggling the switch changes its rfkill state from
0 -> 2, and then from 2 -> 1

It *appears* from the code that it should be possible to get the device
to power up in the state it was last in, but I cant make mine do it.

I've also noticed that on recent kernels, I get an extra rfkillswitch
for hci0 (bluetooth) in addition to the ACPI one. This vanishes if power
is toggled using the ACPI rfkill softswitch, however bluetooth continues
to work (when enabled).

Has anyone else experienced these issues?

-Ian
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index d93108d..4896af5 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -4055,14 +4055,37 @@ enum {
 };
 
 #define TPACPI_RFK_WWAN_SW_NAME		"tpacpi_wwan_sw"
+static int laststat;
 
 static void wan_suspend(pm_message_t state)
 {
+	int status;
+	acpi_evalf(hkey_handle, &status, "GWAN", "d");
+	laststat = status;
+        printk("s%d stat.\n", status);
 	/* Try to make sure radio will resume powered off */
 	if (!acpi_evalf(NULL, NULL, "\\WGSV", "qvd",
 		   TP_ACPI_WGSV_PWR_OFF_ON_RESUME))
 		vdbg_printk(TPACPI_DBG_RFKILL,
 			"WWAN power down on resume request failed\n");
+	printk("sus\n");
+	acpi_evalf(hkey_handle, &status, "GWAN", "d");
+        printk("s%d stat.\n", status);
+}
+
+static int wan_resume(pm_message_t state)
+{
+	int status;
+	printk("res\n");
+	acpi_evalf(hkey_handle, &status, "GWAN", "d");
+	printk("r%d stat.\n", status);
+        printk("l%d stat.\n", laststat);
+	if(laststat & TP_ACPI_WANCARD_RADIOSSW) {
+	acpi_evalf(hkey_handle, NULL, "SWAN", "vd", TP_ACPI_WANCARD_RADIOSSW);
+	acpi_evalf(hkey_handle, &status, "GWAN", "d");
+	printk("r%d stat.\n", status);
+	tpacpi_rfk_update_swstate_all();
+	}
 }
 
 static int wan_get_status(void)
@@ -4078,6 +4101,7 @@ static int wan_get_status(void)
 	if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
 		return -EIO;
 
+	printk("gs: %d\n", status);
 	return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0) ?
 			TPACPI_RFK_RADIO_ON : TPACPI_RFK_RADIO_OFF;
 }
@@ -4103,6 +4127,7 @@ static int wan_set_status(enum tpacpi_rfkill_state state)
 	else
 		status = 0;
 
+	printk("ss: %d\n", status);
 	if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
 		return -EIO;
 
@@ -4239,6 +4264,7 @@ static struct ibm_struct wan_driver_data = {
 	.read = wan_read,
 	.write = wan_write,
 	.exit = wan_exit,
+	.resume = wan_resume,
 	.suspend = wan_suspend,
 	.shutdown = wan_shutdown,
 };

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux