/* * Keymap for WMI events of type 0x0000 * * Certain keys are flagged as KE_IGNORE. All of these are either * notifications (rather than requests for change) or are also sent * via the keyboard controller so should not be sent again.
*/ staticconststruct key_entry dell_wmi_keymap_type_0000[] = {
{ KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
/* NIC Link is Up */
{ KE_IGNORE, 0xe043, { KEY_RESERVED } },
/* NIC Link is Down */
{ KE_IGNORE, 0xe044, { KEY_RESERVED } },
/* * This entry is very suspicious! * Originally Matthew Garrett created this dell-wmi driver specially for * "button with a picture of a battery" which has event code 0xe045. * Later Mario Limonciello from Dell told us that event code 0xe045 is * reported by Num Lock and should be ignored because key is send also * by keyboard controller. * So for now we will ignore this event to prevent potential double * Num Lock key press.
*/
{ KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
/* Scroll lock and also going to tablet mode on portable devices */
{ KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
/* Untested, going from tablet mode on portable devices */ /* { KE_IGNORE, 0xe047, { KEY_RESERVED } }, */
/* Dell Support Center key */
{ KE_IGNORE, 0xe06e, { KEY_RESERVED } },
/* * Keymap for WMI events of type 0x0010 * * These are applied if the 0xB2 DMI hotkey table is present and doesn't * override them.
*/ staticconststruct key_entry dell_wmi_keymap_type_0010[] = { /* Fn-lock switched to function keys */
{ KE_IGNORE, 0x0, { KEY_RESERVED } },
/* * Radio disable (notify only -- there is no model for which the * WMI event is supposed to trigger an action).
*/
{ KE_IGNORE, 0x153, { KEY_RFKILL } },
/* * Stealth mode toggle. This will "disable all lights and sounds". * The action is performed by the BIOS and EC; the WMI event is just * a notification. On the XPS 13 9350, this is Fn+F7, and there's * a BIOS setting to enable and disable the hotkey.
*/
{ KE_IGNORE, 0x155, { KEY_RESERVED } },
/* * Radio disable (notify only -- there is no model for which the * WMI event is supposed to trigger an action).
*/
{ KE_IGNORE, 0xe008, { KEY_RFKILL } },
/* * Detachable keyboard detached / undocked * Note SW_TABLET_MODE is already reported through the intel_vbtn * driver for this, so we ignore it.
*/
{ KE_IGNORE, 0xfff2, { KEY_RESERVED } },
/* * Keymap for WMI events of type 0x0012 * They are events with extended data
*/ staticconststruct key_entry dell_wmi_keymap_type_0012[] = { /* Backlight brightness change event */
{ KE_IGNORE, 0x0003, { KEY_RESERVED } },
staticint dell_wmi_process_key(struct wmi_device *wdev, int type, int code, u16 *buffer, int remaining)
{ struct dell_wmi_priv *priv = dev_get_drvdata(&wdev->dev); conststruct key_entry *key; int used = 0; int value = 1;
key = sparse_keymap_entry_from_scancode(priv->input_dev,
(type << 16) | code); if (!key) {
pr_info("Unknown key with type 0x%04x and code 0x%04x pressed\n",
type, code); return 0;
}
pr_debug("Key with type 0x%04x and code 0x%04x pressed\n", type, code);
/* Don't report brightness notifications that will also come via ACPI */ if ((key->keycode == KEY_BRIGHTNESSUP ||
key->keycode == KEY_BRIGHTNESSDOWN) &&
acpi_video_handles_brightness_key_presses()) return 0;
/* * BIOS/ACPI on devices with WMI interface version 0 does not clear * buffer before filling it. So next time when BIOS/ACPI send WMI event * which is smaller as previous then it contains garbage in buffer from * previous event. * * BIOS/ACPI on devices with WMI interface version 1 clears buffer and * sometimes send more events in buffer at one call. * * So to prevent reading garbage from buffer we will process only first * one event on devices with WMI interface version 0.
*/ if (priv->interface_version == 0 && buffer_entry < buffer_end) if (buffer_end > buffer_entry + buffer_entry[0] + 1)
buffer_end = buffer_entry + buffer_entry[0] + 1;
while (buffer_entry < buffer_end) {
len = buffer_entry[0]; if (len == 0) break;
len++;
if (buffer_entry + len > buffer_end) {
pr_warn("Invalid length of WMI event\n"); break;
}
switch (buffer_entry[1]) { case 0x0000: /* One key pressed or event occurred */ if (len > 2)
dell_wmi_process_key(wdev, buffer_entry[1],
buffer_entry[2],
buffer_entry + 3,
len - 3); /* Extended data is currently ignored */ break; case 0x0010: /* Sequence of keys pressed */ case 0x0011: /* Sequence of events occurred */ for (i = 2; i < len; ++i)
i += dell_wmi_process_key(wdev, buffer_entry[1],
buffer_entry[i],
buffer_entry + i,
len - i - 1); break; case 0x0012: if ((len > 4) && dell_privacy_process_event(buffer_entry[1], buffer_entry[3],
buffer_entry[4])) /* dell_privacy_process_event has handled the event */; elseif (len > 2)
dell_wmi_process_key(wdev, buffer_entry[1], buffer_entry[2],
buffer_entry + 3, len - 3); break; default: /* Unknown event */
pr_info("Unknown WMI event type 0x%x\n",
(int)buffer_entry[1]); break;
}
buffer_entry += len;
}
}
staticbool have_scancode(u32 scancode, conststruct key_entry *keymap, int len)
{ int i;
for (i = 0; i < len; i++) if (keymap[i].code == scancode) returntrue;
hotkey_num = (table->header.length - sizeof(struct dell_bios_hotkey_table)) / sizeof(struct dell_bios_keymap_entry); if (hotkey_num < 1) { /* * Historically, dell-wmi would ignore a DMI entry of * fewer than 7 bytes. Sizes between 4 and 8 bytes are * nonsensical (both the header and all entries are 4 * bytes), so we approximate the old behavior by * ignoring tables with fewer than one entry.
*/ return;
}
/* * Log if we find an entry in the DMI table that we don't * understand. If this happens, we should figure out what * the entry means and add it to bios_to_linux_keycode.
*/ if (keycode == KEY_RESERVED) {
pr_info("firmware scancode 0x%x maps to unrecognized keycode 0x%x\n",
bios_entry->scancode, bios_entry->keycode); continue;
}
if (dmi_walk(handle_dmi_entry, &dmi_results)) { /* * Historically, dell-wmi ignored dmi_walk errors. A failure * is certainly surprising, but it probably just indicates * a very old laptop.
*/
pr_warn("no DMI; using the old-style hotkey interface\n");
}
if (dmi_results.err) {
err = dmi_results.err; goto err_free_dev;
}
/* Append table with events of type 0x0010 which comes from DMI */ for (i = 0; i < dmi_results.keymap_size; i++) {
keymap[pos] = dmi_results.keymap[i];
keymap[pos].code |= (0x0010 << 16);
pos++;
}
kfree(dmi_results.keymap);
/* Append table with extra events of type 0x0010 which are not in DMI */ for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0010); i++) { conststruct key_entry *entry = &dell_wmi_keymap_type_0010[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 (dmi_results.keymap_size &&
have_scancode(entry->code | (0x0010 << 16),
keymap, dmi_results.keymap_size)
) continue;
/* Append table with events of type 0x0011 */ for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0011); i++) {
keymap[pos] = dell_wmi_keymap_type_0011[i];
keymap[pos].code |= (0x0011 << 16);
pos++;
}
/* Append table with events of type 0x0012 */ for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
keymap[pos] = dell_wmi_keymap_type_0012[i];
keymap[pos].code |= (0x0012 << 16);
pos++;
}
/* * Now append also table with "legacy" events of type 0x0000. Some of * them are reported also on laptops which have scancodes in DMI.
*/ for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0000); i++) {
keymap[pos] = dell_wmi_keymap_type_0000[i];
pos++;
}
keymap[pos].type = KE_END;
err = sparse_keymap_setup(priv->input_dev, keymap, NULL); /* * Sparse keymap library makes a copy of keymap so we don't need the * original one that was allocated.
*/
kfree(keymap); if (err) goto err_free_dev;
err = input_register_device(priv->input_dev); if (err) goto err_free_dev;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.