^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Dell WMI hotkeys
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2008 Red Hat <mjg@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2014-2015 Pali Rohár <pali@kernel.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Portions based on wistron_btns.c:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/input/sparse-keymap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/wmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <acpi/video.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include "dell-smbios.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "dell-wmi-descriptor.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) MODULE_AUTHOR("Pali Rohár <pali@kernel.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static bool wmi_requires_smbios_request;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct dell_wmi_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct input_dev *input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) u32 interface_version;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static int __init dmi_matched(const struct dmi_system_id *dmi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) wmi_requires_smbios_request = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) .ident = "Dell Inspiron M5110",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) .callback = dmi_matched,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) .ident = "Dell Vostro V131",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * Keymap for WMI events of type 0x0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * Certain keys are flagged as KE_IGNORE. All of these are either
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * notifications (rather than requests for change) or are also sent
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * via the keyboard controller so should not be sent again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static const struct key_entry dell_wmi_keymap_type_0000[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) { KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) /* Key code is followed by brightness level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) { KE_KEY, 0xe005, { KEY_BRIGHTNESSDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) { KE_KEY, 0xe006, { KEY_BRIGHTNESSUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* Battery health status button */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) { KE_KEY, 0xe007, { KEY_BATTERY } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* Radio devices state change, key code is followed by other values */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) { KE_IGNORE, 0xe008, { KEY_RFKILL } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) { KE_KEY, 0xe009, { KEY_EJECTCD } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* Key code is followed by: next, active and attached devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) { KE_KEY, 0xe00b, { KEY_SWITCHVIDEOMODE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /* Key code is followed by keyboard illumination level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) { KE_IGNORE, 0xe00c, { KEY_KBDILLUMTOGGLE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* BIOS error detected */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) { KE_IGNORE, 0xe00d, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* Battery was removed or inserted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) { KE_IGNORE, 0xe00e, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* Wifi Catcher */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) { KE_KEY, 0xe011, { KEY_WLAN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* Ambient light sensor toggle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) { KE_IGNORE, 0xe013, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) { KE_IGNORE, 0xe020, { KEY_MUTE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* Unknown, defined in ACPI DSDT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /* { KE_IGNORE, 0xe023, { KEY_RESERVED } }, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Untested, Dell Instant Launch key on Inspiron 7520 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) /* { KE_IGNORE, 0xe024, { KEY_RESERVED } }, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /* Dell Instant Launch key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) { KE_KEY, 0xe025, { KEY_PROG4 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) /* Audio panel key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) { KE_IGNORE, 0xe026, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /* LCD Display On/Off Control key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) { KE_KEY, 0xe027, { KEY_DISPLAYTOGGLE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* Untested, Multimedia key on Dell Vostro 3560 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /* { KE_IGNORE, 0xe028, { KEY_RESERVED } }, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* Dell Instant Launch key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) { KE_KEY, 0xe029, { KEY_PROG4 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* Untested, Windows Mobility Center button on Inspiron 7520 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /* { KE_IGNORE, 0xe02a, { KEY_RESERVED } }, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* Unknown, defined in ACPI DSDT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* { KE_IGNORE, 0xe02b, { KEY_RESERVED } }, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /* Untested, Dell Audio With Preset Switch button on Inspiron 7520 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) /* { KE_IGNORE, 0xe02c, { KEY_RESERVED } }, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) { KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) { KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) { KE_IGNORE, 0xe034, { KEY_KBDILLUMDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) { KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* NIC Link is Up */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) { KE_IGNORE, 0xe043, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* NIC Link is Down */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) { KE_IGNORE, 0xe044, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * This entry is very suspicious!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * Originally Matthew Garrett created this dell-wmi driver specially for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * "button with a picture of a battery" which has event code 0xe045.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) * Later Mario Limonciello from Dell told us that event code 0xe045 is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * reported by Num Lock and should be ignored because key is send also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) * by keyboard controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * So for now we will ignore this event to prevent potential double
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * Num Lock key press.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) { KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /* Scroll lock and also going to tablet mode on portable devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) { KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /* Untested, going from tablet mode on portable devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* { KE_IGNORE, 0xe047, { KEY_RESERVED } }, */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /* Dell Support Center key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) { KE_IGNORE, 0xe06e, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) { KE_IGNORE, 0xe0f7, { KEY_MUTE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) { KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) { KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct dell_bios_keymap_entry {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) u16 scancode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) u16 keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct dell_bios_hotkey_table {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) struct dmi_header header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) struct dell_bios_keymap_entry keymap[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct dell_dmi_results {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) int keymap_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) struct key_entry *keymap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* Uninitialized entries here are KEY_RESERVED == 0. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) static const u16 bios_to_linux_keycode[256] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) [0] = KEY_MEDIA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) [1] = KEY_NEXTSONG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) [2] = KEY_PLAYPAUSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) [3] = KEY_PREVIOUSSONG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) [4] = KEY_STOPCD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) [5] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) [6] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) [7] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) [8] = KEY_WWW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) [9] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) [10] = KEY_VOLUMEDOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) [11] = KEY_MUTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) [12] = KEY_VOLUMEUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) [13] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) [14] = KEY_BATTERY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) [15] = KEY_EJECTCD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) [16] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) [17] = KEY_SLEEP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) [18] = KEY_PROG1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) [19] = KEY_BRIGHTNESSDOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) [20] = KEY_BRIGHTNESSUP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) [21] = KEY_BRIGHTNESS_AUTO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) [22] = KEY_KBDILLUMTOGGLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) [23] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) [24] = KEY_SWITCHVIDEOMODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) [25] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) [26] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) [27] = KEY_SWITCHVIDEOMODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) [28] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) [29] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) [30] = KEY_PROG2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) [31] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) [32] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) [33] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) [34] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) [35] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) [36] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) [37] = KEY_UNKNOWN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) [38] = KEY_MICMUTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) [255] = KEY_PROG3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * Keymap for WMI events of type 0x0010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * These are applied if the 0xB2 DMI hotkey table is present and doesn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * override them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static const struct key_entry dell_wmi_keymap_type_0010[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /* Fn-lock switched to function keys */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) { KE_IGNORE, 0x0, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* Fn-lock switched to multimedia keys */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) { KE_IGNORE, 0x1, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) /* Keyboard backlight change notification */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) { KE_IGNORE, 0x3f, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* Backlight brightness level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) { KE_KEY, 0x57, { KEY_BRIGHTNESSDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) { KE_KEY, 0x58, { KEY_BRIGHTNESSUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /* Mic mute */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) { KE_KEY, 0x150, { KEY_MICMUTE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) /* Fn-lock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) { KE_IGNORE, 0x151, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* Change keyboard illumination */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) { KE_IGNORE, 0x152, { KEY_KBDILLUMTOGGLE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * Radio disable (notify only -- there is no model for which the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * WMI event is supposed to trigger an action).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) { KE_IGNORE, 0x153, { KEY_RFKILL } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* RGB keyboard backlight control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) { KE_IGNORE, 0x154, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * Stealth mode toggle. This will "disable all lights and sounds".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * The action is performed by the BIOS and EC; the WMI event is just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * a notification. On the XPS 13 9350, this is Fn+F7, and there's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * a BIOS setting to enable and disable the hotkey.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) { KE_IGNORE, 0x155, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) /* Rugged magnetic dock attach/detach events */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) { KE_IGNORE, 0x156, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) { KE_IGNORE, 0x157, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) /* Rugged programmable (P1/P2/P3 keys) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) { KE_KEY, 0x850, { KEY_PROG1 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) { KE_KEY, 0x851, { KEY_PROG2 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) { KE_KEY, 0x852, { KEY_PROG3 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) * Radio disable (notify only -- there is no model for which the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) * WMI event is supposed to trigger an action).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) { KE_IGNORE, 0xe008, { KEY_RFKILL } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) /* Fn-lock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) { KE_IGNORE, 0xe035, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * Keymap for WMI events of type 0x0011
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) static const struct key_entry dell_wmi_keymap_type_0011[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) /* Battery unplugged */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) { KE_IGNORE, 0xfff0, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* Battery inserted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) { KE_IGNORE, 0xfff1, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) * Detachable keyboard detached / undocked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) * Note SW_TABLET_MODE is already reported through the intel_vbtn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) * driver for this, so we ignore it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) { KE_IGNORE, 0xfff2, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* Detachable keyboard attached / docked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) { KE_IGNORE, 0xfff3, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) /* Keyboard backlight level changed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) { KE_IGNORE, KBD_LED_OFF_TOKEN, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) { KE_IGNORE, KBD_LED_ON_TOKEN, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) { KE_IGNORE, KBD_LED_AUTO_TOKEN, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) { KE_IGNORE, KBD_LED_AUTO_25_TOKEN, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) { KE_IGNORE, KBD_LED_AUTO_50_TOKEN, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) { KE_IGNORE, KBD_LED_AUTO_75_TOKEN, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) { KE_IGNORE, KBD_LED_AUTO_100_TOKEN, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) * Keymap for WMI events of type 0x0012
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * They are events with extended data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) static const struct key_entry dell_wmi_keymap_type_0012[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) /* Fn-lock button pressed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) { KE_IGNORE, 0xe035, { KEY_RESERVED } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) static void dell_wmi_process_key(struct wmi_device *wdev, int type, int code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) const struct key_entry *key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) key = sparse_keymap_entry_from_scancode(priv->input_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) (type << 16) | code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (!key) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) type, code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) pr_debug("Key with type 0x%04x and code 0x%04x pressed\n", type, code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /* Don't report brightness notifications that will also come via ACPI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if ((key->keycode == KEY_BRIGHTNESSUP ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) key->keycode == KEY_BRIGHTNESSDOWN) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) acpi_video_handles_brightness_key_presses())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (type == 0x0000 && code == 0xe025 && !wmi_requires_smbios_request)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) if (key->keycode == KEY_KBDILLUMTOGGLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) dell_laptop_call_notifier(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) DELL_LAPTOP_KBD_BACKLIGHT_BRIGHTNESS_CHANGED, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) sparse_keymap_report_entry(priv->input_dev, key, 1, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static void dell_wmi_notify(struct wmi_device *wdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) union acpi_object *obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) u16 *buffer_entry, *buffer_end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) acpi_size buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) int len, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (obj->type != ACPI_TYPE_BUFFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) pr_warn("bad response type %x\n", obj->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) pr_debug("Received WMI event (%*ph)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) obj->buffer.length, obj->buffer.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) buffer_entry = (u16 *)obj->buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) buffer_size = obj->buffer.length/2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) buffer_end = buffer_entry + buffer_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * BIOS/ACPI on devices with WMI interface version 0 does not clear
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) * buffer before filling it. So next time when BIOS/ACPI send WMI event
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * which is smaller as previous then it contains garbage in buffer from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * previous event.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) * BIOS/ACPI on devices with WMI interface version 1 clears buffer and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) * sometimes send more events in buffer at one call.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) * So to prevent reading garbage from buffer we will process only first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) * one event on devices with WMI interface version 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (priv->interface_version == 0 && buffer_entry < buffer_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (buffer_end > buffer_entry + buffer_entry[0] + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) buffer_end = buffer_entry + buffer_entry[0] + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) while (buffer_entry < buffer_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) len = buffer_entry[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (len == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) len++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (buffer_entry + len > buffer_end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) pr_warn("Invalid length of WMI event\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) switch (buffer_entry[1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) case 0x0000: /* One key pressed or event occurred */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) case 0x0012: /* Event with extended data occurred */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (len > 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) dell_wmi_process_key(wdev, buffer_entry[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) buffer_entry[2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) /* Extended data is currently ignored */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) case 0x0010: /* Sequence of keys pressed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) case 0x0011: /* Sequence of events occurred */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) for (i = 2; i < len; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) dell_wmi_process_key(wdev, buffer_entry[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) buffer_entry[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) default: /* Unknown event */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) pr_info("Unknown WMI event type 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) (int)buffer_entry[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) buffer_entry += len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) for (i = 0; i < len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (keymap[i].code == scancode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) static void handle_dmi_entry(const struct dmi_header *dm, void *opaque)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) struct dell_dmi_results *results = opaque;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) struct dell_bios_hotkey_table *table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) int hotkey_num, i, pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) struct key_entry *keymap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (results->err || results->keymap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return; /* We already found the hotkey table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) /* The Dell hotkey table is type 0xB2. Scan until we find it. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (dm->type != 0xb2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) table = container_of(dm, struct dell_bios_hotkey_table, header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) hotkey_num = (table->header.length -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) sizeof(struct dell_bios_hotkey_table)) /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) sizeof(struct dell_bios_keymap_entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (hotkey_num < 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) * Historically, dell-wmi would ignore a DMI entry of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) * fewer than 7 bytes. Sizes between 4 and 8 bytes are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) * nonsensical (both the header and all entries are 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) * bytes), so we approximate the old behavior by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) * ignoring tables with fewer than one entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) keymap = kcalloc(hotkey_num, sizeof(struct key_entry), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (!keymap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) results->err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) for (i = 0; i < hotkey_num; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) const struct dell_bios_keymap_entry *bios_entry =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) &table->keymap[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* Uninitialized entries are 0 aka KEY_RESERVED. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) u16 keycode = (bios_entry->keycode <
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) ARRAY_SIZE(bios_to_linux_keycode)) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) bios_to_linux_keycode[bios_entry->keycode] :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) (bios_entry->keycode == 0xffff ? KEY_UNKNOWN : KEY_RESERVED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) * Log if we find an entry in the DMI table that we don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) * understand. If this happens, we should figure out what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * the entry means and add it to bios_to_linux_keycode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (keycode == KEY_RESERVED) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) pr_info("firmware scancode 0x%x maps to unrecognized keycode 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) bios_entry->scancode, bios_entry->keycode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (keycode == KEY_KBDILLUMTOGGLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) keymap[pos].type = KE_IGNORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) keymap[pos].type = KE_KEY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) keymap[pos].code = bios_entry->scancode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) keymap[pos].keycode = keycode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) pos++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) results->keymap = keymap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) results->keymap_size = pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) static int dell_wmi_input_setup(struct wmi_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) struct dell_dmi_results dmi_results = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) struct key_entry *keymap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) int err, i, pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) priv->input_dev = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (!priv->input_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) priv->input_dev->name = "Dell WMI hotkeys";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) priv->input_dev->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) priv->input_dev->dev.parent = &wdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) if (dmi_walk(handle_dmi_entry, &dmi_results)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * Historically, dell-wmi ignored dmi_walk errors. A failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * is certainly surprising, but it probably just indicates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * a very old laptop.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) pr_warn("no DMI; using the old-style hotkey interface\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) if (dmi_results.err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) err = dmi_results.err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) keymap = kcalloc(dmi_results.keymap_size +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) ARRAY_SIZE(dell_wmi_keymap_type_0000) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) ARRAY_SIZE(dell_wmi_keymap_type_0010) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) ARRAY_SIZE(dell_wmi_keymap_type_0011) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) ARRAY_SIZE(dell_wmi_keymap_type_0012) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) sizeof(struct key_entry), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (!keymap) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) kfree(dmi_results.keymap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /* Append table with events of type 0x0010 which comes from DMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) for (i = 0; i < dmi_results.keymap_size; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) keymap[pos] = dmi_results.keymap[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) keymap[pos].code |= (0x0010 << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) pos++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) kfree(dmi_results.keymap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) /* Append table with extra events of type 0x0010 which are not in DMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0010); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) const struct key_entry *entry = &dell_wmi_keymap_type_0010[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) * Check if we've already found this scancode. This takes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) * quadratic time, but it doesn't matter unless the list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) * of extra keys gets very long.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (dmi_results.keymap_size &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) have_scancode(entry->code | (0x0010 << 16),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) keymap, dmi_results.keymap_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) )
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) keymap[pos] = *entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) keymap[pos].code |= (0x0010 << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) pos++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) /* Append table with events of type 0x0011 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0011); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) keymap[pos] = dell_wmi_keymap_type_0011[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) keymap[pos].code |= (0x0011 << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) pos++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) /* Append table with events of type 0x0012 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) keymap[pos] = dell_wmi_keymap_type_0012[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) keymap[pos].code |= (0x0012 << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) pos++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * Now append also table with "legacy" events of type 0x0000. Some of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) * them are reported also on laptops which have scancodes in DMI.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0000); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) keymap[pos] = dell_wmi_keymap_type_0000[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) pos++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) keymap[pos].type = KE_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) err = sparse_keymap_setup(priv->input_dev, keymap, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * Sparse keymap library makes a copy of keymap so we don't need the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) * original one that was allocated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) kfree(keymap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) err = input_register_device(priv->input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) err_free_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) input_free_device(priv->input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) static void dell_wmi_input_destroy(struct wmi_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) input_unregister_device(priv->input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) * According to Dell SMBIOS documentation:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) * 17 3 Application Program Registration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) * cbArg1 Application ID 1 = 0x00010000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) * cbArg2 Application ID 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) * QUICKSET/DCP = 0x51534554 "QSET"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * ALS Driver = 0x416c7353 "AlsS"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * Latitude ON = 0x4c6f6e52 "LonR"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) * cbArg3 Application version or revision number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) * cbArg4 0 = Unregister application
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) * 1 = Register application
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) * cbRes1 Standard return codes (0, -1, -2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static int dell_wmi_events_set_enabled(bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct calling_interface_buffer *buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) buffer = kzalloc(sizeof(struct calling_interface_buffer), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) if (!buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) buffer->cmd_class = CLASS_INFO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) buffer->cmd_select = SELECT_APP_REGISTRATION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) buffer->input[0] = 0x10000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) buffer->input[1] = 0x51534554;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) buffer->input[3] = enable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) ret = dell_smbios_call(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) ret = buffer->output[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) kfree(buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) return dell_smbios_error(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) static int dell_wmi_probe(struct wmi_device *wdev, const void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) struct dell_wmi_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) ret = dell_wmi_get_descriptor_valid();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) priv = devm_kzalloc(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) &wdev->dev, sizeof(struct dell_wmi_priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) dev_set_drvdata(&wdev->dev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (!dell_wmi_get_interface_version(&priv->interface_version))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) return dell_wmi_input_setup(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) static int dell_wmi_remove(struct wmi_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) dell_wmi_input_destroy(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) static const struct wmi_device_id dell_wmi_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) { .guid_string = DELL_EVENT_GUID },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) static struct wmi_driver dell_wmi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) .name = "dell-wmi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) .id_table = dell_wmi_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) .probe = dell_wmi_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) .remove = dell_wmi_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) .notify = dell_wmi_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) static int __init dell_wmi_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) dmi_check_system(dell_wmi_smbios_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) if (wmi_requires_smbios_request) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) err = dell_wmi_events_set_enabled(true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) pr_err("Failed to enable WMI events\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) return wmi_driver_register(&dell_wmi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) late_initcall(dell_wmi_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) static void __exit dell_wmi_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) if (wmi_requires_smbios_request)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) dell_wmi_events_set_enabled(false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) wmi_driver_unregister(&dell_wmi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) module_exit(dell_wmi_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) MODULE_DEVICE_TABLE(wmi, dell_wmi_id_table);