From ce363c2bcb2303e7fad3a79398db739c6995141b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jun 2014 16:45:51 +0200 Subject: [PATCH] ideapad-laptop: Change Lenovo Yoga 2 series rfkill handling It seems that the same problems which lead to adding an rfkill blacklist and putting the Lenovo Yoga 2 11 on it are also present on the Lenovo Yoga 2 13 and Lenovo Yoga 2 Pro too: https://bugzilla.redhat.com/show_bug.cgi?id=1021036 https://forums.lenovo.com/t5/Linux-Discussion/Yoga-2-13-not-Pro-Linux-Warning/m-p/1517612 Testing has shown that the firmware rfkill settings are persistent over reboots. So blacklisting the driver is not good enough, if the wifi is blocked at the firmware level the wifi needs to be explictly unblocked through the ideapad-laptop interface. And at least on the Lenovo Yoga 2 13 the VPCCMD_RF register which on devices with hardware kill switch reports the hardware switch state, needs to be explictly set to 1 (radio enabled / not blocked). So this patch does 3 things to get proper rfkill handling on these models: 1) Instead of blacklisting the rfkill functionality, which means that people with a firmware blocked wifi get stuck in that situation, ignore the value reported by the not present hardware rfkill switch, as this is what is causing ideapad-laptop to wrongly report all radios as hardware blocks. But do register the rfkill interfaces so that the user can soft [un]block them. 2) On models without a hardware rfkill switch, explictly set VPCCMD_RF to 1 3) Drop the " 11" postfix from the dmi match string, as the entire Yoga 2 series is affected. Yoga 2 11: Reported-and-tested-by: Vincent Gerris Yoga 2 13: Tested-by: madls05 Yoga 2 Pro: Reported-and-tested-by: Peter F. Patel-Schneider Signed-off-by: Hans de Goede Signed-off-by: Matthew Garrett --- drivers/platform/x86/ideapad-laptop.c | 41 ++++++++++++++++++--------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index b4c495a62eec..b0e3a2eef0ac 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -87,6 +87,7 @@ struct ideapad_private { struct backlight_device *blightdev; struct dentry *debug; unsigned long cfg; + bool has_hw_rfkill_switch; }; static bool no_bt_rfkill; @@ -473,12 +474,14 @@ static struct rfkill_ops ideapad_rfk_ops = { static void ideapad_sync_rfk_state(struct ideapad_private *priv) { - unsigned long hw_blocked; + unsigned long hw_blocked = 0; int i; - if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked)) - return; - hw_blocked = !hw_blocked; + if (priv->has_hw_rfkill_switch) { + if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked)) + return; + hw_blocked = !hw_blocked; + } for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) if (priv->rfk[i]) @@ -821,14 +824,17 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) } } -/* Blacklist for devices where the ideapad rfkill interface does not work */ -static struct dmi_system_id rfkill_blacklist[] = { - /* The Lenovo Yoga 2 11 always reports everything as blocked */ +/* + * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF + * always results in 0 on these models, causing ideapad_laptop to wrongly + * report all radios as hardware-blocked. + */ +static struct dmi_system_id no_hw_rfkill_list[] = { { - .ident = "Lenovo Yoga 2 11", + .ident = "Lenovo Yoga 2 11 / 13 / Pro", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"), }, }, {} @@ -856,6 +862,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) priv->cfg = cfg; priv->adev = adev; priv->platform_device = pdev; + priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list); ret = ideapad_sysfs_init(priv); if (ret) @@ -869,11 +876,17 @@ static int ideapad_acpi_add(struct platform_device *pdev) if (ret) goto input_failed; - if (!dmi_check_system(rfkill_blacklist)) { - for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) - if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) - ideapad_register_rfkill(priv, i); - } + /* + * On some models without a hw-switch (the yoga 2 13 at least) + * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work. + */ + if (!priv->has_hw_rfkill_switch) + write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1); + + for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) + if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) + ideapad_register_rfkill(priv, i); + ideapad_sync_rfk_state(priv); ideapad_sync_touchpad_state(priv);