From 21a3542753a63091bc4700525e6096d76fe32f62 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 15 Apr 2014 10:54:11 +0800 Subject: [PATCH 01/17] platform-drivers-x86: intel_pmic_gpio: Fix off-by-one valid offset range check Only pin 0-7 support input, so the valid offset range should be 0 ~ 7. Signed-off-by: Axel Lin Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_pmic_gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 2805988485f6..40929e4f7ad7 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c @@ -91,7 +91,7 @@ static void pmic_program_irqtype(int gpio, int type) static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { - if (offset > 8) { + if (offset >= 8) { pr_err("only pin 0-7 support input\n"); return -1;/* we only have 8 GPIO can use as input */ } @@ -130,7 +130,7 @@ static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset) int ret; /* we only have 8 GPIO pins we can use as input */ - if (offset > 8) + if (offset >= 8) return -EOPNOTSUPP; ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r); if (ret < 0) From fe808bfb59d693e07ee23c99542cd64e1f41b8c9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 29 Apr 2014 15:15:38 +0200 Subject: [PATCH 02/17] toshiba_acpi: Add alternative keymap support for Satellite M840 Toshiba Satellite M840 laptop has a complete different keymap although it's bound with the same ACPI ID "TOS1900". This patch provides an alternative keymap specific to this machine by identifying via DMI matching. The keymap table doesn't fill all entries that were used before since some keys aren't found on this machine at all. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=69761 Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=812209 Reported-and-tested-by: Federico Vecchiarelli Signed-off-by: Takashi Iwai Signed-off-by: Matthew Garrett --- drivers/platform/x86/toshiba_acpi.c | 30 ++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 46473ca7566b..76441dcbe5ff 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -56,6 +56,7 @@ #include #include #include +#include #include MODULE_AUTHOR("John Belmonte"); @@ -213,6 +214,30 @@ static const struct key_entry toshiba_acpi_keymap[] = { { KE_END, 0 }, }; +/* alternative keymap */ +static const struct dmi_system_id toshiba_alt_keymap_dmi[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite M840"), + }, + }, + {} +}; + +static const struct key_entry toshiba_acpi_alt_keymap[] = { + { KE_KEY, 0x157, { KEY_MUTE } }, + { KE_KEY, 0x102, { KEY_ZOOMOUT } }, + { KE_KEY, 0x103, { KEY_ZOOMIN } }, + { KE_KEY, 0x139, { KEY_ZOOMRESET } }, + { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, + { KE_KEY, 0x158, { KEY_WLAN } }, + { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, + { KE_END, 0 }, +}; + /* utility */ @@ -1440,6 +1465,7 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) acpi_handle ec_handle; int error; u32 hci_result; + const struct key_entry *keymap = toshiba_acpi_keymap; dev->hotkey_dev = input_allocate_device(); if (!dev->hotkey_dev) @@ -1449,7 +1475,9 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) dev->hotkey_dev->phys = "toshiba_acpi/input0"; dev->hotkey_dev->id.bustype = BUS_HOST; - error = sparse_keymap_setup(dev->hotkey_dev, toshiba_acpi_keymap, NULL); + if (dmi_check_system(toshiba_alt_keymap_dmi)) + keymap = toshiba_acpi_alt_keymap; + error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL); if (error) goto err_free_dev; From 0ca849ea4fb86d9ee61435559f7159ed627895c3 Mon Sep 17 00:00:00 2001 From: Scott Thrasher Date: Tue, 6 May 2014 08:06:42 -0700 Subject: [PATCH 03/17] platform/x86: samsung-laptop: Add support for Samsung's NP7[34]0U3E models. These models have only 4 levels of keyboard backlight brightness and forget how to work the backlight after resuming from S3 sleep. I've added a quirk to set the appropriate number of backlight levels, and one to re-enable the keyboard backlight on resume. (Whitespace cleaned up by Matthew Garrett) Signed-off-by: Scott Thrasher Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index d1f030053176..5a5966512277 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -27,6 +27,7 @@ #include #include #include +#include #include /* @@ -340,6 +341,8 @@ struct samsung_laptop { struct samsung_laptop_debug debug; struct samsung_quirks *quirks; + struct notifier_block pm_nb; + bool handle_backlight; bool has_stepping_quirk; @@ -348,6 +351,8 @@ struct samsung_laptop { struct samsung_quirks { bool broken_acpi_video; + bool four_kbd_backlight_levels; + bool enable_kbd_backlight; }; static struct samsung_quirks samsung_unknown = {}; @@ -356,6 +361,11 @@ static struct samsung_quirks samsung_broken_acpi_video = { .broken_acpi_video = true, }; +static struct samsung_quirks samsung_np740u3e = { + .four_kbd_backlight_levels = true, + .enable_kbd_backlight = true, +}; + static bool force; module_param(force, bool, 0); MODULE_PARM_DESC(force, @@ -1051,6 +1061,8 @@ static int __init samsung_leds_init(struct samsung_laptop *samsung) samsung->kbd_led.brightness_set = kbd_led_set; samsung->kbd_led.brightness_get = kbd_led_get; samsung->kbd_led.max_brightness = 8; + if (samsung->quirks->four_kbd_backlight_levels) + samsung->kbd_led.max_brightness = 4; ret = led_classdev_register(&samsung->platform_device->dev, &samsung->kbd_led); @@ -1414,6 +1426,19 @@ static void samsung_platform_exit(struct samsung_laptop *samsung) } } +static int samsung_pm_notification(struct notifier_block *nb, + unsigned long val, void *ptr) +{ + struct samsung_laptop *samsung; + + samsung = container_of(nb, struct samsung_laptop, pm_nb); + if (val == PM_POST_HIBERNATION && + samsung->quirks->enable_kbd_backlight) + kbd_backlight_enable(samsung); + + return 0; +} + static int __init samsung_platform_init(struct samsung_laptop *samsung) { struct platform_device *pdev; @@ -1534,6 +1559,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { }, .driver_data = &samsung_broken_acpi_video, }, + { + .callback = samsung_dmi_matched, + .ident = "730U3E/740U3E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"), + }, + .driver_data = &samsung_np740u3e, + }, { }, }; MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); @@ -1608,6 +1642,9 @@ static int __init samsung_init(void) if (ret) goto error_debugfs; + samsung->pm_nb.notifier_call = samsung_pm_notification; + register_pm_notifier(&samsung->pm_nb); + samsung_platform_device = samsung->platform_device; return ret; @@ -1633,6 +1670,7 @@ static void __exit samsung_exit(void) struct samsung_laptop *samsung; samsung = platform_get_drvdata(samsung_platform_device); + unregister_pm_notifier(&samsung->pm_nb); samsung_debugfs_exit(samsung); samsung_leds_exit(samsung); From 7939831eacd81fccbd7a956b30c7bb3abb9079db Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 6 May 2014 17:52:26 +0200 Subject: [PATCH 04/17] pvpanic: Set high notifier priority We've observed the missing pvpanic call at panic, and it turned out that this was blocked by the broken notifier of drm_fb_helper, where scheduling may be called during switching to the fb console. It's fairly difficult to fix the drm_fb problem and a quick fix isn't foreseen, a simpler solution for the missing pvpanic call would be just to call this earlier. In order to assure that, this patch sets a higher priority to pvpanic notifier_block. Once when the issue of drm_fb is resolved, we can remove this priority again. Signed-off-by: Takashi Iwai Signed-off-by: Matthew Garrett --- drivers/platform/x86/pvpanic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/pvpanic.c b/drivers/platform/x86/pvpanic.c index c9f6e511daa6..073a90a63dbc 100644 --- a/drivers/platform/x86/pvpanic.c +++ b/drivers/platform/x86/pvpanic.c @@ -70,6 +70,7 @@ pvpanic_panic_notify(struct notifier_block *nb, unsigned long code, static struct notifier_block pvpanic_panic_nb = { .notifier_call = pvpanic_panic_notify, + .priority = 1, /* let this called before broken drm_fb_helper */ }; From b998680e9adea22159b66bd59ecdf07624e201ed Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 7 May 2014 15:08:09 -0500 Subject: [PATCH 05/17] alienware-wmi: Update WMAX brightness method limit to 15 This more closely reflects what the hardware can actually support. Signed-off-by: Mario Limonciello Signed-off-by: Matthew Garrett --- drivers/platform/x86/alienware-wmi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 541f9514f76f..e5329eac86b7 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -350,12 +350,11 @@ static int alienware_zone_init(struct platform_device *dev) char *name; if (interface == WMAX) { - global_led.max_brightness = 100; lighting_control_state = WMAX_RUNNING; } else if (interface == LEGACY) { - global_led.max_brightness = 0x0F; lighting_control_state = LEGACY_RUNNING; } + global_led.max_brightness = 0x0F; global_brightness = global_led.max_brightness; /* From bc2ef884320bdca8d2544d517ac5489bb1722896 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Wed, 7 May 2014 15:08:10 -0500 Subject: [PATCH 06/17] alienware-wmi: For WMAX HDMI method, introduce a way to query HDMI cable status Since there are now multiple HDMI attributes associated with the WMAX method, create a sysfs group for them instead. Signed-off-by: Mario Limonciello Signed-off-by: Matthew Garrett --- drivers/platform/x86/alienware-wmi.c | 118 ++++++++++++++++++++------- 1 file changed, 88 insertions(+), 30 deletions(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index e5329eac86b7..297b6640213f 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -32,6 +32,7 @@ #define WMAX_METHOD_HDMI_STATUS 0x2 #define WMAX_METHOD_BRIGHTNESS 0x3 #define WMAX_METHOD_ZONE_CONTROL 0x4 +#define WMAX_METHOD_HDMI_CABLE 0x5 MODULE_AUTHOR("Mario Limonciello "); MODULE_DESCRIPTION("Alienware special feature control"); @@ -422,41 +423,85 @@ static void alienware_zone_exit(struct platform_device *dev) The HDMI mux sysfs node indicates the status of the HDMI input mux. It can toggle between standard system GPU output and HDMI input. */ -static ssize_t show_hdmi(struct device *dev, struct device_attribute *attr, - char *buf) +static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, + u32 command, int *out_data) { acpi_status status; - struct acpi_buffer input; union acpi_object *obj; - u32 tmp = 0; - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer input; + struct acpi_buffer output; + + input.length = (acpi_size) sizeof(*in_args); + input.pointer = in_args; + if (out_data != NULL) { + output.length = ACPI_ALLOCATE_BUFFER; + output.pointer = NULL; + status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, + command, &input, &output); + } else + status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, + command, &input, NULL); + + if (ACPI_SUCCESS(status) && out_data != NULL) { + obj = (union acpi_object *)output.pointer; + if (obj && obj->type == ACPI_TYPE_INTEGER) + *out_data = (u32) obj->integer.value; + } + return status; + +} + +static ssize_t show_hdmi_cable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + acpi_status status; + u32 out_data; struct hdmi_args in_args = { .arg = 0, }; - input.length = (acpi_size) sizeof(in_args); - input.pointer = &in_args; - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, - WMAX_METHOD_HDMI_STATUS, &input, &output); + status = + alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE, + (u32 *) &out_data); + if (ACPI_SUCCESS(status)) { + if (out_data == 0) + return scnprintf(buf, PAGE_SIZE, + "[unconnected] connected unknown\n"); + else if (out_data == 1) + return scnprintf(buf, PAGE_SIZE, + "unconnected [connected] unknown\n"); + } + pr_err("alienware-wmi: unknown HDMI cable status: %d\n", status); + return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n"); +} + +static ssize_t show_hdmi_source(struct device *dev, + struct device_attribute *attr, char *buf) +{ + acpi_status status; + u32 out_data; + struct hdmi_args in_args = { + .arg = 0, + }; + status = + alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_STATUS, + (u32 *) &out_data); if (ACPI_SUCCESS(status)) { - obj = (union acpi_object *)output.pointer; - if (obj && obj->type == ACPI_TYPE_INTEGER) - tmp = (u32) obj->integer.value; - if (tmp == 1) + if (out_data == 1) return scnprintf(buf, PAGE_SIZE, "[input] gpu unknown\n"); - else if (tmp == 2) + else if (out_data == 2) return scnprintf(buf, PAGE_SIZE, "input [gpu] unknown\n"); } - pr_err("alienware-wmi: unknown HDMI status: %d\n", status); + pr_err("alienware-wmi: unknown HDMI source status: %d\n", out_data); return scnprintf(buf, PAGE_SIZE, "input gpu [unknown]\n"); } -static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t toggle_hdmi_source(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { - struct acpi_buffer input; acpi_status status; struct hdmi_args args; if (strcmp(buf, "gpu\n") == 0) @@ -466,33 +511,46 @@ static ssize_t toggle_hdmi(struct device *dev, struct device_attribute *attr, else args.arg = 3; pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); - input.length = (acpi_size) sizeof(args); - input.pointer = &args; - status = wmi_evaluate_method(WMAX_CONTROL_GUID, 1, - WMAX_METHOD_HDMI_SOURCE, &input, NULL); + + status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); + if (ACPI_FAILURE(status)) pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", status); return count; } -static DEVICE_ATTR(hdmi, S_IRUGO | S_IWUSR, show_hdmi, toggle_hdmi); +static DEVICE_ATTR(cable, S_IRUGO, show_hdmi_cable, NULL); +static DEVICE_ATTR(source, S_IRUGO | S_IWUSR, show_hdmi_source, + toggle_hdmi_source); -static void remove_hdmi(struct platform_device *device) +static struct attribute *hdmi_attrs[] = { + &dev_attr_cable.attr, + &dev_attr_source.attr, + NULL, +}; + +static struct attribute_group hdmi_attribute_group = { + .name = "hdmi", + .attrs = hdmi_attrs, +}; + +static void remove_hdmi(struct platform_device *dev) { - device_remove_file(&device->dev, &dev_attr_hdmi); + sysfs_remove_group(&dev->dev.kobj, &hdmi_attribute_group); } -static int create_hdmi(void) +static int create_hdmi(struct platform_device *dev) { - int ret = -ENOMEM; - ret = device_create_file(&platform_device->dev, &dev_attr_hdmi); + int ret; + + ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group); if (ret) goto error_create_hdmi; return 0; error_create_hdmi: - remove_hdmi(platform_device); + remove_hdmi(dev); return ret; } @@ -526,7 +584,7 @@ static int __init alienware_wmi_init(void) goto fail_platform_device2; if (interface == WMAX) { - ret = create_hdmi(); + ret = create_hdmi(platform_device); if (ret) goto fail_prep_hdmi; } From c08db55fe1455202e4bcda416e88bbbc20700dc4 Mon Sep 17 00:00:00 2001 From: Andreas Utterberg Date: Tue, 6 May 2014 22:27:45 +0200 Subject: [PATCH 07/17] asus-wmi: Set WAPF to 4 for Asus X550CA The 'asus-nb-wmi' WAPF parameter must be set to 4, so the internal Wireless LAN device is operational. Signed-off-by: Andreas Utterberg Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 563f59efa669..ddf0eefd862c 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -135,6 +135,15 @@ static struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_x401u, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X550CA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X550CA"), + }, + .driver_data = &quirk_asus_x401u, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. X55A", From 85093f79f586176f8bbf90e56e22a3dfa526e334 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 13 May 2014 16:00:28 +0200 Subject: [PATCH 08/17] ideapad-laptop: Blacklist rfkill control on the Lenovo Yoga 2 11 The Lenovo Yoga 2 11 always reports everything as blocked, causing userspace to not even try to use the wlan / bluetooth even though they work fine. Note this patch also removes the "else priv->rfk[i] = NULL;" bit of the rfkill initialization, it is not necessary as the priv struct is allocated with kzalloc. Reported-and-tested-by: Vincent Gerris Signed-off-by: Hans de Goede Signed-off-by: Matthew Garrett --- drivers/platform/x86/ideapad-laptop.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 6dd060a0bb65..219eb289a909 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -36,6 +36,7 @@ #include #include #include +#include #define IDEAPAD_RFKILL_DEV_NUM (3) @@ -819,6 +820,19 @@ 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 */ + { + .ident = "Lenovo Yoga 2 11", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"), + }, + }, + {} +}; + static int ideapad_acpi_add(struct platform_device *pdev) { int ret, i; @@ -854,11 +868,10 @@ static int ideapad_acpi_add(struct platform_device *pdev) if (ret) goto input_failed; - 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; + 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); } ideapad_sync_rfk_state(priv); ideapad_sync_touchpad_state(priv); From 4cbfdac12cd14252e5bd4c963cffd7e61a698396 Mon Sep 17 00:00:00 2001 From: Ismael Luceno Date: Wed, 21 May 2014 17:24:27 -0300 Subject: [PATCH 09/17] Documentation: Add list of laptop models supported by the Compal driver Signed-off-by: Ismael Luceno Signed-off-by: Matthew Garrett --- Documentation/platform/x86-laptop-drivers.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/platform/x86-laptop-drivers.txt diff --git a/Documentation/platform/x86-laptop-drivers.txt b/Documentation/platform/x86-laptop-drivers.txt new file mode 100644 index 000000000000..01facd2590bb --- /dev/null +++ b/Documentation/platform/x86-laptop-drivers.txt @@ -0,0 +1,18 @@ +compal-laptop +============= +List of supported hardware: + +by Compal: + Compal FL90/IFL90 + Compal FL91/IFL91 + Compal FL92/JFL92 + Compal FT00/IFT00 + +by Dell: + Dell Vostro 1200 + Dell Mini 9 (Inspiron 910) + Dell Mini 10 (Inspiron 1010) + Dell Mini 10v (Inspiron 1011) + Dell Mini 1012 (Inspiron 1012) + Dell Inspiron 11z (Inspiron 1110) + Dell Mini 12 (Inspiron 1210) From eec3b959f57508b250831ed10efa07f8209e9d1b Mon Sep 17 00:00:00 2001 From: Ismael Luceno Date: Wed, 21 May 2014 17:24:28 -0300 Subject: [PATCH 10/17] platform x86 Kconfig: Refer to the laptop list in the Compal driver help Signed-off-by: Ismael Luceno Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 27df2c533b09..3ba9c42408c5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -102,7 +102,7 @@ config DELL_LAPTOP default n ---help--- This driver adds support for rfkill and backlight control to Dell - laptops. + laptops (except for some models covered by the Compal driver). config DELL_WMI tristate "Dell WMI extras" @@ -265,23 +265,21 @@ config PANASONIC_LAPTOP R2, R3, R5, T2, W2 and Y2 series), say Y. config COMPAL_LAPTOP - tristate "Compal Laptop Extras" + tristate "Compal (and others) Laptop Extras" depends on ACPI depends on BACKLIGHT_CLASS_DEVICE depends on RFKILL depends on HWMON depends on POWER_SUPPLY ---help--- - This is a driver for laptops built by Compal: + This is a driver for laptops built by Compal, and some models by + other brands (e.g. Dell, Toshiba). - Compal FL90/IFL90 - Compal FL91/IFL91 - Compal FL92/JFL92 - Compal FT00/IFT00 + It adds support for rfkill, Bluetooth, WLAN and LCD brightness + control. - It adds support for Bluetooth, WLAN and LCD brightness control. - - If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here. + For a (possibly incomplete) list of supported laptops, please refer + to: Documentation/platform/x86-laptop-drivers.txt config SONY_LAPTOP tristate "Sony Laptop Extras" From 14627e36121c90b9a794ab0ea3195efa4c23373e Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 25 May 2014 13:05:45 +0530 Subject: [PATCH 11/17] ix86/mid/thermal: Introduce the use of the managed version of kzalloc This patch moves data allocated using kzalloc to managed data allocated using devm_kzalloc and cleans now unnecessary kfrees in probe and remove functions. The following Coccinelle semantic patch was used for making the change: @platform@ identifier p, probefn, removefn; @@ struct platform_driver p = { .probe = probefn, .remove = removefn, }; @prb@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression e; @@ removefn(...) { <... - kfree(e); ...> } Signed-off-by: Himangi Saraogi Signed-off-by: Matthew Garrett --- drivers/platform/x86/intel_mid_thermal.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 93fab8b70ce1..ab7860a21a22 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -481,7 +481,8 @@ static int mid_thermal_probe(struct platform_device *pdev) int i; struct platform_info *pinfo; - pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL); + pinfo = devm_kzalloc(&pdev->dev, sizeof(struct platform_info), + GFP_KERNEL); if (!pinfo) return -ENOMEM; @@ -489,7 +490,6 @@ static int mid_thermal_probe(struct platform_device *pdev) ret = mid_initialize_adc(&pdev->dev); if (ret) { dev_err(&pdev->dev, "ADC init failed"); - kfree(pinfo); return ret; } @@ -520,7 +520,6 @@ err: thermal_zone_device_unregister(pinfo->tzd[i]); } configure_adc(0); - kfree(pinfo); return ret; } @@ -541,8 +540,6 @@ static int mid_thermal_remove(struct platform_device *pdev) thermal_zone_device_unregister(pinfo->tzd[i]); } - kfree(pinfo); - /* Stop the ADC */ return configure_adc(0); } From 8ad3be1eacbe252b93f5a0478413774308f3dbfb Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 1 Jun 2014 14:58:52 +0200 Subject: [PATCH 12/17] platform: x86: asus-wmi.c: Cleaning up uninitialized variables There is a risk that the variable will be used without being initialized. This was largely found by using a static code analysis program called cppcheck. Signed-off-by: Rickard Strandqvist Signed-off-by: Matthew Garrett --- drivers/platform/x86/asus-wmi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 91ef69a52263..3c6ccedc82b6 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -266,7 +266,7 @@ static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_status status; union acpi_object *obj; - u32 tmp; + u32 tmp = 0; status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, &input, &output); @@ -277,8 +277,6 @@ static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, obj = (union acpi_object *)output.pointer; if (obj && obj->type == ACPI_TYPE_INTEGER) tmp = (u32) obj->integer.value; - else - tmp = 0; if (retval) *retval = tmp; From b02fdfcc40d74e64d3ea2a2120c96979e1b33128 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 1 Jun 2014 22:02:48 +0200 Subject: [PATCH 13/17] platform/x86: Fix run-time dependencies of OLPC drivers Let the xo15-ebook driver depend on OLPC as all other OLPC drivers already do. Add COMPILE_TEST as an alternative for both xo1-rfkill and xo15-ebook, to increase the build testing coverage. Signed-off-by: Jean Delvare Cc: Matthew Garrett Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 3ba9c42408c5..60d33834f28f 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -722,7 +722,7 @@ config IBM_RTL config XO1_RFKILL tristate "OLPC XO-1 software RF kill switch" - depends on OLPC + depends on OLPC || COMPILE_TEST depends on RFKILL ---help--- Support for enabling/disabling the WLAN interface on the OLPC XO-1 @@ -730,6 +730,7 @@ config XO1_RFKILL config XO15_EBOOK tristate "OLPC XO-1.5 ebook switch" + depends on OLPC || COMPILE_TEST depends on ACPI && INPUT ---help--- Support for the ebook switch on the OLPC XO-1.5 laptop. From b3facd7ba822ede3e98108e17a75f2c9c3e463af Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Mon, 9 Jun 2014 17:46:50 -0400 Subject: [PATCH 14/17] ideapad_laptop: Introduce the use of the managed version of kzalloc This patch moves data allocated using kzalloc to managed data allocated using devm_kzalloc and cleans now unnecessary kfrees in probe and remove functions. The label sysfs_failed is removed as it is no longer required. Also, linux/device.h is added to make sure the devm_*() routine declarations are unambiguously available. The following Coccinelle semantic patch was used for making the change: @platform@ identifier p, probefn, removefn; @@ struct platform_driver p = { .probe = probefn, .remove = removefn, }; @prb@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression e; @@ removefn(...) { <... - kfree(e); ...> } Signed-off-by: Himangi Saraogi Acked-by: Julia Lawall Signed-off-by: Matthew Garrett --- drivers/platform/x86/ideapad-laptop.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 219eb289a909..b4c495a62eec 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -37,6 +37,7 @@ #include #include #include +#include #define IDEAPAD_RFKILL_DEV_NUM (3) @@ -847,7 +848,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) 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; @@ -858,7 +859,7 @@ static int ideapad_acpi_add(struct platform_device *pdev) ret = ideapad_sysfs_init(priv); if (ret) - goto sysfs_failed; + return ret; ret = ideapad_debugfs_init(priv); if (ret) @@ -897,8 +898,6 @@ input_failed: ideapad_debugfs_exit(priv); debugfs_failed: ideapad_sysfs_exit(priv); -sysfs_failed: - kfree(priv); return ret; } @@ -916,7 +915,6 @@ static int ideapad_acpi_remove(struct platform_device *pdev) ideapad_debugfs_exit(priv); ideapad_sysfs_exit(priv); dev_set_drvdata(&pdev->dev, NULL); - kfree(priv); return 0; } From 4738d8aabe89d237f30a28c65f61391a1435e3a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= Date: Thu, 22 May 2014 13:15:48 +0200 Subject: [PATCH 15/17] platform: x86: dell-smo8800: Dell Latitude freefall driver (ACPI SMO8800/SMO8810) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This acpi driver provide supports for freefall sensors SMO8800/SMO8810 which can be found on Dell Latitude laptops. Driver register /dev/freefall misc device which has same interface as driver hp_accel freefall driver. So any existing applications for HP freefall sensor /dev/freefall will work for with this new driver for Dell Latitude laptops too. Signed-off-by: Pali Rohár Cc: Sonal Santan Tested-By: Valdis Kletnieks Acked-By: Valdis Kletnieks Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 10 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/dell-smo8800.c | 233 ++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 drivers/platform/x86/dell-smo8800.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 60d33834f28f..172f26ce59ac 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -127,6 +127,16 @@ config DELL_WMI_AIO To compile this driver as a module, choose M here: the module will be called dell-wmi-aio. +config DELL_SMO8800 + tristate "Dell Latitude freefall driver (ACPI SMO8800/SMO8810)" + depends on ACPI + ---help--- + Say Y here if you want to support SMO8800/SMO8810 freefall device + on Dell Latitude laptops. + + To compile this driver as a module, choose M here: the module will + be called dell-smo8800. + config FUJITSU_LAPTOP tristate "Fujitsu Laptop Extras" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 1a2eafc9d48e..c4ca428fd3db 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_DELL_WMI) += dell-wmi.o obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o +obj-$(CONFIG_DELL_SMO8800) += dell-smo8800.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ACERHDF) += acerhdf.o obj-$(CONFIG_HP_ACCEL) += hp_accel.o diff --git a/drivers/platform/x86/dell-smo8800.c b/drivers/platform/x86/dell-smo8800.c new file mode 100644 index 000000000000..a653716055d1 --- /dev/null +++ b/drivers/platform/x86/dell-smo8800.c @@ -0,0 +1,233 @@ +/* + * dell-smo8800.c - Dell Latitude ACPI SMO8800/SMO8810 freefall sensor driver + * + * Copyright (C) 2012 Sonal Santan + * Copyright (C) 2014 Pali Rohár + * + * This is loosely based on lis3lv02d driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define DRIVER_NAME "smo8800" + +#include +#include +#include +#include +#include + +struct smo8800_device { + u32 irq; /* acpi device irq */ + atomic_t counter; /* count after last read */ + struct miscdevice miscdev; /* for /dev/freefall */ + unsigned long misc_opened; /* whether the device is open */ + wait_queue_head_t misc_wait; /* Wait queue for the misc dev */ + struct device *dev; /* acpi device */ +}; + +static irqreturn_t smo8800_interrupt_quick(int irq, void *data) +{ + struct smo8800_device *smo8800 = data; + + atomic_inc(&smo8800->counter); + wake_up_interruptible(&smo8800->misc_wait); + return IRQ_WAKE_THREAD; +} + +static irqreturn_t smo8800_interrupt_thread(int irq, void *data) +{ + struct smo8800_device *smo8800 = data; + + dev_info(smo8800->dev, "detected free fall\n"); + return IRQ_HANDLED; +} + +static acpi_status smo8800_get_resource(struct acpi_resource *resource, + void *context) +{ + struct acpi_resource_extended_irq *irq; + + if (resource->type != ACPI_RESOURCE_TYPE_EXTENDED_IRQ) + return AE_OK; + + irq = &resource->data.extended_irq; + if (!irq || !irq->interrupt_count) + return AE_OK; + + *((u32 *)context) = irq->interrupts[0]; + return AE_CTRL_TERMINATE; +} + +static u32 smo8800_get_irq(struct acpi_device *device) +{ + u32 irq = 0; + acpi_status status; + + status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, + smo8800_get_resource, &irq); + if (ACPI_FAILURE(status)) { + dev_err(&device->dev, "acpi_walk_resources failed\n"); + return 0; + } + + return irq; +} + +static ssize_t smo8800_misc_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct smo8800_device *smo8800 = container_of(file->private_data, + struct smo8800_device, miscdev); + + u32 data = 0; + unsigned char byte_data = 0; + ssize_t retval = 1; + + if (count < 1) + return -EINVAL; + + atomic_set(&smo8800->counter, 0); + retval = wait_event_interruptible(smo8800->misc_wait, + (data = atomic_xchg(&smo8800->counter, 0))); + + if (retval) + return retval; + + byte_data = 1; + retval = 1; + + if (data < 255) + byte_data = data; + else + byte_data = 255; + + if (put_user(byte_data, buf)) + retval = -EFAULT; + + return retval; +} + +static int smo8800_misc_open(struct inode *inode, struct file *file) +{ + struct smo8800_device *smo8800 = container_of(file->private_data, + struct smo8800_device, miscdev); + + if (test_and_set_bit(0, &smo8800->misc_opened)) + return -EBUSY; /* already open */ + + atomic_set(&smo8800->counter, 0); + return 0; +} + +static int smo8800_misc_release(struct inode *inode, struct file *file) +{ + struct smo8800_device *smo8800 = container_of(file->private_data, + struct smo8800_device, miscdev); + + clear_bit(0, &smo8800->misc_opened); /* release the device */ + return 0; +} + +static const struct file_operations smo8800_misc_fops = { + .owner = THIS_MODULE, + .read = smo8800_misc_read, + .open = smo8800_misc_open, + .release = smo8800_misc_release, +}; + +static int smo8800_add(struct acpi_device *device) +{ + int err; + struct smo8800_device *smo8800; + + smo8800 = devm_kzalloc(&device->dev, sizeof(*smo8800), GFP_KERNEL); + if (!smo8800) { + dev_err(&device->dev, "failed to allocate device data\n"); + return -ENOMEM; + } + + smo8800->dev = &device->dev; + smo8800->miscdev.minor = MISC_DYNAMIC_MINOR; + smo8800->miscdev.name = "freefall"; + smo8800->miscdev.fops = &smo8800_misc_fops; + + init_waitqueue_head(&smo8800->misc_wait); + + err = misc_register(&smo8800->miscdev); + if (err) { + dev_err(&device->dev, "failed to register misc dev: %d\n", err); + return err; + } + + device->driver_data = smo8800; + + smo8800->irq = smo8800_get_irq(device); + if (!smo8800->irq) { + dev_err(&device->dev, "failed to obtain IRQ\n"); + err = -EINVAL; + goto error; + } + + err = request_threaded_irq(smo8800->irq, smo8800_interrupt_quick, + smo8800_interrupt_thread, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + DRIVER_NAME, smo8800); + if (err) { + dev_err(&device->dev, + "failed to request thread for IRQ %d: %d\n", + smo8800->irq, err); + goto error; + } + + dev_dbg(&device->dev, "device /dev/freefall registered with IRQ %d\n", + smo8800->irq); + return 0; + +error: + misc_deregister(&smo8800->miscdev); + return err; +} + +static int smo8800_remove(struct acpi_device *device) +{ + struct smo8800_device *smo8800 = device->driver_data; + + free_irq(smo8800->irq, smo8800); + misc_deregister(&smo8800->miscdev); + dev_dbg(&device->dev, "device /dev/freefall unregistered\n"); + return 0; +} + +static const struct acpi_device_id smo8800_ids[] = { + { "SMO8800", 0 }, + { "SMO8810", 0 }, + { "", 0 }, +}; + +MODULE_DEVICE_TABLE(acpi, smo8800_ids); + +static struct acpi_driver smo8800_driver = { + .name = DRIVER_NAME, + .class = "Latitude", + .ids = smo8800_ids, + .ops = { + .add = smo8800_add, + .remove = smo8800_remove, + }, + .owner = THIS_MODULE, +}; + +module_acpi_driver(smo8800_driver); + +MODULE_DESCRIPTION("Dell Latitude freefall driver (ACPI SMO8800/SMO8810)"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sonal Santan, Pali Rohár"); From 8b9dd4fab26a0f328420cbda0845a325f45bcd92 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 9 Apr 2014 11:46:46 +0200 Subject: [PATCH 16/17] thinkpad_acpi: Add mappings for F9 - F12 hotkeys on X240 / T440 / T540 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The T440s user guide says that when Fn-lock is not active, the *40s' F9 - F12 keys should be mapped to: control-panel, search, show-all-windows and Computer. These keys generate the sofar unused 28 - 31 hotkey scancodes. For the first 2 this nicely matches the icons on the keys, for the latter 2 the icons are somewhat creative, which is why I ended up looking them up in the user manual. Signed-off-by: Hans de Goede Signed-off-by: Matthew Garrett --- drivers/platform/x86/thinkpad_acpi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 15e61c16736e..d82f196e3cfe 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3171,8 +3171,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */ /* (assignments unknown, please report if found) */ - KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + + /* Extra keys in use since the X240 / T440 / T540 */ + KEY_CONFIG, KEY_SEARCH, KEY_SCALE, KEY_COMPUTER, }, }; From f82bdd0d77b6bf0dea08a1d957ab45d503f328b1 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Mon, 9 Jun 2014 12:26:06 -0500 Subject: [PATCH 17/17] hp-wmi: Enable hotkeys on some systems This is a third attempt to enable these buttons. The new variable being commit 997daa1bd9aca412ab97955a35b26c460c0ec7a4 (i.e. hp-wmi: detect "2009 BIOS or later"). Older systems that do not have the 2009 BIOS query method respond with a dummy value, in this case 4. Using that, we can target a fairly narrow group of systems. i.e. old enough to not have HPWMI_FEATURE_QUERY 0xd, but new enough to have HPWMI_BIOS_QUERY 0x9. This group may be further limited if some systems respond with something other than 4 to non-existant feature queries. Signed-off-by: Kyle Evans Signed-off-by: Matthew Garrett --- drivers/platform/x86/hp-wmi.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 8ba8956b5a48..484a8673b835 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -53,6 +53,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); #define HPWMI_ALS_QUERY 0x3 #define HPWMI_HARDWARE_QUERY 0x4 #define HPWMI_WIRELESS_QUERY 0x5 +#define HPWMI_BIOS_QUERY 0x9 #define HPWMI_HOTKEY_QUERY 0xc #define HPWMI_FEATURE_QUERY 0xd #define HPWMI_WIRELESS2_QUERY 0x1b @@ -144,6 +145,7 @@ static const struct key_entry hp_wmi_keymap[] = { { KE_KEY, 0x2142, { KEY_MEDIA } }, { KE_KEY, 0x213b, { KEY_INFO } }, { KE_KEY, 0x2169, { KEY_DIRECTION } }, + { KE_KEY, 0x216a, { KEY_SETUP } }, { KE_KEY, 0x231b, { KEY_HELP } }, { KE_END, 0 } }; @@ -304,6 +306,19 @@ static int hp_wmi_bios_2009_later(void) return (state & 0x10) ? 1 : 0; } +static int hp_wmi_enable_hotkeys(void) +{ + int ret; + int query = 0x6e; + + ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query), + 0); + + if (ret) + return -EINVAL; + return 0; +} + static int hp_wmi_set_block(void *data, bool blocked) { enum hp_wmi_radio r = (enum hp_wmi_radio) data; @@ -648,6 +663,9 @@ static int __init hp_wmi_input_setup(void) hp_wmi_tablet_state()); input_sync(hp_wmi_input_dev); + if (hp_wmi_bios_2009_later() == 4) + hp_wmi_enable_hotkeys(); + status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); if (ACPI_FAILURE(status)) { err = -EIO;