sudo apt-get install linux-source

sudo su
cd /usr/local/src

cat<<EOF>linux-ideapad-lenovo-g40-30.patch

--- orig/ideapad-laptop.c       2015-05-01 01:32:41.760340514 +0200
+++ mine/ideapad-laptop.c       2015-05-01 01:32:44.116343594 +0200
@@ -26,8 +26,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
+#include <linux/acpi.h>
 #include <linux/rfkill.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
@@ -37,6 +36,8 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/i8042.h>
+#include <linux/dmi.h>
+#include <linux/device.h>
 
 #define IDEAPAD_RFKILL_DEV_NUM (3)
 
@@ -86,6 +87,7 @@
        struct backlight_device *blightdev;
        struct dentry *debug;
        unsigned long cfg;
+       bool has_hw_rfkill_switch;
 };
 
 static bool no_bt_rfkill;
@@ -472,12 +474,14 @@
 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])
@@ -820,6 +824,29 @@
        }
 }
 
+/*
+ * 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 / 13 / Pro",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"),
+               },
+       },
+       {
+               .ident = "Lenovo G40-30",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"),
+               },
+       },
+       {}
+};
 static int ideapad_acpi_add(struct platform_device *pdev)
 {
        int ret, i;
@@ -834,7 +861,7 @@
        if (read_method_int(adev->handle, "_CFG", &cfg))
                return -ENODEV;
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
 
@@ -842,10 +869,11 @@
        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)
-               goto sysfs_failed;
+               return ret;
 
        ret = ideapad_debugfs_init(priv);
        if (ret)
@@ -855,12 +883,17 @@
        if (ret)
                goto input_failed;
 
-       for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; 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);
-               else
-                       priv->rfk[i] = NULL;
-       }
+
        ideapad_sync_rfk_state(priv);
        ideapad_sync_touchpad_state(priv);
 
@@ -885,8 +918,6 @@
        ideapad_debugfs_exit(priv);
 debugfs_failed:
        ideapad_sysfs_exit(priv);
-sysfs_failed:
-       kfree(priv);
        return ret;
 }
 
@@ -904,7 +935,6 @@
        ideapad_debugfs_exit(priv);
        ideapad_sysfs_exit(priv);
        dev_set_drvdata(&pdev->dev, NULL);
-       kfree(priv);
 
        return 0;
 }


###
 cat /usr/local/src/linux-ideapad-lenovo-g40-30-3.19.0.patch
--- ./drivers/platform/x86/ideapad-laptop.c.orig        2015-05-01 21:54:22.304179266 +0200
+++ ./drivers/platform/x86/ideapad-laptop.c     2015-05-01 21:55:24.820686950 +0200
@@ -843,6 +843,13 @@
                        DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3 Pro-1370"),
                },
        },
+       {
+               .ident = "Lenovo G40-30",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"),
+               },
+       },
        {}
 };

MISC

MORE

rfkill.txt · Last modified: 2015/11/01 20:18 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 3.0 Unported
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki