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, };