aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/hp-wmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/hp-wmi.c')
-rw-r--r--drivers/platform/x86/hp-wmi.c172
1 files changed, 51 insertions, 121 deletions
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index c1741142a4cb..1dac659b5e0c 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -29,6 +29,7 @@
29#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/types.h> 30#include <linux/types.h>
31#include <linux/input.h> 31#include <linux/input.h>
32#include <linux/input/sparse-keymap.h>
32#include <linux/platform_device.h> 33#include <linux/platform_device.h>
33#include <linux/acpi.h> 34#include <linux/acpi.h>
34#include <linux/rfkill.h> 35#include <linux/rfkill.h>
@@ -88,24 +89,16 @@ struct bios_return {
88 u32 value; 89 u32 value;
89}; 90};
90 91
91struct key_entry { 92static const struct key_entry hp_wmi_keymap[] = {
92 char type; /* See KE_* below */ 93 { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
93 u16 code; 94 { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
94 u16 keycode; 95 { KE_KEY, 0x20e6, { KEY_PROG1 } },
95}; 96 { KE_KEY, 0x20e8, { KEY_MEDIA } },
96 97 { KE_KEY, 0x2142, { KEY_MEDIA } },
97enum { KE_KEY, KE_END }; 98 { KE_KEY, 0x213b, { KEY_INFO } },
98 99 { KE_KEY, 0x2169, { KEY_DIRECTION } },
99static struct key_entry hp_wmi_keymap[] = { 100 { KE_KEY, 0x231b, { KEY_HELP } },
100 {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, 101 { KE_END, 0 }
101 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN},
102 {KE_KEY, 0x20e6, KEY_PROG1},
103 {KE_KEY, 0x20e8, KEY_MEDIA},
104 {KE_KEY, 0x2142, KEY_MEDIA},
105 {KE_KEY, 0x213b, KEY_INFO},
106 {KE_KEY, 0x2169, KEY_DIRECTION},
107 {KE_KEY, 0x231b, KEY_HELP},
108 {KE_END, 0}
109}; 102};
110 103
111static struct input_dev *hp_wmi_input_dev; 104static struct input_dev *hp_wmi_input_dev;
@@ -347,64 +340,9 @@ static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
347static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL); 340static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
348static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL); 341static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
349 342
350static struct key_entry *hp_wmi_get_entry_by_scancode(unsigned int code)
351{
352 struct key_entry *key;
353
354 for (key = hp_wmi_keymap; key->type != KE_END; key++)
355 if (code == key->code)
356 return key;
357
358 return NULL;
359}
360
361static struct key_entry *hp_wmi_get_entry_by_keycode(unsigned int keycode)
362{
363 struct key_entry *key;
364
365 for (key = hp_wmi_keymap; key->type != KE_END; key++)
366 if (key->type == KE_KEY && keycode == key->keycode)
367 return key;
368
369 return NULL;
370}
371
372static int hp_wmi_getkeycode(struct input_dev *dev,
373 unsigned int scancode, unsigned int *keycode)
374{
375 struct key_entry *key = hp_wmi_get_entry_by_scancode(scancode);
376
377 if (key && key->type == KE_KEY) {
378 *keycode = key->keycode;
379 return 0;
380 }
381
382 return -EINVAL;
383}
384
385static int hp_wmi_setkeycode(struct input_dev *dev,
386 unsigned int scancode, unsigned int keycode)
387{
388 struct key_entry *key;
389 unsigned int old_keycode;
390
391 key = hp_wmi_get_entry_by_scancode(scancode);
392 if (key && key->type == KE_KEY) {
393 old_keycode = key->keycode;
394 key->keycode = keycode;
395 set_bit(keycode, dev->keybit);
396 if (!hp_wmi_get_entry_by_keycode(old_keycode))
397 clear_bit(old_keycode, dev->keybit);
398 return 0;
399 }
400
401 return -EINVAL;
402}
403
404static void hp_wmi_notify(u32 value, void *context) 343static void hp_wmi_notify(u32 value, void *context)
405{ 344{
406 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 345 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
407 static struct key_entry *key;
408 union acpi_object *obj; 346 union acpi_object *obj;
409 u32 event_id, event_data; 347 u32 event_id, event_data;
410 int key_code = 0, ret; 348 int key_code = 0, ret;
@@ -465,19 +403,9 @@ static void hp_wmi_notify(u32 value, void *context)
465 sizeof(key_code)); 403 sizeof(key_code));
466 if (ret) 404 if (ret)
467 break; 405 break;
468 key = hp_wmi_get_entry_by_scancode(key_code); 406
469 if (key) { 407 if (!sparse_keymap_report_event(hp_wmi_input_dev,
470 switch (key->type) { 408 key_code, 1, true))
471 case KE_KEY:
472 input_report_key(hp_wmi_input_dev,
473 key->keycode, 1);
474 input_sync(hp_wmi_input_dev);
475 input_report_key(hp_wmi_input_dev,
476 key->keycode, 0);
477 input_sync(hp_wmi_input_dev);
478 break;
479 }
480 } else
481 printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n", 409 printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
482 key_code); 410 key_code);
483 break; 411 break;
@@ -510,7 +438,7 @@ static void hp_wmi_notify(u32 value, void *context)
510 438
511static int __init hp_wmi_input_setup(void) 439static int __init hp_wmi_input_setup(void)
512{ 440{
513 struct key_entry *key; 441 acpi_status status;
514 int err; 442 int err;
515 443
516 hp_wmi_input_dev = input_allocate_device(); 444 hp_wmi_input_dev = input_allocate_device();
@@ -520,21 +448,14 @@ static int __init hp_wmi_input_setup(void)
520 hp_wmi_input_dev->name = "HP WMI hotkeys"; 448 hp_wmi_input_dev->name = "HP WMI hotkeys";
521 hp_wmi_input_dev->phys = "wmi/input0"; 449 hp_wmi_input_dev->phys = "wmi/input0";
522 hp_wmi_input_dev->id.bustype = BUS_HOST; 450 hp_wmi_input_dev->id.bustype = BUS_HOST;
523 hp_wmi_input_dev->getkeycode = hp_wmi_getkeycode;
524 hp_wmi_input_dev->setkeycode = hp_wmi_setkeycode;
525
526 for (key = hp_wmi_keymap; key->type != KE_END; key++) {
527 switch (key->type) {
528 case KE_KEY:
529 set_bit(EV_KEY, hp_wmi_input_dev->evbit);
530 set_bit(key->keycode, hp_wmi_input_dev->keybit);
531 break;
532 }
533 }
534 451
535 set_bit(EV_SW, hp_wmi_input_dev->evbit); 452 __set_bit(EV_SW, hp_wmi_input_dev->evbit);
536 set_bit(SW_DOCK, hp_wmi_input_dev->swbit); 453 __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
537 set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); 454 __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
455
456 err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
457 if (err)
458 goto err_free_dev;
538 459
539 /* Set initial hardware state */ 460 /* Set initial hardware state */
540 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state()); 461 input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
@@ -542,14 +463,32 @@ static int __init hp_wmi_input_setup(void)
542 hp_wmi_tablet_state()); 463 hp_wmi_tablet_state());
543 input_sync(hp_wmi_input_dev); 464 input_sync(hp_wmi_input_dev);
544 465
545 err = input_register_device(hp_wmi_input_dev); 466 status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
546 467 if (ACPI_FAILURE(status)) {
547 if (err) { 468 err = -EIO;
548 input_free_device(hp_wmi_input_dev); 469 goto err_free_keymap;
549 return err;
550 } 470 }
551 471
472 err = input_register_device(hp_wmi_input_dev);
473 if (err)
474 goto err_uninstall_notifier;
475
552 return 0; 476 return 0;
477
478 err_uninstall_notifier:
479 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
480 err_free_keymap:
481 sparse_keymap_free(hp_wmi_input_dev);
482 err_free_dev:
483 input_free_device(hp_wmi_input_dev);
484 return err;
485}
486
487static void hp_wmi_input_destroy(void)
488{
489 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
490 sparse_keymap_free(hp_wmi_input_dev);
491 input_unregister_device(hp_wmi_input_dev);
553} 492}
554 493
555static void cleanup_sysfs(struct platform_device *device) 494static void cleanup_sysfs(struct platform_device *device)
@@ -704,15 +643,9 @@ static int __init hp_wmi_init(void)
704 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); 643 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
705 644
706 if (event_capable) { 645 if (event_capable) {
707 err = wmi_install_notify_handler(HPWMI_EVENT_GUID,
708 hp_wmi_notify, NULL);
709 if (ACPI_FAILURE(err))
710 return -EINVAL;
711 err = hp_wmi_input_setup(); 646 err = hp_wmi_input_setup();
712 if (err) { 647 if (err)
713 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
714 return err; 648 return err;
715 }
716 } 649 }
717 650
718 if (bios_capable) { 651 if (bios_capable) {
@@ -739,20 +672,17 @@ err_device_add:
739err_device_alloc: 672err_device_alloc:
740 platform_driver_unregister(&hp_wmi_driver); 673 platform_driver_unregister(&hp_wmi_driver);
741err_driver_reg: 674err_driver_reg:
742 if (wmi_has_guid(HPWMI_EVENT_GUID)) { 675 if (event_capable)
743 input_unregister_device(hp_wmi_input_dev); 676 hp_wmi_input_destroy();
744 wmi_remove_notify_handler(HPWMI_EVENT_GUID);
745 }
746 677
747 return err; 678 return err;
748} 679}
749 680
750static void __exit hp_wmi_exit(void) 681static void __exit hp_wmi_exit(void)
751{ 682{
752 if (wmi_has_guid(HPWMI_EVENT_GUID)) { 683 if (wmi_has_guid(HPWMI_EVENT_GUID))
753 wmi_remove_notify_handler(HPWMI_EVENT_GUID); 684 hp_wmi_input_destroy();
754 input_unregister_device(hp_wmi_input_dev); 685
755 }
756 if (hp_wmi_platform_dev) { 686 if (hp_wmi_platform_dev) {
757 platform_device_unregister(hp_wmi_platform_dev); 687 platform_device_unregister(hp_wmi_platform_dev);
758 platform_driver_unregister(&hp_wmi_driver); 688 platform_driver_unregister(&hp_wmi_driver);