From 3de59bcd3bebca6ba4827e7b6ce19568f11652b6 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 15 Jun 2016 21:49:10 +0200 Subject: dell-wmi: Ignore WMI event code 0xe045 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit >From Dell we know that WMI event code 0xe045 is for Num Lock key, but it is unclear due to message in commit 0b3f6109f0c9 ("dell-wmi: new driver for hotkey control"). Signed-off-by: Pali Rohár Tested-by: Michał Kępień Tested-by: Gabriele Mazzotta Reviewed-by: Michał Kępień Cc: Matthew Garrett Cc: Mario Limonciello Link: https://lkml.org/lkml/2015/7/7/830 Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 15c6f1191aec..4d23c910afeb 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -88,7 +88,6 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = { static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } }, - { KE_KEY, 0xe045, { KEY_PROG1 } }, { KE_KEY, 0xe009, { KEY_EJECTCD } }, /* These also contain the brightness level at offset 6 */ @@ -130,7 +129,19 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } }, { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } }, + + /* + * This entry is very suspicious! + * Originally Matthew Garrett created this dell-wmi driver specially for + * "button with a picture of a battery" which has event code 0xe045. + * Later Mario Limonciello from Dell told us that event code 0xe045 is + * reported by Num Lock and should be ignored because key is send also + * by keyboard controller. + * So for now we will ignore this event to prevent potential double + * Num Lock key press. + */ { KE_IGNORE, 0xe045, { KEY_NUMLOCK } }, + { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } }, { KE_IGNORE, 0xe0f7, { KEY_MUTE } }, { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } }, -- cgit v1.2.3-59-g8ed1b From 6a4d260a63999dae65289e790f7af2ab1e26cd97 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 15 Jun 2016 21:49:11 +0200 Subject: dell-wmi: Sort WMI event codes and update comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For better readability of keymap table, sort events by codes and also update comments for events to be more informative. Signed-off-by: Pali Rohár Tested-by: Michał Kępień Reviewed-by: Michał Kępień Tested-by: Gabriele Mazzotta Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 4d23c910afeb..b3b99709f824 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -88,29 +88,29 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = { static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } }, - { KE_KEY, 0xe009, { KEY_EJECTCD } }, - - /* These also contain the brightness level at offset 6 */ - { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } }, - { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } }, + /* Key code is followed by brightness level */ + { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } }, + { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } }, /* Battery health status button */ - { KE_KEY, 0xe007, { KEY_BATTERY } }, + { KE_KEY, 0xe007, { KEY_BATTERY } }, - /* Radio devices state change */ + /* Radio devices state change, key code is followed by other values */ { KE_IGNORE, 0xe008, { KEY_RFKILL } }, - /* The next device is at offset 6, the active devices are at - offset 8 and the attached devices at offset 10 */ - { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } }, + { KE_KEY, 0xe009, { KEY_EJECTCD } }, + + /* Key code is followed by: next, active and attached devices */ + { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } }, + /* Key code is followed by keyboard illumination level */ { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } }, /* BIOS error detected */ { KE_IGNORE, 0xe00d, { KEY_RESERVED } }, /* Wifi Catcher */ - { KE_KEY, 0xe011, {KEY_PROG2 } }, + { KE_KEY, 0xe011, { KEY_PROG2 } }, /* Ambient light sensor toggle */ { KE_IGNORE, 0xe013, { KEY_RESERVED } }, @@ -118,12 +118,14 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe020, { KEY_MUTE } }, /* Dell Instant Launch key */ - { KE_KEY, 0xe025, { KEY_PROG4 } }, - { KE_KEY, 0xe029, { KEY_PROG4 } }, + { KE_KEY, 0xe025, { KEY_PROG4 } }, /* Audio panel key */ { KE_IGNORE, 0xe026, { KEY_RESERVED } }, + /* Dell Instant Launch key */ + { KE_KEY, 0xe029, { KEY_PROG4 } }, + { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } }, { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } }, @@ -146,6 +148,7 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe0f7, { KEY_MUTE } }, { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } }, { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } }, + { KE_END, 0 } }; -- cgit v1.2.3-59-g8ed1b From 3237a861049bb3a8f335392c37505d4d3692d79e Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 15 Jun 2016 21:49:12 +0200 Subject: dell-wmi: Add information about other WMI event codes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ACPI DSDT tables have defined other WMI codes, but does not contain any description when those codes are emitted. Some other codes can be found in logs on internet. In this patch are all which I saw, but lot of them are not tested properly (e.g. for duplicate events with AT keyboard). Now we have all WMI event codes at one place and in future after proper testing those codes can be correctly enabled or disabled... Signed-off-by: Pali Rohár Tested-by: Michał Kępień Reviewed-by: Michał Kępień Tested-by: Gabriele Mazzotta Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index b3b99709f824..41ae79d507b3 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -109,6 +109,9 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { /* BIOS error detected */ { KE_IGNORE, 0xe00d, { KEY_RESERVED } }, + /* Unknown, defined in ACPI DSDT */ + /* { KE_IGNORE, 0xe00e, { KEY_RESERVED } }, */ + /* Wifi Catcher */ { KE_KEY, 0xe011, { KEY_PROG2 } }, @@ -117,21 +120,45 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe020, { KEY_MUTE } }, + /* Unknown, defined in ACPI DSDT */ + /* { KE_IGNORE, 0xe023, { KEY_RESERVED } }, */ + + /* Untested, Dell Instant Launch key on Inspiron 7520 */ + /* { KE_IGNORE, 0xe024, { KEY_RESERVED } }, */ + /* Dell Instant Launch key */ { KE_KEY, 0xe025, { KEY_PROG4 } }, /* Audio panel key */ { KE_IGNORE, 0xe026, { KEY_RESERVED } }, + /* Untested, Multimedia key on Dell Vostro 3560 */ + /* { KE_IGNORE, 0xe028, { KEY_RESERVED } }, */ + /* Dell Instant Launch key */ { KE_KEY, 0xe029, { KEY_PROG4 } }, + /* Untested, Windows Mobility Center button on Inspiron 7520 */ + /* { KE_IGNORE, 0xe02a, { KEY_RESERVED } }, */ + + /* Unknown, defined in ACPI DSDT */ + /* { KE_IGNORE, 0xe02b, { KEY_RESERVED } }, */ + + /* Untested, Dell Audio With Preset Switch button on Inspiron 7520 */ + /* { KE_IGNORE, 0xe02c, { KEY_RESERVED } }, */ + { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } }, { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } }, { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } }, + /* NIC Link is Up */ + { KE_IGNORE, 0xe043, { KEY_RESERVED } }, + + /* NIC Link is Down */ + { KE_IGNORE, 0xe044, { KEY_RESERVED } }, + /* * This entry is very suspicious! * Originally Matthew Garrett created this dell-wmi driver specially for @@ -144,7 +171,15 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { */ { KE_IGNORE, 0xe045, { KEY_NUMLOCK } }, + /* Scroll lock and also going to tablet mode on portable devices */ { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } }, + + /* Untested, going from tablet mode on portable devices */ + /* { KE_IGNORE, 0xe047, { KEY_RESERVED } }, */ + + /* Dell Support Center key */ + { KE_IGNORE, 0xe06e, { KEY_RESERVED } }, + { KE_IGNORE, 0xe0f7, { KEY_MUTE } }, { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } }, { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } }, -- cgit v1.2.3-59-g8ed1b From e075b3c898e4055ec62a1f0ed7f3b8e62814bfb6 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Wed, 15 Jun 2016 21:49:13 +0200 Subject: dell-wmi: Generate one sparse keymap for all machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch reworks code for generating sparse keymap and processing WMI events. It unifies procedure for generating sparse keymap and also unifies big switch code for processing WMI events of different types. After this patch dell-wmi driver does not differ between "old" and "new" hotkey type. It constructs sparse keymap table with all WMI codes. It is because on some laptops (e.g. Dell Latitude E6440) ACPI/firmware send both event types (old and new). Each WMI code in sparse keymap table is prefixed by 16bit event type, so it does not change functionality on laptops with "old" hotkey support (those without scancodes in DMI). This allow us to distinguish between same WMI codes with different types in sparse keymap. Thanks to this WMI events of type 0x0011 were moved from big switch into sparse keymap table too. This patch also fixes possible bug in parsing WMI event buffer introduced in commit 5ea2559726b7 ("dell-wmi: Add support for new Dell systems"). That commit changed buffer type from int* to u16* without fixing code. More at: http://lkml.iu.edu/hypermail/linux/kernel/1507.0/01950.html Signed-off-by: Pali Rohár Tested-by: Michał Kępień Reviewed-by: Michał Kępień Tested-by: Gabriele Mazzotta Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 215 +++++++++++++++++++--------------------- 1 file changed, 104 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 41ae79d507b3..b8ad055078cf 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -80,12 +80,13 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = { }; /* + * Keymap for WMI events of type 0x0000 + * * Certain keys are flagged as KE_IGNORE. All of these are either * notifications (rather than requests for change) or are also sent * via the keyboard controller so should not be sent again. */ - -static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { +static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = { { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } }, /* Key code is followed by brightness level */ @@ -183,12 +184,8 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { { KE_IGNORE, 0xe0f7, { KEY_MUTE } }, { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } }, { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } }, - - { KE_END, 0 } }; -static bool dell_new_hk_type; - struct dell_bios_keymap_entry { u16 scancode; u16 keycode; @@ -202,6 +199,7 @@ struct dell_bios_hotkey_table { struct dell_dmi_results { int err; + int keymap_size; struct key_entry *keymap; }; @@ -250,10 +248,12 @@ static const u16 bios_to_linux_keycode[256] __initconst = { }; /* + * Keymap for WMI events of type 0x0010 + * * These are applied if the 0xB2 DMI hotkey table is present and doesn't * override them. */ -static const struct key_entry dell_wmi_extra_keymap[] __initconst = { +static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = { /* Fn-lock */ { KE_IGNORE, 0x151, { KEY_RESERVED } }, @@ -273,21 +273,39 @@ static const struct key_entry dell_wmi_extra_keymap[] __initconst = { { KE_IGNORE, 0x155, { KEY_RESERVED } }, }; +/* + * Keymap for WMI events of type 0x0011 + */ +static const struct key_entry dell_wmi_keymap_type_0011[] __initconst = { + /* Battery unplugged */ + { KE_IGNORE, 0xfff0, { KEY_RESERVED } }, + + /* Battery inserted */ + { KE_IGNORE, 0xfff1, { KEY_RESERVED } }, + + /* Keyboard backlight level changed */ + { KE_IGNORE, 0x01e1, { KEY_RESERVED } }, + { KE_IGNORE, 0x02ea, { KEY_RESERVED } }, + { KE_IGNORE, 0x02eb, { KEY_RESERVED } }, + { KE_IGNORE, 0x02ec, { KEY_RESERVED } }, + { KE_IGNORE, 0x02f6, { KEY_RESERVED } }, +}; + static struct input_dev *dell_wmi_input_dev; -static void dell_wmi_process_key(int reported_key) +static void dell_wmi_process_key(int type, int code) { const struct key_entry *key; key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, - reported_key); + (type << 16) | code); if (!key) { - pr_info("Unknown key with scancode 0x%x pressed\n", - reported_key); + pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n", + type, code); return; } - pr_debug("Key %x pressed\n", reported_key); + pr_debug("Key with type 0x%04x and code 0x%04x pressed\n", type, code); /* Don't report brightness notifications that will also come via ACPI */ if ((key->keycode == KEY_BRIGHTNESSUP || @@ -295,7 +313,7 @@ static void dell_wmi_process_key(int reported_key) acpi_video_handles_brightness_key_presses()) return; - if (reported_key == 0xe025 && !wmi_requires_smbios_request) + if (type == 0x0000 && code == 0xe025 && !wmi_requires_smbios_request) return; sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); @@ -333,18 +351,6 @@ static void dell_wmi_notify(u32 value, void *context) buffer_entry = (u16 *)obj->buffer.pointer; buffer_size = obj->buffer.length/2; - - if (!dell_new_hk_type) { - if (buffer_size >= 3 && buffer_entry[1] == 0x0) - dell_wmi_process_key(buffer_entry[2]); - else if (buffer_size >= 2) - dell_wmi_process_key(buffer_entry[1]); - else - pr_info("Received unknown WMI event\n"); - kfree(obj); - return; - } - buffer_end = buffer_entry + buffer_size; /* @@ -379,62 +385,18 @@ static void dell_wmi_notify(u32 value, void *context) pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry); switch (buffer_entry[1]) { - case 0x00: - for (i = 2; i < len; ++i) { - switch (buffer_entry[i]) { - case 0xe043: - /* NIC Link is Up */ - pr_debug("NIC Link is Up\n"); - break; - case 0xe044: - /* NIC Link is Down */ - pr_debug("NIC Link is Down\n"); - break; - case 0xe045: - /* Unknown event but defined in DSDT */ - default: - /* Unknown event */ - pr_info("Unknown WMI event type 0x00: " - "0x%x\n", (int)buffer_entry[i]); - break; - } - } + case 0x0000: /* One key pressed or event occurred */ + if (len > 2) + dell_wmi_process_key(0x0000, buffer_entry[2]); + /* Other entries could contain additional information */ break; - case 0x10: - /* Keys pressed */ + case 0x0010: /* Sequence of keys pressed */ + case 0x0011: /* Sequence of events occurred */ for (i = 2; i < len; ++i) - dell_wmi_process_key(buffer_entry[i]); - break; - case 0x11: - for (i = 2; i < len; ++i) { - switch (buffer_entry[i]) { - case 0xfff0: - /* Battery unplugged */ - pr_debug("Battery unplugged\n"); - break; - case 0xfff1: - /* Battery inserted */ - pr_debug("Battery inserted\n"); - break; - case 0x01e1: - case 0x02ea: - case 0x02eb: - case 0x02ec: - case 0x02f6: - /* Keyboard backlight level changed */ - pr_debug("Keyboard backlight level " - "changed\n"); - break; - default: - /* Unknown event */ - pr_info("Unknown WMI event type 0x11: " - "0x%x\n", (int)buffer_entry[i]); - break; - } - } + dell_wmi_process_key(buffer_entry[1], + buffer_entry[i]); break; - default: - /* Unknown event */ + default: /* Unknown event */ pr_info("Unknown WMI event type 0x%x\n", (int)buffer_entry[1]); break; @@ -459,7 +421,6 @@ static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len) } static void __init handle_dmi_entry(const struct dmi_header *dm, - void *opaque) { @@ -467,7 +428,6 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, struct dell_bios_hotkey_table *table; int hotkey_num, i, pos = 0; struct key_entry *keymap; - int num_bios_keys; if (results->err || results->keymap) return; /* We already found the hotkey table. */ @@ -491,8 +451,7 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, return; } - keymap = kcalloc(hotkey_num + ARRAY_SIZE(dell_wmi_extra_keymap) + 1, - sizeof(struct key_entry), GFP_KERNEL); + keymap = kcalloc(hotkey_num, sizeof(struct key_entry), GFP_KERNEL); if (!keymap) { results->err = -ENOMEM; return; @@ -529,31 +488,15 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, pos++; } - num_bios_keys = pos; - - for (i = 0; i < ARRAY_SIZE(dell_wmi_extra_keymap); i++) { - const struct key_entry *entry = &dell_wmi_extra_keymap[i]; - - /* - * Check if we've already found this scancode. This takes - * quadratic time, but it doesn't matter unless the list - * of extra keys gets very long. - */ - if (!have_scancode(entry->code, keymap, num_bios_keys)) { - keymap[pos] = *entry; - pos++; - } - } - - keymap[pos].type = KE_END; - results->keymap = keymap; + results->keymap_size = pos; } static int __init dell_wmi_input_setup(void) { struct dell_dmi_results dmi_results = {}; - int err; + struct key_entry *keymap; + int err, i, pos = 0; dell_wmi_input_dev = input_allocate_device(); if (!dell_wmi_input_dev) @@ -577,21 +520,71 @@ static int __init dell_wmi_input_setup(void) goto err_free_dev; } - if (dmi_results.keymap) { - dell_new_hk_type = true; + keymap = kcalloc(dmi_results.keymap_size + + ARRAY_SIZE(dell_wmi_keymap_type_0000) + + ARRAY_SIZE(dell_wmi_keymap_type_0010) + + ARRAY_SIZE(dell_wmi_keymap_type_0011) + + 1, + sizeof(struct key_entry), GFP_KERNEL); + if (!keymap) { + kfree(dmi_results.keymap); + err = -ENOMEM; + goto err_free_dev; + } - err = sparse_keymap_setup(dell_wmi_input_dev, - dmi_results.keymap, NULL); + /* Append table with events of type 0x0010 which comes from DMI */ + for (i = 0; i < dmi_results.keymap_size; i++) { + keymap[pos] = dmi_results.keymap[i]; + keymap[pos].code |= (0x0010 << 16); + pos++; + } + + kfree(dmi_results.keymap); + + /* Append table with extra events of type 0x0010 which are not in DMI */ + for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0010); i++) { + const struct key_entry *entry = &dell_wmi_keymap_type_0010[i]; /* - * Sparse keymap library makes a copy of keymap so we - * don't need the original one that was allocated. + * Check if we've already found this scancode. This takes + * quadratic time, but it doesn't matter unless the list + * of extra keys gets very long. */ - kfree(dmi_results.keymap); - } else { - err = sparse_keymap_setup(dell_wmi_input_dev, - dell_wmi_legacy_keymap, NULL); + if (dmi_results.keymap_size && + have_scancode(entry->code | (0x0010 << 16), + keymap, dmi_results.keymap_size) + ) + continue; + + keymap[pos] = *entry; + keymap[pos].code |= (0x0010 << 16); + pos++; + } + + /* Append table with events of type 0x0011 */ + for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0011); i++) { + keymap[pos] = dell_wmi_keymap_type_0011[i]; + keymap[pos].code |= (0x0011 << 16); + pos++; } + + /* + * Now append also table with "legacy" events of type 0x0000. Some of + * them are reported also on laptops which have scancodes in DMI. + */ + for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0000); i++) { + keymap[pos] = dell_wmi_keymap_type_0000[i]; + pos++; + } + + keymap[pos].type = KE_END; + + err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL); + /* + * Sparse keymap library makes a copy of keymap so we don't need the + * original one that was allocated. + */ + kfree(keymap); if (err) goto err_free_dev; -- cgit v1.2.3-59-g8ed1b From ab9bb11ccbaa9e84be2534b677fe5350c2cc2014 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Fri, 17 Jun 2016 11:44:27 +0800 Subject: dell-wmi: Add a WMI event code for display on/off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some new Dell AIO systems have a button that generates a WMI event to turn the LCD on/off. Signed-off-by: Alex Hung Acked-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-wmi.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index b8ad055078cf..d2bc092defd7 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -133,6 +133,9 @@ static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = { /* Audio panel key */ { KE_IGNORE, 0xe026, { KEY_RESERVED } }, + /* LCD Display On/Off Control key */ + { KE_KEY, 0xe027, { KEY_DISPLAYTOGGLE } }, + /* Untested, Multimedia key on Dell Vostro 3560 */ /* { KE_IGNORE, 0xe028, { KEY_RESERVED } }, */ -- cgit v1.2.3-59-g8ed1b From 98010f1ea0ccd9a0e56bdb4e2cf913b72db0f939 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 27 Jun 2016 19:48:08 -0600 Subject: toshiba_acpi: Add IIO interface for accelerometer axis data This patch adds the accelerometer axis data to the IIO subsystem. Currently reporting the X, Y and Z values, as no other data can be queried given the fact that the accelerometer chip itself is hidden behind the Toshiba proprietary interface. Signed-off-by: Azael Avalos Acked-by: Jonathan Cameron Signed-off-by: Darren Hart --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/toshiba_acpi.c | 107 ++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index c06bb85c2839..633fc5c191fc 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -669,6 +669,7 @@ config ACPI_TOSHIBA depends on SERIO_I8042 || SERIO_I8042 = n depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL || RFKILL = n + depends on IIO select INPUT_POLLDEV select INPUT_SPARSEKMAP ---help--- diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 01e12d221a8b..bd9b346ac846 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include @@ -134,6 +135,7 @@ MODULE_LICENSE("GPL"); /* Field definitions */ #define HCI_ACCEL_MASK 0x7fff +#define HCI_ACCEL_DIRECTION_MASK 0x8000 #define HCI_HOTKEY_DISABLE 0x0b #define HCI_HOTKEY_ENABLE 0x09 #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 @@ -178,6 +180,7 @@ struct toshiba_acpi_dev { struct led_classdev eco_led; struct miscdevice miscdev; struct rfkill *wwan_rfk; + struct iio_dev *indio_dev; int force_fan; int last_key_event; @@ -2419,6 +2422,81 @@ static void toshiba_acpi_kbd_bl_work(struct work_struct *work) 0x92, 0); } +/* + * IIO device + */ + +enum toshiba_iio_accel_chan { + AXIS_X, + AXIS_Y, + AXIS_Z +}; + +static int toshiba_iio_accel_get_axis(enum toshiba_iio_accel_chan chan) +{ + u32 xyval, zval; + int ret; + + ret = toshiba_accelerometer_get(toshiba_acpi, &xyval, &zval); + if (ret < 0) + return ret; + + switch (chan) { + case AXIS_X: + return xyval & HCI_ACCEL_DIRECTION_MASK ? + -(xyval & HCI_ACCEL_MASK) : xyval & HCI_ACCEL_MASK; + case AXIS_Y: + return (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_DIRECTION_MASK ? + -((xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK) : + (xyval >> HCI_MISC_SHIFT) & HCI_ACCEL_MASK; + case AXIS_Z: + return zval & HCI_ACCEL_DIRECTION_MASK ? + -(zval & HCI_ACCEL_MASK) : zval & HCI_ACCEL_MASK; + } + + return ret; +} + +static int toshiba_iio_accel_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = toshiba_iio_accel_get_axis(chan->channel); + if (ret == -EIO || ret == -ENODEV) + return ret; + + *val = ret; + + return IIO_VAL_INT; + } + + return -EINVAL; +} + +#define TOSHIBA_IIO_ACCEL_CHANNEL(axis, chan) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel = chan, \ + .channel2 = IIO_MOD_##axis, \ + .output = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ +} + +static const struct iio_chan_spec toshiba_iio_accel_channels[] = { + TOSHIBA_IIO_ACCEL_CHANNEL(X, AXIS_X), + TOSHIBA_IIO_ACCEL_CHANNEL(Y, AXIS_Y), + TOSHIBA_IIO_ACCEL_CHANNEL(Z, AXIS_Z), +}; + +static const struct iio_info toshiba_iio_accel_info = { + .driver_module = THIS_MODULE, + .read_raw = &toshiba_iio_accel_read_raw, +}; + /* * Misc device */ @@ -2904,6 +2982,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) remove_toshiba_proc_entries(dev); + if (dev->accelerometer_supported && dev->indio_dev) { + iio_device_unregister(dev->indio_dev); + iio_device_free(dev->indio_dev); + } + if (dev->sysfs_created) sysfs_remove_group(&dev->acpi_dev->dev.kobj, &toshiba_attr_group); @@ -3051,6 +3134,30 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) dev->touchpad_supported = !ret; toshiba_accelerometer_available(dev); + if (dev->accelerometer_supported) { + dev->indio_dev = iio_device_alloc(sizeof(*dev)); + if (!dev->indio_dev) { + pr_err("Unable to allocate iio device\n"); + goto iio_error; + } + + pr_info("Registering Toshiba accelerometer iio device\n"); + + dev->indio_dev->info = &toshiba_iio_accel_info; + dev->indio_dev->name = "Toshiba accelerometer"; + dev->indio_dev->dev.parent = &acpi_dev->dev; + dev->indio_dev->modes = INDIO_DIRECT_MODE; + dev->indio_dev->channels = toshiba_iio_accel_channels; + dev->indio_dev->num_channels = + ARRAY_SIZE(toshiba_iio_accel_channels); + + ret = iio_device_register(dev->indio_dev); + if (ret < 0) { + pr_err("Unable to register iio device\n"); + iio_device_free(dev->indio_dev); + } + } +iio_error: toshiba_usb_sleep_charge_available(dev); -- cgit v1.2.3-59-g8ed1b From 2fd67884459ad35730ba2a92f0bb92ecd35285fc Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 27 Jun 2016 19:46:43 -0600 Subject: toshiba_acpi: Remove the position sysfs entry Now that we have proper support for the acceleromeer under the IIO subsystem, the _position_ sysfs file is now deprecated. This patch removes all code related to the position sysfs entry. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index bd9b346ac846..ea0262e1e49a 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1961,28 +1961,6 @@ static ssize_t touchpad_show(struct device *dev, } static DEVICE_ATTR_RW(touchpad); -static ssize_t position_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); - u32 xyval, zval, tmp; - u16 x, y, z; - int ret; - - xyval = zval = 0; - ret = toshiba_accelerometer_get(toshiba, &xyval, &zval); - if (ret < 0) - return ret; - - x = xyval & HCI_ACCEL_MASK; - tmp = xyval >> HCI_MISC_SHIFT; - y = tmp & HCI_ACCEL_MASK; - z = zval & HCI_ACCEL_MASK; - - return sprintf(buf, "%d %d %d\n", x, y, z); -} -static DEVICE_ATTR_RO(position); - static ssize_t usb_sleep_charge_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2353,7 +2331,6 @@ static struct attribute *toshiba_attributes[] = { &dev_attr_available_kbd_modes.attr, &dev_attr_kbd_backlight_timeout.attr, &dev_attr_touchpad.attr, - &dev_attr_position.attr, &dev_attr_usb_sleep_charge.attr, &dev_attr_sleep_functions_on_battery.attr, &dev_attr_usb_rapid_charge.attr, @@ -2380,8 +2357,6 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false; else if (attr == &dev_attr_touchpad.attr) exists = (drv->touchpad_supported) ? true : false; - else if (attr == &dev_attr_position.attr) - exists = (drv->accelerometer_supported) ? true : false; else if (attr == &dev_attr_usb_sleep_charge.attr) exists = (drv->usb_sleep_charge_supported) ? true : false; else if (attr == &dev_attr_sleep_functions_on_battery.attr) -- cgit v1.2.3-59-g8ed1b From 95d16d816a45d52e0aecd0dd21cf7b93d88fedf7 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Mon, 27 Jun 2016 19:46:44 -0600 Subject: toshiba_acpi: Bump driver version and update copyright year After several fixes, and added support for more features (WWAN, Cooling Method and IIO accelometer axis data), bump the driver version to 0.24. Also update the copyright year. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index ea0262e1e49a..9d60a40d8b3f 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -4,7 +4,7 @@ * Copyright (C) 2002-2004 John Belmonte * Copyright (C) 2008 Philip Langdale * Copyright (C) 2010 Pierre Ducroquet - * Copyright (C) 2014-2015 Azael Avalos + * Copyright (C) 2014-2016 Azael Avalos * * 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 @@ -31,7 +31,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define TOSHIBA_ACPI_VERSION "0.23" +#define TOSHIBA_ACPI_VERSION "0.24" #define PROC_INTERFACE_VERSION 1 #include -- cgit v1.2.3-59-g8ed1b From fc8a601e1175ae351f662506030f9939cb7fdbfe Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Mon, 13 Jun 2016 19:44:00 +0800 Subject: hp-wmi: Fix wifi cannot be hard-unblocked Several users reported wifi cannot be unblocked as discussed in [1]. This patch removes the use of the 2009 flag by BIOS but uses the actual WMI function calls - it will be skipped if WMI reports unsupported. [1] https://bugzilla.kernel.org/show_bug.cgi?id=69131 Signed-off-by: Alex Hung Tested-by: Evgenii Shatokhin Cc: stable@vger.kernel.org Signed-off-by: Darren Hart --- drivers/platform/x86/hp-wmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 6f145f2d004d..96ffda493266 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -718,6 +718,11 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) if (err) return err; + err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, &wireless, + sizeof(wireless), 0); + if (err) + return err; + if (wireless & 0x1) { wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, RFKILL_TYPE_WLAN, @@ -882,7 +887,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) wwan_rfkill = NULL; rfkill2_count = 0; - if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) + if (hp_wmi_rfkill_setup(device)) hp_wmi_rfkill2_setup(device); err = device_create_file(&device->dev, &dev_attr_display); -- cgit v1.2.3-59-g8ed1b From 98020a4ab05755fe500f69d90c3b31555893a5f2 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Thu, 23 Jun 2016 12:02:47 +0200 Subject: fujitsu-laptop: Use module name in debug messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vdbg_printk() always prefixes the log messages it generates with "FUJ02B1", which can be misleading, because it might have been called while handling a notify for ACPI device FUJ02E3 or during module initialization etc. Employ pr_fmt() to prefix debug messages with the module name instead and thus avoid confusion. Reported-by: Jan-Marek Glogowski Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index ce41bc34288d..04e633d55af7 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -136,7 +136,7 @@ #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG #define vdbg_printk(a_dbg_level, format, arg...) \ do { if (dbg_level & a_dbg_level) \ - printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \ + printk(KERN_DEBUG pr_fmt("%s: " format), __func__, ## arg); \ } while (0) #else #define vdbg_printk(a_dbg_level, format, arg...) \ -- cgit v1.2.3-59-g8ed1b From 00816e1b3839c8e95d0e2e1b0290c1bc5e950bc6 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Thu, 23 Jun 2016 12:02:48 +0200 Subject: fujitsu-laptop: Remove unused macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FUJLAPTOP_* macros were introduced by 20b9373, but have never been used except FUJLAPTOP_DEBUG, which was made redundant by the previous patch. ACPI_VIDEO_NOTIFY_* macros were also introduced by 20b9373, but they have not been needed since 1696d9d. Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 04e633d55af7..7a345f92da52 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -88,9 +88,6 @@ #define ACPI_FUJITSU_NOTIFY_CODE1 0x80 -#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 -#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 - /* FUNC interface - command values */ #define FUNC_RFKILL 0x1000 #define FUNC_LEDS 0x1001 @@ -121,13 +118,6 @@ #define RINGBUFFERSIZE 40 /* Debugging */ -#define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": " -#define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG -#define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG -#define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG -#define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG - -#define FUJLAPTOP_DBG_ALL 0xffff #define FUJLAPTOP_DBG_ERROR 0x0001 #define FUJLAPTOP_DBG_WARN 0x0002 #define FUJLAPTOP_DBG_INFO 0x0004 -- cgit v1.2.3-59-g8ed1b From 1879e69f4c57ead5ff696eb309a0422d01c1cc06 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Tue, 28 Jun 2016 09:25:50 +0200 Subject: fujitsu-laptop: Support touchpad toggle hotkey on Skylake-based models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Haswell-based Fujitsu laptops (Lifebook E734/E744/E754) have a touchpad toggle hotkey (Fn+F4) which is handled transparently to the operating system: while an ACPI notification is sent to FUJ02B1 when Fn+F4 is pressed, touchpad state is properly toggled without any explicit support for this operation in fujitsu-laptop. Skylake-based models (Lifebook E736/E746/E756) also have that hotkey, but the touchpad is not toggled transparently to the operating system. When Fn+F4 is pressed, an ACPI notification is sent to FUJ02E3. A subsequent call to S000 (FUNC_RFKILL) can be used to determine whether the touchpad toggle hotkey was pressed so that an input event can be sent to userspace. Relevant ACPI code: Method (_L21, 0, NotSerialized) { ... If (AHKF) { Notify (\_SB.FEXT, 0x80) } ... } Method (S000, 3, Serialized) { Name (_T_0, Zero) Local0 = Zero While (One) { _T_0 = Arg0 If (_T_0 == Zero) { Local0 |= 0x04000000 Local0 |= 0x02000000 Local0 |= 0x00020000 Local0 |= 0x0200 Local0 |= 0x0100 Local0 |= 0x20 } ElseIf (_T_0 == One) { ... If (AHKF & 0x08) { Local0 |= 0x04000000 AHKF ^= 0x08 } ... } ... Break } Return (Local0) } Pressing Fn+F4 raises GPE 0x21 and sets bit 3 in AHKF. This in turn results in bit 26 being set in the value returned by FUNC_RFKILL called with 1 as its first argument. On Skylake-based models, bit 26 is also set in the value returned by FUNC_RFKILL called with 0 as its first argument (this value is saved in fujitsu_hotkey->rfkill_supported upon module initialization), which suggests that this bit is set on models which do not handle touchpad toggling transparently to the operating system. Note that bit 3 is cleared in AHKF once FUNC_RFKILL is called with 1 as its first argument, which requires fujitsu-laptop to handle this hotkey in a different manner than the other, GIRB-based hotkeys: two input events (press and release) are immediately sent once Fn+F4 is pressed. Reported-and-tested-by: Jan-Marek Glogowski Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 7a345f92da52..5144c353fa14 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -846,6 +846,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) set_bit(fujitsu->keycode3, input->keybit); set_bit(fujitsu->keycode4, input->keybit); set_bit(fujitsu->keycode5, input->keybit); + set_bit(KEY_TOUCHPAD_TOGGLE, input->keybit); set_bit(KEY_UNKNOWN, input->keybit); error = input_register_device(input); @@ -1050,6 +1051,19 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) } } + /* On some models (first seen on the Skylake-based Lifebook + * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is + * handled in software; its state is queried using FUNC_RFKILL + */ + if ((fujitsu_hotkey->rfkill_supported & BIT(26)) && + (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) { + keycode = KEY_TOUCHPAD_TOGGLE; + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + } + break; default: keycode = KEY_UNKNOWN; -- cgit v1.2.3-59-g8ed1b From d6b88f64b0d460c400b1db2d9556bc6a37d29415 Mon Sep 17 00:00:00 2001 From: Matej Groma Date: Tue, 21 Jun 2016 10:09:21 +0200 Subject: fujitsu-laptop: Add support for eco LED There is an indicator LED signaling activated power saving mode on certain Fujitsu laptop models. This has currently no use on Linux. Export it to userspace. Signed-off-by: Matej Groma Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 56 +++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 5144c353fa14..6ce8e7860013 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -105,6 +105,8 @@ #define LOGOLAMP_POWERON 0x2000 #define LOGOLAMP_ALWAYS 0x4000 #define RADIO_LED_ON 0x20 +#define ECO_LED 0x10000 +#define ECO_LED_ON 0x80000 #endif /* Hotkey details */ @@ -166,6 +168,7 @@ struct fujitsu_hotkey_t { int logolamp_registered; int kblamps_registered; int radio_led_registered; + int eco_led_registered; }; static struct fujitsu_hotkey_t *fujitsu_hotkey; @@ -202,6 +205,17 @@ static struct led_classdev radio_led = { .brightness_get = radio_led_get, .brightness_set = radio_led_set }; + +static enum led_brightness eco_led_get(struct led_classdev *cdev); +static void eco_led_set(struct led_classdev *cdev, + enum led_brightness brightness); + +static struct led_classdev eco_led = { + .name = "fujitsu::eco_led", + .max_brightness = 1, + .brightness_get = eco_led_get, + .brightness_set = eco_led_set +}; #endif #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG @@ -286,6 +300,18 @@ static void radio_led_set(struct led_classdev *cdev, call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0); } +static void eco_led_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + int curr; + + curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0); + if (brightness) + call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON); + else + call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON); +} + static enum led_brightness logolamp_get(struct led_classdev *cdev) { enum led_brightness brightness = LED_OFF; @@ -320,6 +346,16 @@ static enum led_brightness radio_led_get(struct led_classdev *cdev) return brightness; } + +static enum led_brightness eco_led_get(struct led_classdev *cdev) +{ + enum led_brightness brightness = LED_OFF; + + if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) + brightness = cdev->max_brightness; + + return brightness; +} #endif /* Hardware access for LCD brightness control */ @@ -934,6 +970,23 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) result); } } + + /* Support for eco led is not always signaled in bit corresponding + * to the bit used to control the led. According to the DSDT table, + * bit 14 seems to indicate presence of said led as well. + * Confirm by testing the status. + */ + if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && + (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { + result = led_classdev_register(&fujitsu->pf_device->dev, + &eco_led); + if (result == 0) { + fujitsu_hotkey->eco_led_registered = 1; + } else { + pr_err("Could not register LED handler for eco LED, error %i\n", + result); + } + } #endif return result; @@ -963,6 +1016,9 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device) if (fujitsu_hotkey->radio_led_registered) led_classdev_unregister(&radio_led); + + if (fujitsu_hotkey->eco_led_registered) + led_classdev_unregister(&eco_led); #endif input_unregister_device(input); -- cgit v1.2.3-59-g8ed1b From 9ee27487127461b5cf71670b708ed5b2b8da568c Mon Sep 17 00:00:00 2001 From: Nick Leiten Date: Sun, 19 Jun 2016 14:59:26 +0300 Subject: asus-wmi: Add ambient light sensor toggle key Ausu laptops issue key 0x7A when the toggle ALS key is pressed (Fn+A on Asus U38N). Update the key_entry so userspace can handle the event. Tested on Asus U38N. Signed-off-by: Nick Leiten Reviewed-By: Corentin Chary [dvhart: cleaned up commit message and comment line length] Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 091ca7ada8fc..096ceba011a0 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -356,6 +356,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */ { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, { KE_IGNORE, 0x6E, }, /* Low Battery notification */ + { KE_KEY, 0x7a, { KEY_ALS_TOGGLE } }, /* Ambient Light Sensor Toggle */ { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */ { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */ { KE_KEY, 0x82, { KEY_CAMERA } }, -- cgit v1.2.3-59-g8ed1b From 1d6de071cb0c321279373634d81eb8e176d887c4 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 29 Jun 2016 11:41:15 +0800 Subject: intel-hid: Remove duplicated acpi_remove_notify_handler The second call to acpi_remove_notify_handler does not result in panic or generate error messages, but it is unnecessary and the function returns with an error. Remove the duplicate call. Correct two improperly indented lines. Signed-off-by: Alex Hung Signed-off-by: Darren Hart --- drivers/platform/x86/intel-hid.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index a818db6aa08f..ed5874217ee7 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -122,8 +122,8 @@ static int intel_hid_input_setup(struct platform_device *device) return 0; err_free_device: - input_free_device(priv->input_dev); - return ret; + input_free_device(priv->input_dev); + return ret; } static void intel_hid_input_destroy(struct platform_device *device) @@ -224,7 +224,6 @@ static int intel_hid_remove(struct platform_device *device) acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); intel_hid_input_destroy(device); intel_hid_set_enable(&device->dev, 0); - acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); /* * Even if we failed to shut off the event stream, we can still -- cgit v1.2.3-59-g8ed1b From 08a245160bce8b3d044fa0fdac9ca099bd720706 Mon Sep 17 00:00:00 2001 From: "Yu, Ong Hock" Date: Thu, 23 Jun 2016 14:59:58 +0800 Subject: intel_telemetry: Remove Monitor MWAIT feature dependency Telemetry capability does not depend on Monitor MWAIT feature. Signed-off-by: "Yu, Ong Hock" Acked-by: Souvik Kumar Chakravarty Signed-off-by: Darren Hart --- drivers/platform/x86/intel_telemetry_debugfs.c | 2 +- drivers/platform/x86/intel_telemetry_pltdrv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_telemetry_debugfs.c b/drivers/platform/x86/intel_telemetry_debugfs.c index f5134acd6ff0..d76ee59f5090 100644 --- a/drivers/platform/x86/intel_telemetry_debugfs.c +++ b/drivers/platform/x86/intel_telemetry_debugfs.c @@ -78,7 +78,7 @@ #define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0])) #define TELEM_DEBUGFS_CPU(model, data) \ - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data} + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data} #define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \ if (evtlog[index].telem_evtid == (EVTID)) { \ diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c index 09c84a2b1c2c..e62cee97d65a 100644 --- a/drivers/platform/x86/intel_telemetry_pltdrv.c +++ b/drivers/platform/x86/intel_telemetry_pltdrv.c @@ -82,7 +82,7 @@ #define TELEM_SET_VERBOSITY_BITS(x, y) ((x) |= ((y) << 27)) #define TELEM_CPU(model, data) \ - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&data } + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data } enum telemetry_action { TELEM_UPDATE = 0, -- cgit v1.2.3-59-g8ed1b From 2c1a49c961237ed8758af3188673b0e9a8826ac6 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 13 Jun 2016 16:57:30 -0400 Subject: asus-wireless: Toggle airplane mode LED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the ASHS device we have the HSWC method, which calls either OWGD or OWGS, depending on its parameter: Device (ASHS) { Name (_HID, "ATK4002") // _HID: Hardware ID Method (HSWC, 1, Serialized) { If ((Arg0 < 0x02)) { OWGD (Arg0) Return (One) } If ((Arg0 == 0x02)) { Local0 = OWGS () If (Local0) { Return (0x05) } Else { Return (0x04) } } If ((Arg0 == 0x03)) { Return (0xFF) } If ((Arg0 == 0x04)) { OWGD (Zero) Return (One) } If ((Arg0 == 0x05)) { OWGD (One) Return (One) } If ((Arg0 == 0x80)) { Return (One) } } Method (_STA, 0, NotSerialized) // _STA: Status { If ((MSOS () >= OSW8)) { Return (0x0F) } Else { Return (Zero) } } } On the Asus laptops that do not have an airplane mode LED, OWGD has an empty implementation and OWGS simply returns 0. On the ones that have an airplane mode LED these methods have the following implementation: Method (OWGD, 1, Serialized) { SGPL (0x0203000F, Arg0) SGPL (0x0203000F, Arg0) } Method (OWGS, 0, Serialized) { Store (RGPL (0x0203000F), Local0) Return (Local0) } Where OWGD(1) sets the airplane mode LED ON, OWGD(0) set it off, and OWGS() returns its state. This commit exposes the airplane mode indicator LED to userspace under the name asus-wireless::airplane, so it can be driven according to userspace's policy. Signed-off-by: João Paulo Rechi Vita Reviewed-by: Corentin Chary Signed-off-by: Darren Hart --- drivers/platform/x86/Kconfig | 2 + drivers/platform/x86/asus-wireless.c | 91 +++++++++++++++++++++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 633fc5c191fc..b0b98e413343 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -604,6 +604,8 @@ config ASUS_WIRELESS tristate "Asus Wireless Radio Control Driver" depends on ACPI depends on INPUT + select NEW_LEDS + select LEDS_CLASS ---help--- The Asus Wireless Radio Control handles the airplane mode hotkey present on some Asus laptops. diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index 9ec721e26532..9f31bc1a47d0 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -15,11 +15,78 @@ #include #include #include +#include + +#define ASUS_WIRELESS_LED_STATUS 0x2 +#define ASUS_WIRELESS_LED_OFF 0x4 +#define ASUS_WIRELESS_LED_ON 0x5 struct asus_wireless_data { struct input_dev *idev; + struct acpi_device *adev; + struct workqueue_struct *wq; + struct work_struct led_work; + struct led_classdev led; + int led_state; }; +static u64 asus_wireless_method(acpi_handle handle, const char *method, + int param) +{ + struct acpi_object_list p; + union acpi_object obj; + acpi_status s; + u64 ret; + + acpi_handle_debug(handle, "Evaluating method %s, parameter %#x\n", + method, param); + obj.type = ACPI_TYPE_INTEGER; + obj.integer.value = param; + p.count = 1; + p.pointer = &obj; + + s = acpi_evaluate_integer(handle, (acpi_string) method, &p, &ret); + if (ACPI_FAILURE(s)) + acpi_handle_err(handle, + "Failed to eval method %s, param %#x (%d)\n", + method, param, s); + acpi_handle_debug(handle, "%s returned %#x\n", method, (uint) ret); + return ret; +} + +static enum led_brightness led_state_get(struct led_classdev *led) +{ + struct asus_wireless_data *data; + int s; + + data = container_of(led, struct asus_wireless_data, led); + s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC", + ASUS_WIRELESS_LED_STATUS); + if (s == ASUS_WIRELESS_LED_ON) + return LED_FULL; + return LED_OFF; +} + +static void led_state_update(struct work_struct *work) +{ + struct asus_wireless_data *data; + + data = container_of(work, struct asus_wireless_data, led_work); + asus_wireless_method(acpi_device_handle(data->adev), "HSWC", + data->led_state); +} + +static void led_state_set(struct led_classdev *led, + enum led_brightness value) +{ + struct asus_wireless_data *data; + + data = container_of(led, struct asus_wireless_data, led); + data->led_state = value == LED_OFF ? ASUS_WIRELESS_LED_OFF : + ASUS_WIRELESS_LED_ON; + queue_work(data->wq, &data->led_work); +} + static void asus_wireless_notify(struct acpi_device *adev, u32 event) { struct asus_wireless_data *data = acpi_driver_data(adev); @@ -37,6 +104,7 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event) static int asus_wireless_add(struct acpi_device *adev) { struct asus_wireless_data *data; + int err; data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -52,11 +120,32 @@ static int asus_wireless_add(struct acpi_device *adev) data->idev->id.vendor = PCI_VENDOR_ID_ASUSTEK; set_bit(EV_KEY, data->idev->evbit); set_bit(KEY_RFKILL, data->idev->keybit); - return input_register_device(data->idev); + err = input_register_device(data->idev); + if (err) + return err; + + data->adev = adev; + data->wq = create_singlethread_workqueue("asus_wireless_workqueue"); + if (!data->wq) + return -ENOMEM; + INIT_WORK(&data->led_work, led_state_update); + data->led.name = "asus-wireless::airplane"; + data->led.brightness_set = led_state_set; + data->led.brightness_get = led_state_get; + data->led.flags = LED_CORE_SUSPENDRESUME; + data->led.max_brightness = 1; + err = devm_led_classdev_register(&adev->dev, &data->led); + if (err) + destroy_workqueue(data->wq); + return err; } static int asus_wireless_remove(struct acpi_device *adev) { + struct asus_wireless_data *data = acpi_driver_data(adev); + + if (data->wq) + destroy_workqueue(data->wq); return 0; } -- cgit v1.2.3-59-g8ed1b From a977e59c0c67c9d492bb16677ce66d67cae0ebd8 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 13 Jun 2016 16:57:31 -0400 Subject: asus-wmi: Create quirk for airplane_mode LED MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some Asus laptops that have an airplane-mode indicator LED, also have the WMI WLAN user bit set, and the following bits in their DSDT: Scope (_SB) { (...) Device (ATKD) { (...) Method (WMNB, 3, Serialized) { (...) If (LEqual (IIA0, 0x00010002)) { OWGD (IIA1) Return (One) } } } } So when asus-wmi uses ASUS_WMI_DEVID_WLAN_LED (0x00010002) to store the wlan state, it drives the airplane-mode indicator LED (through the call to OWGD) in an inverted fashion: the LED is ON when airplane mode is OFF (since wlan is ON), and vice-versa. This commit creates a quirk to not register a RFKill switch at all for these laptops, to allow the asus-wireless driver to drive the airplane mode LED correctly through the ASHS ACPI device. It also adds a match to that quirk for the Asus X555UB, which is affected by this problem. Signed-off-by: João Paulo Rechi Vita Reviewed-by: Corentin Chary Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 13 +++++++++++++ drivers/platform/x86/asus-wmi.c | 8 +++++--- drivers/platform/x86/asus-wmi.h | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 096ceba011a0..99992f46188e 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -78,6 +78,10 @@ static struct quirk_entry quirk_asus_x200ca = { .wapf = 2, }; +static struct quirk_entry quirk_no_rfkill = { + .no_rfkill = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { quirks = dmi->driver_data; @@ -306,6 +310,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_x200ca, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X555UB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X555UB"), + }, + .driver_data = &quirk_no_rfkill, + }, {}, }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index a26dca3640ea..7c093a0b78bb 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -2069,9 +2069,11 @@ static int asus_wmi_add(struct platform_device *pdev) if (err) goto fail_leds; - err = asus_wmi_rfkill_init(asus); - if (err) - goto fail_rfkill; + if (!asus->driver->quirks->no_rfkill) { + err = asus_wmi_rfkill_init(asus); + if (err) + goto fail_rfkill; + } /* Some Asus desktop boards export an acpi-video backlight interface, stop this from showing up */ diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 4da4c8bafe70..5de1df510ebd 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -38,6 +38,7 @@ struct key_entry; struct asus_wmi; struct quirk_entry { + bool no_rfkill; bool hotplug_wireless; bool scalar_panel_brightness; bool store_backlight_power; -- cgit v1.2.3-59-g8ed1b From 2d735244b798f0c8bf93ace1facfafdc1f7a4e6e Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 13 Jun 2016 16:57:32 -0400 Subject: asus-wmi: Add quirk_no_rfkill for the Asus N552VW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Asus N552VW has an airplane-mode indicator LED and the WMI WLAN user bit set, so asus-wmi uses ASUS_WMI_DEVID_WLAN_LED (0x00010002) to store the wlan state, which has a side-effect of driving the airplane mode indicator LED in an inverted fashion. quirk_no_rfkill prevents asus-wmi from registering RFKill switches at all for this laptop and allows asus-wireless to drive the LED through the ASHS ACPI device. Signed-off-by: João Paulo Rechi Vita Reviewed-by: Corentin Chary Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 99992f46188e..63dec1e4ee36 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -319,6 +319,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_no_rfkill, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. N552VW", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "N552VW"), + }, + .driver_data = &quirk_no_rfkill, + }, {}, }; -- cgit v1.2.3-59-g8ed1b From 02db9ff7af18f7ace60f430cbbaa1d846b350916 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 13 Jun 2016 16:57:33 -0400 Subject: asus-wmi: Add quirk_no_rfkill for the Asus U303LB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Asus U303LB has an airplane-mode indicator LED and the WMI WLAN user bit set, so asus-wmi uses ASUS_WMI_DEVID_WLAN_LED (0x00010002) to store the wlan state, which has a side-effect of driving the airplane mode indicator LED in an inverted fashion. quirk_no_rfkill prevents asus-wmi from registering RFKill switches at all for this laptop and allows asus-wireless to drive the LED through the ASHS ACPI device. Signed-off-by: João Paulo Rechi Vita Reported-by: Mousou Yuu Reviewed-by: Corentin Chary Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 63dec1e4ee36..9ff05121df59 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -328,6 +328,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_no_rfkill, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. U303LB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "U303LB"), + }, + .driver_data = &quirk_no_rfkill, + }, {}, }; -- cgit v1.2.3-59-g8ed1b From 6b7ff2af5286a8c6bec7ff5f4df62e3506c1674e Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 13 Jun 2016 16:57:34 -0400 Subject: asus-wmi: Add quirk_no_rfkill for the Asus Z550MA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Asus Z550MA has an airplane-mode indicator LED and the WMI WLAN user bit set, so asus-wmi uses ASUS_WMI_DEVID_WLAN_LED (0x00010002) to store the wlan state, which has a side-effect of driving the airplane mode indicator LED in an inverted fashion. quirk_no_rfkill prevents asus-wmi from registering RFKill switches at all for this laptop and allows asus-wireless to drive the LED through the ASHS ACPI device. Signed-off-by: João Paulo Rechi Vita Reported-by: Ming Shuo Chiu Reviewed-by: Corentin Chary Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 9ff05121df59..a93a6dbe186d 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -337,6 +337,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_no_rfkill, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. Z550MA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "Z550MA"), + }, + .driver_data = &quirk_no_rfkill, + }, {}, }; -- cgit v1.2.3-59-g8ed1b From a961a285b479977fa21f12f71cd62f28adaba17c Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 13 Jun 2016 16:57:35 -0400 Subject: asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Asus X456UF has an airplane-mode indicator LED and the WMI WLAN user bit set, so asus-wmi uses ASUS_WMI_DEVID_WLAN_LED (0x00010002) to store the wlan state, which has a side-effect of driving the airplane mode indicator LED in an inverted fashion. quirk_no_rfkill prevents asus-wmi from registering RFKill switches at all for this laptop and allows asus-wireless to drive the LED through the ASHS ACPI device. This laptop already has a quirk for setting WAPF=4, so this commit creates a new quirk, quirk_no_rfkill_wapf4, which both disables rfkill and sets WAPF=4. Signed-off-by: João Paulo Rechi Vita Reported-by: Carlo Caione Reviewed-by: Corentin Chary Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index a93a6dbe186d..8e5255d465d5 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -82,6 +82,11 @@ static struct quirk_entry quirk_no_rfkill = { .no_rfkill = true, }; +static struct quirk_entry quirk_no_rfkill_wapf4 = { + .wapf = 4, + .no_rfkill = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { quirks = dmi->driver_data; @@ -146,7 +151,7 @@ static const struct dmi_system_id asus_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "X456UF"), }, - .driver_data = &quirk_asus_wapf4, + .driver_data = &quirk_no_rfkill_wapf4, }, { .callback = dmi_matched, -- cgit v1.2.3-59-g8ed1b From 56a37a72002b1eb01a1de391cf66383652784e78 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 13 Jun 2016 16:57:36 -0400 Subject: asus-wmi: Add quirk_no_rfkill_wapf4 for the Asus X456UA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Asus X456UA has an airplane-mode indicator LED and the WMI WLAN user bit set, so asus-wmi uses ASUS_WMI_DEVID_WLAN_LED (0x00010002) to store the wlan state, which has a side-effect of driving the airplane mode indicator LED in an inverted fashion. quirk_no_rfkill prevents asus-wmi from registering RFKill switches at all for this laptop and allows asus-wireless to drive the LED through the ASHS ACPI device. This laptop already has a quirk for setting WAPF=4, so use quirk_no_rfkill_wapf4, which both disables rfkill and sets WAPF=4. Signed-off-by: João Paulo Rechi Vita Reported-by: Angela Traeger Reviewed-by: Corentin Chary Signed-off-by: Darren Hart --- drivers/platform/x86/asus-nb-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 8e5255d465d5..adecc1c555f0 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -142,7 +142,7 @@ static const struct dmi_system_id asus_quirks[] = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "X456UA"), }, - .driver_data = &quirk_asus_wapf4, + .driver_data = &quirk_no_rfkill_wapf4, }, { .callback = dmi_matched, -- cgit v1.2.3-59-g8ed1b From 696789343b56f3efa26da29eb5b442b673bd83c8 Mon Sep 17 00:00:00 2001 From: Matej Groma Date: Mon, 4 Jul 2016 12:04:12 +0200 Subject: fujitsu-laptop: Rework brightness of eco led For the sake of internal consistency, unset maximum brightness of eco led and make it activatable only on values >= LED_FULL. Signed-off-by: Matej Groma Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 6ce8e7860013..61f39abf5dc8 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -212,7 +212,6 @@ static void eco_led_set(struct led_classdev *cdev, static struct led_classdev eco_led = { .name = "fujitsu::eco_led", - .max_brightness = 1, .brightness_get = eco_led_get, .brightness_set = eco_led_set }; @@ -306,7 +305,7 @@ static void eco_led_set(struct led_classdev *cdev, int curr; curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0); - if (brightness) + if (brightness >= LED_FULL) call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON); else call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON); @@ -352,7 +351,7 @@ static enum led_brightness eco_led_get(struct led_classdev *cdev) enum led_brightness brightness = LED_OFF; if (call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) - brightness = cdev->max_brightness; + brightness = LED_FULL; return brightness; } -- cgit v1.2.3-59-g8ed1b From df2294fb64285d2d793cf50c682ac4bfddf56c4c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Jul 2016 15:39:48 +0300 Subject: intel_pmc_core: Convert to DEFINE_DEBUGFS_ATTRIBUTE Refactor the code to use the recently introduced DEFINE_DEBUGFS_ATTRIBUTE() macro to eliminate boilerplate code. Make the absence of DEBUG_FS a non-fatal error. Signed-off-by: Andy Shevchenko Reviewed-and-tested-by: Rajneesh Bhardwaj Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_core.c | 45 ++++++++--------------------------- drivers/platform/x86/intel_pmc_core.h | 3 +-- 2 files changed, 11 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 2776bec89c88..d8379cd86516 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include @@ -77,30 +76,18 @@ int intel_pmc_slp_s0_counter_read(u32 *data) } EXPORT_SYMBOL_GPL(intel_pmc_slp_s0_counter_read); -#if IS_ENABLED(CONFIG_DEBUG_FS) -static int pmc_core_dev_state_show(struct seq_file *s, void *unused) +static int pmc_core_dev_state_get(void *data, u64 *val) { - struct pmc_dev *pmcdev = s->private; - u32 counter_val; + struct pmc_dev *pmcdev = data; + u32 value; - counter_val = pmc_core_reg_read(pmcdev, - SPT_PMC_SLP_S0_RES_COUNTER_OFFSET); - seq_printf(s, "%u\n", pmc_core_adjust_slp_s0_step(counter_val)); + value = pmc_core_reg_read(pmcdev, SPT_PMC_SLP_S0_RES_COUNTER_OFFSET); + *val = pmc_core_adjust_slp_s0_step(value); return 0; } -static int pmc_core_dev_state_open(struct inode *inode, struct file *file) -{ - return single_open(file, pmc_core_dev_state_show, inode->i_private); -} - -static const struct file_operations pmc_core_dev_state_ops = { - .open = pmc_core_dev_state_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_DEBUGFS_ATTRIBUTE(pmc_core_dev_state, pmc_core_dev_state_get, NULL, "%llu\n"); static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) { @@ -112,12 +99,12 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) struct dentry *dir, *file; dir = debugfs_create_dir("pmc_core", NULL); - if (!dir) + if (IS_ERR_OR_NULL(dir)) return -ENOMEM; pmcdev->dbgfs_dir = dir; file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO, - dir, pmcdev, &pmc_core_dev_state_ops); + dir, pmcdev, &pmc_core_dev_state); if (!file) { pmc_core_dbgfs_unregister(pmcdev); @@ -126,16 +113,6 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) return 0; } -#else -static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) -{ - return 0; -} - -static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) -{ -} -#endif /* CONFIG_DEBUG_FS */ static const struct x86_cpu_id intel_pmc_core_ids[] = { { X86_VENDOR_INTEL, 6, 0x4e, X86_FEATURE_MWAIT, @@ -182,10 +159,8 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) } err = pmc_core_dbgfs_register(pmcdev); - if (err < 0) { - dev_err(&dev->dev, "PMC Core: debugfs register failed.\n"); - return err; - } + if (err < 0) + dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n"); pmc.has_slp_s0_res = true; return 0; diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index a9dadaf787c1..e3f671f4d122 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -23,6 +23,7 @@ /* Sunrise Point Power Management Controller PCI Device ID */ #define SPT_PMC_PCI_DEVICE_ID 0x9d21 + #define SPT_PMC_BASE_ADDR_OFFSET 0x48 #define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c #define SPT_PMC_MMIO_REG_LEN 0x100 @@ -42,9 +43,7 @@ struct pmc_dev { u32 base_addr; void __iomem *regbase; -#if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *dbgfs_dir; -#endif /* CONFIG_DEBUG_FS */ bool has_slp_s0_res; }; -- cgit v1.2.3-59-g8ed1b From 332e081225fc2a657aa587c42943d5f5a7dae88b Mon Sep 17 00:00:00 2001 From: AceLan Kao Date: Fri, 1 Jul 2016 09:51:49 +0800 Subject: intel-vbtn: new driver for Intel Virtual Button This driver supports power button event in Intel Virtual Button currently. New Dell XPS 13 requires this driver for the power button. This driver is copied/modified from intel-hid.c Most credit goes to the author of intel-hid.c, Alex Hung Signed-off-by: AceLan Kao Signed-off-by: Darren Hart --- MAINTAINERS | 6 ++ drivers/platform/x86/Kconfig | 12 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel-vbtn.c | 188 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 drivers/platform/x86/intel-vbtn.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 16700e4fcc4a..f1efeae1fccd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5903,6 +5903,12 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: drivers/platform/x86/intel-hid.c +INTEL VIRTUAL BUTTON DRIVER +M: AceLan Kao +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/intel-vbtn.c + INTEL IDLE DRIVER M: Len Brown L: linux-pm@vger.kernel.org diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b0b98e413343..bdf027716f3e 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -774,6 +774,18 @@ config INTEL_HID_EVENT To compile this driver as a module, choose M here: the module will be called intel_hid. +config INTEL_VBTN + tristate "INTEL VIRTUAL BUTTON" + depends on ACPI + depends on INPUT + select INPUT_SPARSEKMAP + help + This driver provides support for the Intel Virtual Button interface. + Some laptops require this driver for power button support. + + To compile this driver as a module, choose M here: the module will + be called intel_vbtn. + config INTEL_SCU_IPC bool "Intel SCU IPC Support" depends on X86_INTEL_MID diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 9b11b4073e03..2efa86d2a1a7 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o obj-$(CONFIG_TOSHIBA_HAPS) += toshiba_haps.o obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o +obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c new file mode 100644 index 000000000000..146d02f8c9bc --- /dev/null +++ b/drivers/platform/x86/intel-vbtn.c @@ -0,0 +1,188 @@ +/* + * Intel Virtual Button driver for Windows 8.1+ + * + * Copyright (C) 2016 AceLan Kao + * Copyright (C) 2016 Alex Hung + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("AceLan Kao"); + +static const struct acpi_device_id intel_vbtn_ids[] = { + {"INT33D6", 0}, + {"", 0}, +}; + +/* In theory, these are HID usages. */ +static const struct key_entry intel_vbtn_keymap[] = { + { KE_IGNORE, 0xC0, { KEY_POWER } }, /* power key press */ + { KE_KEY, 0xC1, { KEY_POWER } }, /* power key release */ + { KE_END }, +}; + +struct intel_vbtn_priv { + struct input_dev *input_dev; +}; + +static int intel_vbtn_input_setup(struct platform_device *device) +{ + struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); + int ret; + + priv->input_dev = input_allocate_device(); + if (!priv->input_dev) + return -ENOMEM; + + ret = sparse_keymap_setup(priv->input_dev, intel_vbtn_keymap, NULL); + if (ret) + goto err_free_device; + + priv->input_dev->dev.parent = &device->dev; + priv->input_dev->name = "Intel Virtual Button driver"; + priv->input_dev->id.bustype = BUS_HOST; + + ret = input_register_device(priv->input_dev); + if (ret) + goto err_free_device; + + return 0; + +err_free_device: + input_free_device(priv->input_dev); + return ret; +} + +static void intel_vbtn_input_destroy(struct platform_device *device) +{ + struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); + + input_unregister_device(priv->input_dev); +} + +static void notify_handler(acpi_handle handle, u32 event, void *context) +{ + struct platform_device *device = context; + struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); + + if (!sparse_keymap_report_event(priv->input_dev, event, 1, true)) + dev_info(&device->dev, "unknown event index 0x%x\n", + event); +} + +static int intel_vbtn_probe(struct platform_device *device) +{ + acpi_handle handle = ACPI_HANDLE(&device->dev); + struct intel_vbtn_priv *priv; + acpi_status status; + int err; + + status = acpi_evaluate_object(handle, "VBDL", NULL, NULL); + if (!ACPI_SUCCESS(status)) { + dev_warn(&device->dev, "failed to read Intel Virtual Button driver\n"); + return -ENODEV; + } + + priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + dev_set_drvdata(&device->dev, priv); + + err = intel_vbtn_input_setup(device); + if (err) { + pr_err("Failed to setup Intel Virtual Button\n"); + return err; + } + + status = acpi_install_notify_handler(handle, + ACPI_DEVICE_NOTIFY, + notify_handler, + device); + if (ACPI_FAILURE(status)) { + err = -EBUSY; + goto err_remove_input; + } + + return 0; + +err_remove_input: + intel_vbtn_input_destroy(device); + + return err; +} + +static int intel_vbtn_remove(struct platform_device *device) +{ + acpi_handle handle = ACPI_HANDLE(&device->dev); + + intel_vbtn_input_destroy(device); + acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); + + /* + * Even if we failed to shut off the event stream, we can still + * safely detach from the device. + */ + return 0; +} + +static struct platform_driver intel_vbtn_pl_driver = { + .driver = { + .name = "intel-vbtn", + .acpi_match_table = intel_vbtn_ids, + }, + .probe = intel_vbtn_probe, + .remove = intel_vbtn_remove, +}; +MODULE_DEVICE_TABLE(acpi, intel_vbtn_ids); + +static acpi_status __init +check_acpi_dev(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + const struct acpi_device_id *ids = context; + struct acpi_device *dev; + + if (acpi_bus_get_device(handle, &dev) != 0) + return AE_OK; + + if (acpi_match_device_ids(dev, ids) == 0) + if (acpi_create_platform_device(dev)) + dev_info(&dev->dev, + "intel-vbtn: created platform device\n"); + + return AE_OK; +} + +static int __init intel_vbtn_init(void) +{ + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, check_acpi_dev, NULL, + (void *)intel_vbtn_ids, NULL); + + return platform_driver_register(&intel_vbtn_pl_driver); +} +module_init(intel_vbtn_init); + +static void __exit intel_vbtn_exit(void) +{ + platform_driver_unregister(&intel_vbtn_pl_driver); +} +module_exit(intel_vbtn_exit); -- cgit v1.2.3-59-g8ed1b