aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/hp-wmi.c
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2009-06-01 10:25:45 -0400
committerLen Brown <len.brown@intel.com>2009-06-17 23:46:31 -0400
commit871043bc463e7d191e7b5b00436a8852921dd833 (patch)
tree2e386de106434ec6fe3728077a56824b64f1a440 /drivers/platform/x86/hp-wmi.c
parentdb18b040af6571a7eeed9e1adc2e92c9c87e4b1a (diff)
hp-wmi: Add support for reporting tablet state
HP tablets send a WMI event when a tablet state change occurs, but use the same method as is used for reporting docking and undocking. The same query is used to obtain the state of the hardware. Bit 0 indicates the docking state, while bit 2 indicates the tablet state. This patch breaks these out and sends separate input events for tablet and dock state changes. An additional sysfs file is added to report the tablet state. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform/x86/hp-wmi.c')
-rw-r--r--drivers/platform/x86/hp-wmi.c87
1 files changed, 55 insertions, 32 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index 50d9019de2be..46a7a6e8ed91 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -47,7 +47,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
47#define HPWMI_DISPLAY_QUERY 0x1 47#define HPWMI_DISPLAY_QUERY 0x1
48#define HPWMI_HDDTEMP_QUERY 0x2 48#define HPWMI_HDDTEMP_QUERY 0x2
49#define HPWMI_ALS_QUERY 0x3 49#define HPWMI_ALS_QUERY 0x3
50#define HPWMI_DOCK_QUERY 0x4 50#define HPWMI_HARDWARE_QUERY 0x4
51#define HPWMI_WIRELESS_QUERY 0x5 51#define HPWMI_WIRELESS_QUERY 0x5
52#define HPWMI_HOTKEY_QUERY 0xc 52#define HPWMI_HOTKEY_QUERY 0xc
53 53
@@ -75,10 +75,9 @@ struct key_entry {
75 u16 keycode; 75 u16 keycode;
76}; 76};
77 77
78enum { KE_KEY, KE_SW, KE_END }; 78enum { KE_KEY, KE_END };
79 79
80static struct key_entry hp_wmi_keymap[] = { 80static struct key_entry hp_wmi_keymap[] = {
81 {KE_SW, 0x01, SW_DOCK},
82 {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, 81 {KE_KEY, 0x02, KEY_BRIGHTNESSUP},
83 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, 82 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
84 {KE_KEY, 0x20e6, KEY_PROG1}, 83 {KE_KEY, 0x20e6, KEY_PROG1},
@@ -151,7 +150,22 @@ static int hp_wmi_als_state(void)
151 150
152static int hp_wmi_dock_state(void) 151static int hp_wmi_dock_state(void)
153{ 152{
154 return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0); 153 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
154
155 if (ret < 0)
156 return ret;
157
158 return ret & 0x1;
159}
160
161static int hp_wmi_tablet_state(void)
162{
163 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0);
164
165 if (ret < 0)
166 return ret;
167
168 return (ret & 0x4) ? 1 : 0;
155} 169}
156 170
157static int hp_wmi_wifi_set(void *data, enum rfkill_state state) 171static int hp_wmi_wifi_set(void *data, enum rfkill_state state)
@@ -244,6 +258,15 @@ static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
244 return sprintf(buf, "%d\n", value); 258 return sprintf(buf, "%d\n", value);
245} 259}
246 260
261static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
262 char *buf)
263{
264 int value = hp_wmi_tablet_state();
265 if (value < 0)
266 return -EINVAL;
267 return sprintf(buf, "%d\n", value);
268}
269
247static ssize_t set_als(struct device *dev, struct device_attribute *attr, 270static ssize_t set_als(struct device *dev, struct device_attribute *attr,
248 const char *buf, size_t count) 271 const char *buf, size_t count)
249{ 272{
@@ -256,6 +279,7 @@ static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
256static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL); 279static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
257static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als); 280static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
258static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); 281static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
282static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
259 283
260static struct key_entry *hp_wmi_get_entry_by_scancode(int code) 284static struct key_entry *hp_wmi_get_entry_by_scancode(int code)
261{ 285{
@@ -338,13 +362,13 @@ static void hp_wmi_notify(u32 value, void *context)
338 key->keycode, 0); 362 key->keycode, 0);
339 input_sync(hp_wmi_input_dev); 363 input_sync(hp_wmi_input_dev);
340 break; 364 break;
341 case KE_SW:
342 input_report_switch(hp_wmi_input_dev,
343 key->keycode,
344 hp_wmi_dock_state());
345 input_sync(hp_wmi_input_dev);
346 break;
347 } 365 }
366 } else if (eventcode == 0x1) {
367 input_report_switch(hp_wmi_input_dev, SW_DOCK,
368 hp_wmi_dock_state());
369 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
370 hp_wmi_tablet_state());
371 input_sync(hp_wmi_input_dev);
348 } else if (eventcode == 0x5) { 372 } else if (eventcode == 0x5) {
349 if (wifi_rfkill) 373 if (wifi_rfkill)
350 rfkill_force_state(wifi_rfkill, 374 rfkill_force_state(wifi_rfkill,
@@ -381,18 +405,19 @@ static int __init hp_wmi_input_setup(void)
381 set_bit(EV_KEY, hp_wmi_input_dev->evbit); 405 set_bit(EV_KEY, hp_wmi_input_dev->evbit);
382 set_bit(key->keycode, hp_wmi_input_dev->keybit); 406 set_bit(key->keycode, hp_wmi_input_dev->keybit);
383 break; 407 break;
384 case KE_SW:
385 set_bit(EV_SW, hp_wmi_input_dev->evbit);
386 set_bit(key->keycode, hp_wmi_input_dev->swbit);
387
388 /* Set initial dock state */
389 input_report_switch(hp_wmi_input_dev, key->keycode,
390 hp_wmi_dock_state());
391 input_sync(hp_wmi_input_dev);
392 break;
393 } 408 }
394 } 409 }
395 410
411 set_bit(EV_SW, hp_wmi_input_dev->evbit);
412 set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
413 set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
414
415 /* Set initial hardware state */
416 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
417 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
418 hp_wmi_tablet_state());
419 input_sync(hp_wmi_input_dev);
420
396 err = input_register_device(hp_wmi_input_dev); 421 err = input_register_device(hp_wmi_input_dev);
397 422
398 if (err) { 423 if (err) {
@@ -409,6 +434,7 @@ static void cleanup_sysfs(struct platform_device *device)
409 device_remove_file(&device->dev, &dev_attr_hddtemp); 434 device_remove_file(&device->dev, &dev_attr_hddtemp);
410 device_remove_file(&device->dev, &dev_attr_als); 435 device_remove_file(&device->dev, &dev_attr_als);
411 device_remove_file(&device->dev, &dev_attr_dock); 436 device_remove_file(&device->dev, &dev_attr_dock);
437 device_remove_file(&device->dev, &dev_attr_tablet);
412} 438}
413 439
414static int __init hp_wmi_bios_setup(struct platform_device *device) 440static int __init hp_wmi_bios_setup(struct platform_device *device)
@@ -428,6 +454,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
428 err = device_create_file(&device->dev, &dev_attr_dock); 454 err = device_create_file(&device->dev, &dev_attr_dock);
429 if (err) 455 if (err)
430 goto add_sysfs_error; 456 goto add_sysfs_error;
457 err = device_create_file(&device->dev, &dev_attr_tablet);
458 if (err)
459 goto add_sysfs_error;
431 460
432 if (wireless & 0x1) { 461 if (wireless & 0x1) {
433 wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN); 462 wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
@@ -491,23 +520,17 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
491 520
492static int hp_wmi_resume_handler(struct platform_device *device) 521static int hp_wmi_resume_handler(struct platform_device *device)
493{ 522{
494 struct key_entry *key;
495
496 /* 523 /*
497 * Docking state may have changed while suspended, so trigger 524 * Hardware state may have changed while suspended, so trigger
498 * an input event for the current state. As this is a switch, 525 * input events for the current state. As this is a switch,
499 * the input layer will only actually pass it on if the state 526 * the input layer will only actually pass it on if the state
500 * changed. 527 * changed.
501 */ 528 */
502 for (key = hp_wmi_keymap; key->type != KE_END; key++) { 529
503 switch (key->type) { 530 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
504 case KE_SW: 531 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
505 input_report_switch(hp_wmi_input_dev, key->keycode, 532 hp_wmi_tablet_state());
506 hp_wmi_dock_state()); 533 input_sync(hp_wmi_input_dev);
507 input_sync(hp_wmi_input_dev);
508 break;
509 }
510 }
511 534
512 return 0; 535 return 0;
513} 536}