Merge tag 'platform-drivers-x86-v4.5-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x86 platform driver updates from Darren Hart: "Add intel punit and telemetry driver for APL SoCs. Add intel-hid driver for various laptop hotkey support. Add asus-wireless radio control driver. Keyboard backlight support/improvements for ThinkPads, Vaio, and Toshiba. Several hotkey related fixes and improvements for dell and toshiba. Fix oops on dual GPU Macs in apple-gmux. A few new device IDs and quirks. Various minor config related build issues and cleanups. surface pro 4: - fix compare_const_fl.cocci warnings - Add support for Surface Pro 4 Buttons platform/x86: - Add Intel Telemetry Debugfs interfaces - Add Intel telemetry platform device - Add Intel telemetry platform driver - Add Intel Telemetry Core Driver - add NULL check for input parameters - add Intel P-Unit mailbox IPC driver - update acpi resource structure for Punit thinkpad_acpi: - Add support for keyboard backlight dell-wmi: - Process only one event on devices with interface version 0 - Check if Dell WMI descriptor structure is valid - Improve unknown hotkey handling - Use a C99-style array for bios_to_linux_keycode tc1100-wmi: - fix build warning when CONFIG_PM not enabled asus-wireless: - Add ACPI HID ATK4001 - Add Asus Wireless Radio Control driver asus-wmi: - drop to_platform_driver macro intel-hid: - new hid event driver for hotkeys sony-laptop: - Keyboard backlight control for some Vaio Fit models ideapad-laptop: - Add Lenovo ideapad Y700-17ISK to no_hw_rfkill dmi list apple-gmux: - Assign apple_gmux_data before registering toshiba_acpi: - Add rfkill dependency to ACPI_TOSHIBA entry - Fix keyboard backlight sysfs entries not being updated - Add WWAN RFKill support - Add support for WWAN devices - Fix blank screen at boot if transflective backlight is supported - Propagate the hotkey value via genetlink toshiba_bluetooth: - Add missing newline in toshiba_bluetooth_present function" * tag 'platform-drivers-x86-v4.5-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (29 commits) surface pro 4: fix compare_const_fl.cocci warnings surface pro 4: Add support for Surface Pro 4 Buttons platform:x86: Add Intel Telemetry Debugfs interfaces platform:x86: Add Intel telemetry platform device platform:x86: Add Intel telemetry platform driver platform/x86: Add Intel Telemetry Core Driver intel_punit_ipc: add NULL check for input parameters thinkpad_acpi: Add support for keyboard backlight dell-wmi: Process only one event on devices with interface version 0 dell-wmi: Check if Dell WMI descriptor structure is valid tc1100-wmi: fix build warning when CONFIG_PM not enabled asus-wireless: Add ACPI HID ATK4001 platform/x86: Add Asus Wireless Radio Control driver asus-wmi: drop to_platform_driver macro intel-hid: new hid event driver for hotkeys Keyboard backlight control for some Vaio Fit models platform/x86: Add rfkill dependency to ACPI_TOSHIBA entry platform:x86: add Intel P-Unit mailbox IPC driver intel_pmc_ipc: update acpi resource structure for Punit ideapad-laptop: Add Lenovo ideapad Y700-17ISK to no_hw_rfkill dmi list ...
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
* Dell WMI hotkeys
|
||||
*
|
||||
* Copyright (C) 2008 Red Hat <mjg@redhat.com>
|
||||
* Copyright (C) 2014-2015 Pali Rohár <pali.rohar@gmail.com>
|
||||
*
|
||||
* Portions based on wistron_btns.c:
|
||||
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
|
||||
@@ -38,12 +39,17 @@
|
||||
#include <acpi/video.h>
|
||||
|
||||
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
|
||||
MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
|
||||
MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
|
||||
#define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
|
||||
|
||||
static u32 dell_wmi_interface_version;
|
||||
|
||||
MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
|
||||
MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID);
|
||||
|
||||
/*
|
||||
* Certain keys are flagged as KE_IGNORE. All of these are either
|
||||
@@ -116,28 +122,48 @@ struct dell_bios_hotkey_table {
|
||||
|
||||
static const struct dell_bios_hotkey_table *dell_bios_hotkey_table;
|
||||
|
||||
/* Uninitialized entries here are KEY_RESERVED == 0. */
|
||||
static const u16 bios_to_linux_keycode[256] __initconst = {
|
||||
|
||||
KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG,
|
||||
KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_WWW, KEY_UNKNOWN, KEY_VOLUMEDOWN, KEY_MUTE,
|
||||
KEY_VOLUMEUP, KEY_UNKNOWN, KEY_BATTERY, KEY_EJECTCD,
|
||||
KEY_UNKNOWN, KEY_SLEEP, KEY_PROG1, KEY_BRIGHTNESSDOWN,
|
||||
KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE,
|
||||
KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2,
|
||||
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,
|
||||
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, 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] = KEY_MEDIA,
|
||||
[1] = KEY_NEXTSONG,
|
||||
[2] = KEY_PLAYPAUSE,
|
||||
[3] = KEY_PREVIOUSSONG,
|
||||
[4] = KEY_STOPCD,
|
||||
[5] = KEY_UNKNOWN,
|
||||
[6] = KEY_UNKNOWN,
|
||||
[7] = KEY_UNKNOWN,
|
||||
[8] = KEY_WWW,
|
||||
[9] = KEY_UNKNOWN,
|
||||
[10] = KEY_VOLUMEDOWN,
|
||||
[11] = KEY_MUTE,
|
||||
[12] = KEY_VOLUMEUP,
|
||||
[13] = KEY_UNKNOWN,
|
||||
[14] = KEY_BATTERY,
|
||||
[15] = KEY_EJECTCD,
|
||||
[16] = KEY_UNKNOWN,
|
||||
[17] = KEY_SLEEP,
|
||||
[18] = KEY_PROG1,
|
||||
[19] = KEY_BRIGHTNESSDOWN,
|
||||
[20] = KEY_BRIGHTNESSUP,
|
||||
[21] = KEY_UNKNOWN,
|
||||
[22] = KEY_KBDILLUMTOGGLE,
|
||||
[23] = KEY_UNKNOWN,
|
||||
[24] = KEY_SWITCHVIDEOMODE,
|
||||
[25] = KEY_UNKNOWN,
|
||||
[26] = KEY_UNKNOWN,
|
||||
[27] = KEY_SWITCHVIDEOMODE,
|
||||
[28] = KEY_UNKNOWN,
|
||||
[29] = KEY_UNKNOWN,
|
||||
[30] = KEY_PROG2,
|
||||
[31] = KEY_UNKNOWN,
|
||||
[32] = KEY_UNKNOWN,
|
||||
[33] = KEY_UNKNOWN,
|
||||
[34] = KEY_UNKNOWN,
|
||||
[35] = KEY_UNKNOWN,
|
||||
[36] = KEY_UNKNOWN,
|
||||
[37] = KEY_UNKNOWN,
|
||||
[38] = KEY_MICMUTE,
|
||||
[255] = KEY_PROG3,
|
||||
};
|
||||
|
||||
static struct input_dev *dell_wmi_input_dev;
|
||||
@@ -149,7 +175,8 @@ static void dell_wmi_process_key(int reported_key)
|
||||
key = sparse_keymap_entry_from_scancode(dell_wmi_input_dev,
|
||||
reported_key);
|
||||
if (!key) {
|
||||
pr_info("Unknown key %x pressed\n", reported_key);
|
||||
pr_info("Unknown key with scancode 0x%x pressed\n",
|
||||
reported_key);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -210,6 +237,22 @@ static void dell_wmi_notify(u32 value, void *context)
|
||||
|
||||
buffer_end = buffer_entry + buffer_size;
|
||||
|
||||
/*
|
||||
* 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 (dell_wmi_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];
|
||||
@@ -308,9 +351,23 @@ static const struct key_entry * __init dell_wmi_prepare_new_keymap(void)
|
||||
for (i = 0; i < hotkey_num; i++) {
|
||||
const struct dell_bios_keymap_entry *bios_entry =
|
||||
&dell_bios_hotkey_table->keymap[i];
|
||||
u16 keycode = bios_entry->keycode < 256 ?
|
||||
bios_to_linux_keycode[bios_entry->keycode] :
|
||||
KEY_RESERVED;
|
||||
|
||||
/* Uninitialized entries are 0 aka KEY_RESERVED. */
|
||||
u16 keycode = (bios_entry->keycode <
|
||||
ARRAY_SIZE(bios_to_linux_keycode)) ?
|
||||
bios_to_linux_keycode[bios_entry->keycode] :
|
||||
KEY_RESERVED;
|
||||
|
||||
/*
|
||||
* 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 (keycode == KEY_KBDILLUMTOGGLE)
|
||||
keymap[i].type = KE_IGNORE;
|
||||
@@ -386,16 +443,87 @@ static void __init find_hk_type(const struct dmi_header *dm, void *dummy)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Descriptor buffer is 128 byte long and contains:
|
||||
*
|
||||
* Name Offset Length Value
|
||||
* Vendor Signature 0 4 "DELL"
|
||||
* Object Signature 4 4 " WMI"
|
||||
* WMI Interface Version 8 4 <version>
|
||||
* WMI buffer length 12 4 4096
|
||||
*/
|
||||
static int __init dell_wmi_check_descriptor_buffer(void)
|
||||
{
|
||||
struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
u32 *buffer;
|
||||
|
||||
status = wmi_query_block(DELL_DESCRIPTOR_GUID, 0, &out);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_err("Cannot read Dell descriptor buffer - %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
obj = (union acpi_object *)out.pointer;
|
||||
if (!obj) {
|
||||
pr_err("Dell descriptor buffer is empty\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
pr_err("Cannot read Dell descriptor buffer\n");
|
||||
kfree(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (obj->buffer.length != 128) {
|
||||
pr_err("Dell descriptor buffer has invalid length (%d)\n",
|
||||
obj->buffer.length);
|
||||
if (obj->buffer.length < 16) {
|
||||
kfree(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
buffer = (u32 *)obj->buffer.pointer;
|
||||
|
||||
if (buffer[0] != 0x4C4C4544 && buffer[1] != 0x494D5720)
|
||||
pr_warn("Dell descriptor buffer has invalid signature (%*ph)\n",
|
||||
8, buffer);
|
||||
|
||||
if (buffer[2] != 0 && buffer[2] != 1)
|
||||
pr_warn("Dell descriptor buffer has unknown version (%d)\n",
|
||||
buffer[2]);
|
||||
|
||||
if (buffer[3] != 4096)
|
||||
pr_warn("Dell descriptor buffer has invalid buffer length (%d)\n",
|
||||
buffer[3]);
|
||||
|
||||
dell_wmi_interface_version = buffer[2];
|
||||
|
||||
pr_info("Detected Dell WMI interface version %u\n",
|
||||
dell_wmi_interface_version);
|
||||
|
||||
kfree(obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init dell_wmi_init(void)
|
||||
{
|
||||
int err;
|
||||
acpi_status status;
|
||||
|
||||
if (!wmi_has_guid(DELL_EVENT_GUID)) {
|
||||
pr_warn("No known WMI GUID found\n");
|
||||
if (!wmi_has_guid(DELL_EVENT_GUID) ||
|
||||
!wmi_has_guid(DELL_DESCRIPTOR_GUID)) {
|
||||
pr_warn("Dell WMI GUID were not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
err = dell_wmi_check_descriptor_buffer();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dmi_walk(find_hk_type, NULL);
|
||||
|
||||
err = dell_wmi_input_setup();
|
||||
|
Reference in New Issue
Block a user