--- zzzz-none-000/linux-3.10.107/drivers/platform/x86/dell-wmi.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/platform/x86/dell-wmi.c 2021-02-04 17:41:59.000000000 +0000 @@ -32,10 +32,10 @@ #include #include #include -#include #include #include #include +#include MODULE_AUTHOR("Matthew Garrett "); MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); @@ -66,10 +66,8 @@ /* Battery health status button */ { KE_KEY, 0xe007, { KEY_BATTERY } }, - /* This is actually for all radios. Although physically a - * switch, the notification does not provide an indication of - * state and so it should be reported as a key */ - { KE_KEY, 0xe008, { KEY_WLAN } }, + /* Radio devices state change */ + { KE_IGNORE, 0xe008, { KEY_RFKILL } }, /* The next device is at offset 6, the active devices are at offset 8 and the attached devices at offset 10 */ @@ -130,7 +128,8 @@ KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE, KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2, - KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_MICMUTE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -139,63 +138,160 @@ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - KEY_PROG3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PROG3 }; static struct input_dev *dell_wmi_input_dev; +static void dell_wmi_process_key(int reported_key) +{ + const struct key_entry *key; + + key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, + reported_key); + if (!key) { + pr_info("Unknown key %x pressed\n", reported_key); + return; + } + + pr_debug("Key %x pressed\n", reported_key); + + /* Don't report brightness notifications that will also come via ACPI */ + if ((key->keycode == KEY_BRIGHTNESSUP || + key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) + return; + + sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); +} + static void dell_wmi_notify(u32 value, void *context) { struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; acpi_status status; + acpi_size buffer_size; + u16 *buffer_entry, *buffer_end; + int len, i; status = wmi_get_event_data(value, &response); if (status != AE_OK) { - pr_info("bad event status 0x%x\n", status); + pr_warn("bad event status 0x%x\n", status); return; } obj = (union acpi_object *)response.pointer; + if (!obj) { + pr_warn("no response\n"); + return; + } - if (obj && obj->type == ACPI_TYPE_BUFFER) { - const struct key_entry *key; - int reported_key; - u16 *buffer_entry = (u16 *)obj->buffer.pointer; - int buffer_size = obj->buffer.length/2; - - if (buffer_size >= 2 && dell_new_hk_type && buffer_entry[1] != 0x10) { - pr_info("Received unknown WMI event (0x%x)\n", - buffer_entry[1]); - kfree(obj); - return; - } + if (obj->type != ACPI_TYPE_BUFFER) { + pr_warn("bad response type %x\n", obj->type); + kfree(obj); + return; + } - if (buffer_size >= 3 && (dell_new_hk_type || buffer_entry[1] == 0x0)) - reported_key = (int)buffer_entry[2]; + pr_debug("Received WMI event (%*ph)\n", + obj->buffer.length, obj->buffer.pointer); + + buffer_entry = (u16 *)obj->buffer.pointer; + buffer_size = obj->buffer.length/2; + + if (!dell_new_hk_type) { + if (buffer_size >= 3 && buffer_entry[1] == 0x0) + dell_wmi_process_key(buffer_entry[2]); else if (buffer_size >= 2) - reported_key = (int)buffer_entry[1] & 0xffff; - else { + dell_wmi_process_key(buffer_entry[1]); + else pr_info("Received unknown WMI event\n"); - kfree(obj); - return; + kfree(obj); + return; + } + + buffer_end = buffer_entry + buffer_size; + + 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; } - key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev, - reported_key); - if (!key) { - pr_info("Unknown key %x pressed\n", reported_key); - } else if ((key->keycode == KEY_BRIGHTNESSUP || - key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) { - /* Don't report brightness notifications that will also - * come via ACPI */ - ; - } else { - sparse_keymap_report_entry(dell_wmi_input_dev, key, - 1, true); + pr_debug("Process buffer (%*ph)\n", len*2, buffer_entry); + + switch (buffer_entry[1]) { + case 0x00: + for (i = 2; i < len; ++i) { + switch (buffer_entry[i]) { + case 0xe043: + /* NIC Link is Up */ + pr_debug("NIC Link is Up\n"); + break; + case 0xe044: + /* NIC Link is Down */ + pr_debug("NIC Link is Down\n"); + break; + case 0xe045: + /* Unknown event but defined in DSDT */ + default: + /* Unknown event */ + pr_info("Unknown WMI event type 0x00: " + "0x%x\n", (int)buffer_entry[i]); + break; + } + } + break; + case 0x10: + /* Keys pressed */ + for (i = 2; i < len; ++i) + dell_wmi_process_key(buffer_entry[i]); + break; + case 0x11: + for (i = 2; i < len; ++i) { + switch (buffer_entry[i]) { + case 0xfff0: + /* Battery unplugged */ + pr_debug("Battery unplugged\n"); + break; + case 0xfff1: + /* Battery inserted */ + pr_debug("Battery inserted\n"); + break; + case 0x01e1: + case 0x02ea: + case 0x02eb: + case 0x02ec: + case 0x02f6: + /* Keyboard backlight level changed */ + pr_debug("Keyboard backlight level " + "changed\n"); + break; + default: + /* Unknown event */ + pr_info("Unknown WMI event type 0x11: " + "0x%x\n", (int)buffer_entry[i]); + break; + } + } + break; + default: + /* Unknown event */ + pr_info("Unknown WMI event type 0x%x\n", + (int)buffer_entry[1]); + break; } + + buffer_entry += len; + } + kfree(obj); } @@ -213,11 +309,16 @@ for (i = 0; i < hotkey_num; i++) { const struct dell_bios_keymap_entry *bios_entry = &dell_bios_hotkey_table->keymap[i]; - keymap[i].type = KE_KEY; - keymap[i].code = bios_entry->scancode; - keymap[i].keycode = bios_entry->keycode < 256 ? + u16 keycode = bios_entry->keycode < 256 ? bios_to_linux_keycode[bios_entry->keycode] : KEY_RESERVED; + + if (keycode == KEY_KBDILLUMTOGGLE) + keymap[i].type = KE_IGNORE; + else + keymap[i].type = KE_KEY; + keymap[i].code = bios_entry->scancode; + keymap[i].keycode = keycode; } keymap[hotkey_num].type = KE_END; @@ -297,7 +398,7 @@ } dmi_walk(find_hk_type, NULL); - acpi_video = acpi_video_backlight_support(); + acpi_video = acpi_video_get_backlight_type() != acpi_backlight_vendor; err = dell_wmi_input_setup(); if (err)