aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRezwanul Kabir <Rezwanul_Kabir@dell.com>2009-11-02 12:00:42 -0500
committerLen Brown <len.brown@intel.com>2009-12-10 00:19:36 -0500
commit5ea2559726b786283236835dc2905c23b36ac91c (patch)
tree1958656b00fc42986a43ff6ac9184ee33c0201bd /drivers
parent22763c5cf3690a681551162c15d34d935308c8d7 (diff)
dell-wmi: Add support for new Dell systems
Newer Dell systems support HotKey features differently from legacy systems. A new vendor specifc HotKey SMBIOS table (Type 0xB2) is defined. This table contains a mapping between scancode and the corresponding predefined keyfunction ( i.e. keycode).. Also, a new ACPI-WMI event type (called KeyIDList) with a value of 0x0010 is defined. Any BIOS containing 0xB2 table will send hotkey notifications using KeyIDList event. This is Rezwanul's patch, updated to ensure that brightness events are not sent if the backlight is controlled via ACPI and with the default keycode for the display output switching altered to match desktop expectations. Signed-off-by: Rezwanul Kabir <Rezwanul_Kabir@dell.com> Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/platform/x86/dell-wmi.c129
1 files changed, 116 insertions, 13 deletions
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index 0f900cc9fa7a..67f3fe71c509 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -31,6 +31,7 @@
31#include <acpi/acpi_drivers.h> 31#include <acpi/acpi_drivers.h>
32#include <linux/acpi.h> 32#include <linux/acpi.h>
33#include <linux/string.h> 33#include <linux/string.h>
34#include <linux/dmi.h>
34 35
35MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); 36MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
36MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); 37MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
@@ -38,6 +39,8 @@ MODULE_LICENSE("GPL");
38 39
39#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" 40#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
40 41
42static int acpi_video;
43
41MODULE_ALIAS("wmi:"DELL_EVENT_GUID); 44MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
42 45
43struct key_entry { 46struct key_entry {
@@ -54,7 +57,7 @@ enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
54 * via the keyboard controller so should not be sent again. 57 * via the keyboard controller so should not be sent again.
55 */ 58 */
56 59
57static struct key_entry dell_wmi_keymap[] = { 60static struct key_entry dell_legacy_wmi_keymap[] = {
58 {KE_KEY, 0xe045, KEY_PROG1}, 61 {KE_KEY, 0xe045, KEY_PROG1},
59 {KE_KEY, 0xe009, KEY_EJECTCD}, 62 {KE_KEY, 0xe009, KEY_EJECTCD},
60 63
@@ -72,7 +75,7 @@ static struct key_entry dell_wmi_keymap[] = {
72 75
73 /* The next device is at offset 6, the active devices are at 76 /* The next device is at offset 6, the active devices are at
74 offset 8 and the attached devices at offset 10 */ 77 offset 8 and the attached devices at offset 10 */
75 {KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE}, 78 {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE},
76 79
77 {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, 80 {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
78 81
@@ -96,6 +99,47 @@ static struct key_entry dell_wmi_keymap[] = {
96 {KE_END, 0} 99 {KE_END, 0}
97}; 100};
98 101
102static bool dell_new_hk_type;
103
104struct dell_new_keymap_entry {
105 u16 scancode;
106 u16 keycode;
107};
108
109struct dell_hotkey_table {
110 struct dmi_header header;
111 struct dell_new_keymap_entry keymap[];
112
113};
114
115static struct key_entry *dell_new_wmi_keymap;
116
117static u16 bios_to_linux_keycode[256] = {
118
119 KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG,
120 KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
121 KEY_WWW, KEY_UNKNOWN, KEY_VOLUMEDOWN, KEY_MUTE,
122 KEY_VOLUMEUP, KEY_UNKNOWN, KEY_BATTERY, KEY_EJECTCD,
123 KEY_UNKNOWN, KEY_SLEEP, KEY_PROG1, KEY_BRIGHTNESSDOWN,
124 KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE,
125 KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN,
126 KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2,
127 KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
129 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
130 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
132 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
137 KEY_PROG3
138};
139
140
141static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
142
99static struct input_dev *dell_wmi_input_dev; 143static struct input_dev *dell_wmi_input_dev;
100 144
101static struct key_entry *dell_wmi_get_entry_by_scancode(int code) 145static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
@@ -164,24 +208,78 @@ static void dell_wmi_notify(u32 value, void *context)
164 obj = (union acpi_object *)response.pointer; 208 obj = (union acpi_object *)response.pointer;
165 209
166 if (obj && obj->type == ACPI_TYPE_BUFFER) { 210 if (obj && obj->type == ACPI_TYPE_BUFFER) {
167 int *buffer = (int *)obj->buffer.pointer; 211 int reported_key;
168 /* 212 u16 *buffer_entry = (u16 *)obj->buffer.pointer;
169 * The upper bytes of the event may contain 213 if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
170 * additional information, so mask them off for the 214 printk(KERN_INFO "dell-wmi: Received unknown WMI event"
171 * scancode lookup 215 " (0x%x)\n", buffer_entry[1]);
172 */ 216 return;
173 key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF); 217 }
174 if (key) { 218
219 if (dell_new_hk_type)
220 reported_key = (int)buffer_entry[2];
221 else
222 reported_key = (int)buffer_entry[1] & 0xffff;
223
224 key = dell_wmi_get_entry_by_scancode(reported_key);
225
226 if (!key) {
227 printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
228 reported_key);
229 } else if ((key->keycode == KEY_BRIGHTNESSUP ||
230 key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) {
231 /* Don't report brightness notifications that will also
232 * come via ACPI */
233 return;
234 } else {
175 input_report_key(dell_wmi_input_dev, key->keycode, 1); 235 input_report_key(dell_wmi_input_dev, key->keycode, 1);
176 input_sync(dell_wmi_input_dev); 236 input_sync(dell_wmi_input_dev);
177 input_report_key(dell_wmi_input_dev, key->keycode, 0); 237 input_report_key(dell_wmi_input_dev, key->keycode, 0);
178 input_sync(dell_wmi_input_dev); 238 input_sync(dell_wmi_input_dev);
179 } else if (buffer[1] & 0xFFFF) 239 }
180 printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
181 buffer[1] & 0xFFFF);
182 } 240 }
183} 241}
184 242
243
244static void setup_new_hk_map(const struct dmi_header *dm)
245{
246
247 int i;
248 int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry);
249 struct dell_hotkey_table *table =
250 container_of(dm, struct dell_hotkey_table, header);
251
252 dell_new_wmi_keymap = kzalloc((hotkey_num+1) *
253 sizeof(struct key_entry), GFP_KERNEL);
254
255 for (i = 0; i < hotkey_num; i++) {
256 dell_new_wmi_keymap[i].type = KE_KEY;
257 dell_new_wmi_keymap[i].code = table->keymap[i].scancode;
258 dell_new_wmi_keymap[i].keycode =
259 (table->keymap[i].keycode > 255) ? 0 :
260 bios_to_linux_keycode[table->keymap[i].keycode];
261 }
262
263 dell_new_wmi_keymap[i].type = KE_END;
264 dell_new_wmi_keymap[i].code = 0;
265 dell_new_wmi_keymap[i].keycode = 0;
266
267 dell_wmi_keymap = dell_new_wmi_keymap;
268
269}
270
271
272static void find_hk_type(const struct dmi_header *dm, void *dummy)
273{
274
275 if ((dm->type == 0xb2) && (dm->length > 6)) {
276 dell_new_hk_type = true;
277 setup_new_hk_map(dm);
278 }
279
280}
281
282
185static int __init dell_wmi_input_setup(void) 283static int __init dell_wmi_input_setup(void)
186{ 284{
187 struct key_entry *key; 285 struct key_entry *key;
@@ -226,6 +324,9 @@ static int __init dell_wmi_init(void)
226 int err; 324 int err;
227 325
228 if (wmi_has_guid(DELL_EVENT_GUID)) { 326 if (wmi_has_guid(DELL_EVENT_GUID)) {
327
328 dmi_walk(find_hk_type, NULL);
329
229 err = dell_wmi_input_setup(); 330 err = dell_wmi_input_setup();
230 331
231 if (err) 332 if (err)
@@ -240,6 +341,8 @@ static int __init dell_wmi_init(void)
240 return err; 341 return err;
241 } 342 }
242 343
344 acpi_video = acpi_video_backlight_support();
345
243 } else 346 } else
244 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); 347 printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
245 348