sudo apt-get install linux-source sudo su cd /usr/local/src cat<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 #include #include -#include -#include +#include #include #include #include @@ -37,6 +36,8 @@ #include #include #include +#include +#include #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 ===== * http://iseborn.eu/2014/07/21/activating-wifi-in-ubuntu-on-lenovo-yoga-2/ * http://ubuntuforums.org/showthread.php?t=2276168&p=13276318#post13276318 * http://forums.linuxmint.com/viewtopic.php?f=53&t=192937&p=1013292#p1013292 ===== MORE ===== @TaG: IdeaPad