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