From patchwork Tue Jun 7 23:32:27 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 9162841 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 1EFBA60467 for ; Tue, 7 Jun 2016 23:34:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0ECC9200F4 for ; Tue, 7 Jun 2016 23:34:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 025202836E; Tue, 7 Jun 2016 23:34:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1D5AF2835C for ; Tue, 7 Jun 2016 23:34:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752903AbcFGXdv (ORCPT ); Tue, 7 Jun 2016 19:33:51 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:36717 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932519AbcFGXc5 (ORCPT ); Tue, 7 Jun 2016 19:32:57 -0400 Received: by mail-wm0-f68.google.com with SMTP id m124so26683932wme.3; Tue, 07 Jun 2016 16:32:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=iRwUX+urPDjeiZ6x8v1QHt43RSerU+rg5EZwrR06EHg=; b=MTfRlwjTeL7EM9cHTu/uv3/6VqQStcPIUg+/MfGlfOFsVkZ4iWvw7c0l70d9rteLtw rqDWc7y1kgCK5E7rQNbsg0tqXwU9WGG+bBQbA7a4rWztCdTBiSabVwL3R9EmFmQD48wT rW8wEMr1IkRXpK4TePXGMNNsxrvHhReufJqwd970j+9RE++6tOSCa4GbWMsW4YBquWHK fcq7iIV8lWoboe4EJjP8AvyM3OJEAIdQVqzW6a5BCw5HoxPpwxWcbZORGXrvZoRml9Cc k1HnbbnGqOx+mg1/LR9GQbyIfHKamaod79k2M8IfZRsSBfRPUtTxDhBz7FMkoJSkpAZ9 g1tA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=iRwUX+urPDjeiZ6x8v1QHt43RSerU+rg5EZwrR06EHg=; b=XhcPYaJyUE9RbLt8jIreYhQw4k5DD+HHZWPG7LJUbBqZMVS8525hx9g+6U9DcvZvFJ TKDsJbCoF9kNkDw2H4vmd1jw/2kZbVp0UFa7ufPgaQ0i6qHDO8b2BZX+a5EL/+FHDbEi GRmO80eKBhFQH4p4vSVuwYz3z0EaNKcaRNNIlIKCZ/5LZGu+Qyn0OsOuZMbZq/OsC4vn labd8bwJOyuQsJ/y+reTCRCA47By8x5QzoA3i1qap5gVYC3lu1fK/W1VCyaAi8oYtaMl wYQ5iJr1WiIRnbJqNWRSwpaggpoqf0qqVt+Hdm1EEO5Fv7u1AzdggTcxZpQavnVx0Qs0 bPcQ== X-Gm-Message-State: ALyK8tLr2roAGJBM7bpaFIUCUcxE8JQdoNIFGZ+ZzI2a7I2mW3NkwT8sI/y4eBu7vaL7Cw== X-Received: by 10.28.102.196 with SMTP id a187mr1665959wmc.99.1465342375441; Tue, 07 Jun 2016 16:32:55 -0700 (PDT) Received: from Pali-Latitude.lan (pali.kolej.mff.cuni.cz. [78.128.193.202]) by smtp.gmail.com with ESMTPSA id d195sm21742155wmd.12.2016.06.07.16.32.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 07 Jun 2016 16:32:54 -0700 (PDT) From: =?UTF-8?q?Pali=20Roh=C3=A1r?= To: Matthew Garrett , Darren Hart , Gabriele Mazzotta , =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Cc: Mario Limonciello , Andy Lutomirski , Alex Hung , platform-driver-x86@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Pali=20Roh=C3=A1r?= Subject: [PATCH v2 4/4] dell-wmi: Rework code for generating sparse keymap and processing WMI events Date: Wed, 8 Jun 2016 01:32:27 +0200 Message-Id: <1465342347-20635-5-git-send-email-pali.rohar@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1465342347-20635-1-git-send-email-pali.rohar@gmail.com> References: <1465342347-20635-1-git-send-email-pali.rohar@gmail.com> MIME-Version: 1.0 Sender: platform-driver-x86-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: platform-driver-x86@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch unify procedure for generating sparse keymap and unify also 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 construct 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ń --- drivers/platform/x86/dell-wmi.c | 215 +++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 108 deletions(-) diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index a406f01..fe831f3 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,59 +385,21 @@ 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 in buffer could contain additional information */ break; - case 0x10: - /* Keys pressed */ + case 0x0010: + /* Sequence of keys pressed */ for (i = 2; i < len; ++i) - dell_wmi_process_key(buffer_entry[i]); + dell_wmi_process_key(0x0010, 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; - } - } + case 0x0011: + /* Sequence of events occurred */ + for (i = 2; i < len; ++i) + dell_wmi_process_key(0x0011, buffer_entry[i]); break; default: /* Unknown event */ @@ -459,7 +427,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 +434,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 +457,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 +494,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 +526,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;