mirror of https://gitee.com/openkylin/linux.git
Merge branch 'dell-wmi' into release
This commit is contained in:
commit
689a8ab32f
|
@ -31,6 +31,7 @@
|
|||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
|
||||
MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
|
||||
|
@ -38,6 +39,8 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
|
||||
|
||||
static int acpi_video;
|
||||
|
||||
MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
|
||||
|
||||
struct key_entry {
|
||||
|
@ -54,7 +57,7 @@ enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
|
|||
* via the keyboard controller so should not be sent again.
|
||||
*/
|
||||
|
||||
static struct key_entry dell_wmi_keymap[] = {
|
||||
static struct key_entry dell_legacy_wmi_keymap[] = {
|
||||
{KE_KEY, 0xe045, KEY_PROG1},
|
||||
{KE_KEY, 0xe009, KEY_EJECTCD},
|
||||
|
||||
|
@ -72,7 +75,7 @@ static struct key_entry dell_wmi_keymap[] = {
|
|||
|
||||
/* The next device is at offset 6, the active devices are at
|
||||
offset 8 and the attached devices at offset 10 */
|
||||
{KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE},
|
||||
{KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE},
|
||||
|
||||
{KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
|
||||
|
||||
|
@ -96,6 +99,47 @@ static struct key_entry dell_wmi_keymap[] = {
|
|||
{KE_END, 0}
|
||||
};
|
||||
|
||||
static bool dell_new_hk_type;
|
||||
|
||||
struct dell_new_keymap_entry {
|
||||
u16 scancode;
|
||||
u16 keycode;
|
||||
};
|
||||
|
||||
struct dell_hotkey_table {
|
||||
struct dmi_header header;
|
||||
struct dell_new_keymap_entry keymap[];
|
||||
|
||||
};
|
||||
|
||||
static struct key_entry *dell_new_wmi_keymap;
|
||||
|
||||
static u16 bios_to_linux_keycode[256] = {
|
||||
|
||||
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
|
||||
|
||||
static struct input_dev *dell_wmi_input_dev;
|
||||
|
||||
static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
|
||||
|
@ -164,24 +208,78 @@ static void dell_wmi_notify(u32 value, void *context)
|
|||
obj = (union acpi_object *)response.pointer;
|
||||
|
||||
if (obj && obj->type == ACPI_TYPE_BUFFER) {
|
||||
int *buffer = (int *)obj->buffer.pointer;
|
||||
/*
|
||||
* The upper bytes of the event may contain
|
||||
* additional information, so mask them off for the
|
||||
* scancode lookup
|
||||
*/
|
||||
key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF);
|
||||
if (key) {
|
||||
int reported_key;
|
||||
u16 *buffer_entry = (u16 *)obj->buffer.pointer;
|
||||
if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
|
||||
printk(KERN_INFO "dell-wmi: Received unknown WMI event"
|
||||
" (0x%x)\n", buffer_entry[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dell_new_hk_type)
|
||||
reported_key = (int)buffer_entry[2];
|
||||
else
|
||||
reported_key = (int)buffer_entry[1] & 0xffff;
|
||||
|
||||
key = dell_wmi_get_entry_by_scancode(reported_key);
|
||||
|
||||
if (!key) {
|
||||
printk(KERN_INFO "dell-wmi: 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 */
|
||||
return;
|
||||
} else {
|
||||
input_report_key(dell_wmi_input_dev, key->keycode, 1);
|
||||
input_sync(dell_wmi_input_dev);
|
||||
input_report_key(dell_wmi_input_dev, key->keycode, 0);
|
||||
input_sync(dell_wmi_input_dev);
|
||||
} else if (buffer[1] & 0xFFFF)
|
||||
printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
|
||||
buffer[1] & 0xFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void setup_new_hk_map(const struct dmi_header *dm)
|
||||
{
|
||||
|
||||
int i;
|
||||
int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry);
|
||||
struct dell_hotkey_table *table =
|
||||
container_of(dm, struct dell_hotkey_table, header);
|
||||
|
||||
dell_new_wmi_keymap = kzalloc((hotkey_num+1) *
|
||||
sizeof(struct key_entry), GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < hotkey_num; i++) {
|
||||
dell_new_wmi_keymap[i].type = KE_KEY;
|
||||
dell_new_wmi_keymap[i].code = table->keymap[i].scancode;
|
||||
dell_new_wmi_keymap[i].keycode =
|
||||
(table->keymap[i].keycode > 255) ? 0 :
|
||||
bios_to_linux_keycode[table->keymap[i].keycode];
|
||||
}
|
||||
|
||||
dell_new_wmi_keymap[i].type = KE_END;
|
||||
dell_new_wmi_keymap[i].code = 0;
|
||||
dell_new_wmi_keymap[i].keycode = 0;
|
||||
|
||||
dell_wmi_keymap = dell_new_wmi_keymap;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void find_hk_type(const struct dmi_header *dm, void *dummy)
|
||||
{
|
||||
|
||||
if ((dm->type == 0xb2) && (dm->length > 6)) {
|
||||
dell_new_hk_type = true;
|
||||
setup_new_hk_map(dm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int __init dell_wmi_input_setup(void)
|
||||
{
|
||||
struct key_entry *key;
|
||||
|
@ -226,6 +324,9 @@ static int __init dell_wmi_init(void)
|
|||
int err;
|
||||
|
||||
if (wmi_has_guid(DELL_EVENT_GUID)) {
|
||||
|
||||
dmi_walk(find_hk_type, NULL);
|
||||
|
||||
err = dell_wmi_input_setup();
|
||||
|
||||
if (err)
|
||||
|
@ -240,6 +341,8 @@ static int __init dell_wmi_init(void)
|
|||
return err;
|
||||
}
|
||||
|
||||
acpi_video = acpi_video_backlight_support();
|
||||
|
||||
} else
|
||||
printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
|
||||
|
||||
|
|
Loading…
Reference in New Issue