Merge branch 'dell-wmi' into release

This commit is contained in:
Len Brown 2009-12-16 02:20:43 -05:00
commit 689a8ab32f

View file

@ -31,6 +31,7 @@
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/dmi.h>
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
@ -38,6 +39,8 @@ MODULE_LICENSE("GPL");
#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
static int acpi_video;
MODULE_ALIAS("wmi:"DELL_EVENT_GUID); MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
struct key_entry { 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. * 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, 0xe045, KEY_PROG1},
{KE_KEY, 0xe009, KEY_EJECTCD}, {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 /* The next device is at offset 6, the active devices are at
offset 8 and the attached devices at offset 10 */ offset 8 and the attached devices at offset 10 */
{KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE}, {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE},
{KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
@ -96,6 +99,47 @@ static struct key_entry dell_wmi_keymap[] = {
{KE_END, 0} {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 input_dev *dell_wmi_input_dev;
static struct key_entry *dell_wmi_get_entry_by_scancode(int code) 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; obj = (union acpi_object *)response.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER) { if (obj && obj->type == ACPI_TYPE_BUFFER) {
int *buffer = (int *)obj->buffer.pointer; int reported_key;
/* u16 *buffer_entry = (u16 *)obj->buffer.pointer;
* The upper bytes of the event may contain if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
* additional information, so mask them off for the printk(KERN_INFO "dell-wmi: Received unknown WMI event"
* scancode lookup " (0x%x)\n", buffer_entry[1]);
*/ return;
key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF); }
if (key) {
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_report_key(dell_wmi_input_dev, key->keycode, 1);
input_sync(dell_wmi_input_dev); input_sync(dell_wmi_input_dev);
input_report_key(dell_wmi_input_dev, key->keycode, 0); input_report_key(dell_wmi_input_dev, key->keycode, 0);
input_sync(dell_wmi_input_dev); 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) static int __init dell_wmi_input_setup(void)
{ {
struct key_entry *key; struct key_entry *key;
@ -226,6 +324,9 @@ static int __init dell_wmi_init(void)
int err; int err;
if (wmi_has_guid(DELL_EVENT_GUID)) { if (wmi_has_guid(DELL_EVENT_GUID)) {
dmi_walk(find_hk_type, NULL);
err = dell_wmi_input_setup(); err = dell_wmi_input_setup();
if (err) if (err)
@ -240,6 +341,8 @@ static int __init dell_wmi_init(void)
return err; return err;
} }
acpi_video = acpi_video_backlight_support();
} else } else
printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");