Commit a464afb9 authored by Andy Lutomirski's avatar Andy Lutomirski Committed by Darren Hart

dell-wmi: Support new hotkeys on the XPS 13 9350 (Skylake)

The XPS 13 9350 sends WMI keypress events that aren't enumerated in
the DMI table.  Add a table listing them.  To avoid breaking things
that worked before, these un-enumerated hotkeys won't be used if the
DMI table maps them to something else.

FWIW, it appears that the DMI table may be a legacy thing and we
might want to rethink how we handle events in general.  As an
example, a whole lot of things map to KEY_PROG3 via the DMI table.

This doesn't send keypress events for any of the new events.  They
appear to all be handled by other means (keyboard illumination is
handled automatically and rfkill is handled by intel-hid).
Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
Acked-by: default avatarPali Rohár <pali.rohar@gmail.com>
Signed-off-by: default avatarDarren Hart <dvhart@linux.intel.com>
parent b13de701
...@@ -169,6 +169,30 @@ static const u16 bios_to_linux_keycode[256] __initconst = { ...@@ -169,6 +169,30 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
[255] = KEY_PROG3, [255] = KEY_PROG3,
}; };
/*
* 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 = {
/* Fn-lock */
{ KE_IGNORE, 0x151, { KEY_RESERVED } },
/* Change keyboard illumination */
{ KE_IGNORE, 0x152, { KEY_KBDILLUMTOGGLE } },
/*
* Radio disable (notify only -- there is no model for which the
* WMI event is supposed to trigger an action).
*/
{ KE_IGNORE, 0x153, { KEY_RFKILL } },
/* RGB keyboard backlight control */
{ KE_IGNORE, 0x154, { KEY_RESERVED } },
/* Stealth mode toggle */
{ KE_IGNORE, 0x155, { KEY_RESERVED } },
};
static struct input_dev *dell_wmi_input_dev; static struct input_dev *dell_wmi_input_dev;
static void dell_wmi_process_key(int reported_key) static void dell_wmi_process_key(int reported_key)
...@@ -340,13 +364,27 @@ static void dell_wmi_notify(u32 value, void *context) ...@@ -340,13 +364,27 @@ static void dell_wmi_notify(u32 value, void *context)
kfree(obj); kfree(obj);
} }
static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len)
{
int i;
for (i = 0; i < len; i++)
if (keymap[i].code == scancode)
return true;
return false;
}
static void __init handle_dmi_entry(const struct dmi_header *dm, static void __init handle_dmi_entry(const struct dmi_header *dm,
void *opaque) void *opaque)
{ {
struct dell_dmi_results *results = opaque; struct dell_dmi_results *results = opaque;
struct dell_bios_hotkey_table *table; struct dell_bios_hotkey_table *table;
int hotkey_num, i, pos = 0;
struct key_entry *keymap; struct key_entry *keymap;
int hotkey_num, i; int num_bios_keys;
if (results->err || results->keymap) if (results->err || results->keymap)
return; /* We already found the hotkey table. */ return; /* We already found the hotkey table. */
...@@ -370,7 +408,8 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, ...@@ -370,7 +408,8 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
return; return;
} }
keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL); keymap = kcalloc(hotkey_num + ARRAY_SIZE(dell_wmi_extra_keymap) + 1,
sizeof(struct key_entry), GFP_KERNEL);
if (!keymap) { if (!keymap) {
results->err = -ENOMEM; results->err = -ENOMEM;
return; return;
...@@ -398,14 +437,32 @@ static void __init handle_dmi_entry(const struct dmi_header *dm, ...@@ -398,14 +437,32 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
} }
if (keycode == KEY_KBDILLUMTOGGLE) if (keycode == KEY_KBDILLUMTOGGLE)
keymap[i].type = KE_IGNORE; keymap[pos].type = KE_IGNORE;
else else
keymap[i].type = KE_KEY; keymap[pos].type = KE_KEY;
keymap[i].code = bios_entry->scancode; keymap[pos].code = bios_entry->scancode;
keymap[i].keycode = keycode; keymap[pos].keycode = keycode;
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[hotkey_num].type = KE_END; keymap[pos].type = KE_END;
results->keymap = keymap; results->keymap = keymap;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment