cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dell-wmi-base.c (22180B)


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