aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2016-02-15 11:32:36 -0500
committerDarren Hart <dvhart@linux.intel.com>2016-03-23 13:05:45 -0400
commita464afb9581f6a9eabce8a4aa0c70cb71e6bf4d9 (patch)
tree04c0cff2847f24a712c7c454b4b8de0f91547d27 /drivers/platform
parentb13de7019c1b67f0c1b987fc9fe82fcc371ba1d2 (diff)
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: Andy Lutomirski <luto@kernel.org> Acked-by: Pali Rohár <pali.rohar@gmail.com> Signed-off-by: Darren Hart <dvhart@linux.intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/dell-wmi.c71
1 files changed, 64 insertions, 7 deletions
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 32808a463325..e38258a82be5 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -169,6 +169,30 @@ static const u16 bios_to_linux_keycode[256] __initconst = {
169 [255] = KEY_PROG3, 169 [255] = KEY_PROG3,
170}; 170};
171 171
172/*
173 * These are applied if the 0xB2 DMI hotkey table is present and doesn't
174 * override them.
175 */
176static const struct key_entry dell_wmi_extra_keymap[] __initconst = {
177 /* Fn-lock */
178 { KE_IGNORE, 0x151, { KEY_RESERVED } },
179
180 /* Change keyboard illumination */
181 { KE_IGNORE, 0x152, { KEY_KBDILLUMTOGGLE } },
182
183 /*
184 * Radio disable (notify only -- there is no model for which the
185 * WMI event is supposed to trigger an action).
186 */
187 { KE_IGNORE, 0x153, { KEY_RFKILL } },
188
189 /* RGB keyboard backlight control */
190 { KE_IGNORE, 0x154, { KEY_RESERVED } },
191
192 /* Stealth mode toggle */
193 { KE_IGNORE, 0x155, { KEY_RESERVED } },
194};
195
172static struct input_dev *dell_wmi_input_dev; 196static struct input_dev *dell_wmi_input_dev;
173 197
174static void dell_wmi_process_key(int reported_key) 198static void dell_wmi_process_key(int reported_key)
@@ -340,13 +364,27 @@ static void dell_wmi_notify(u32 value, void *context)
340 kfree(obj); 364 kfree(obj);
341} 365}
342 366
367static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len)
368{
369 int i;
370
371 for (i = 0; i < len; i++)
372 if (keymap[i].code == scancode)
373 return true;
374
375 return false;
376}
377
343static void __init handle_dmi_entry(const struct dmi_header *dm, 378static void __init handle_dmi_entry(const struct dmi_header *dm,
379
344 void *opaque) 380 void *opaque)
381
345{ 382{
346 struct dell_dmi_results *results = opaque; 383 struct dell_dmi_results *results = opaque;
347 struct dell_bios_hotkey_table *table; 384 struct dell_bios_hotkey_table *table;
385 int hotkey_num, i, pos = 0;
348 struct key_entry *keymap; 386 struct key_entry *keymap;
349 int hotkey_num, i; 387 int num_bios_keys;
350 388
351 if (results->err || results->keymap) 389 if (results->err || results->keymap)
352 return; /* We already found the hotkey table. */ 390 return; /* We already found the hotkey table. */
@@ -370,7 +408,8 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
370 return; 408 return;
371 } 409 }
372 410
373 keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL); 411 keymap = kcalloc(hotkey_num + ARRAY_SIZE(dell_wmi_extra_keymap) + 1,
412 sizeof(struct key_entry), GFP_KERNEL);
374 if (!keymap) { 413 if (!keymap) {
375 results->err = -ENOMEM; 414 results->err = -ENOMEM;
376 return; 415 return;
@@ -398,14 +437,32 @@ static void __init handle_dmi_entry(const struct dmi_header *dm,
398 } 437 }
399 438
400 if (keycode == KEY_KBDILLUMTOGGLE) 439 if (keycode == KEY_KBDILLUMTOGGLE)
401 keymap[i].type = KE_IGNORE; 440 keymap[pos].type = KE_IGNORE;
402 else 441 else
403 keymap[i].type = KE_KEY; 442 keymap[pos].type = KE_KEY;
404 keymap[i].code = bios_entry->scancode; 443 keymap[pos].code = bios_entry->scancode;
405 keymap[i].keycode = keycode; 444 keymap[pos].keycode = keycode;
445
446 pos++;
447 }
448
449 num_bios_keys = pos;
450
451 for (i = 0; i < ARRAY_SIZE(dell_wmi_extra_keymap); i++) {
452 const struct key_entry *entry = &dell_wmi_extra_keymap[i];
453
454 /*
455 * Check if we've already found this scancode. This takes
456 * quadratic time, but it doesn't matter unless the list
457 * of extra keys gets very long.
458 */
459 if (!have_scancode(entry->code, keymap, num_bios_keys)) {
460 keymap[pos] = *entry;
461 pos++;
462 }
406 } 463 }
407 464
408 keymap[hotkey_num].type = KE_END; 465 keymap[pos].type = KE_END;
409 466
410 results->keymap = keymap; 467 results->keymap = keymap;
411} 468}