aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorColin King <colin.king@canonical.com>2010-11-19 10:40:02 -0500
committerMatthew Garrett <mjg@redhat.com>2011-01-07 17:03:41 -0500
commit58f6425eb92f54943878b0b3f9c1e51f99c2cb72 (patch)
treeaa4a5083adbf03561b9aee2d36129e0e7a5e2aa9 /drivers/platform
parent3098064d3b4a9bf9d2855b2a89599ad77695e324 (diff)
WMI: Cater for multiple events with same GUID
WMI data blocks can contain WMI events with the same GUID but with different notifiy_ids, for example volume up/down hotkeys. This patch enables a single event handler to be registered and unregistered against all events with same GUID but different notify_ids. Since an event handler is passed the notify_id of an event it can can differentiate between the different events. The patch also ensures we only register and unregister a device per unique GUID. Signed-off-by: Colin Ian King <colin.king@canonical.com> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/wmi.c133
1 files changed, 72 insertions, 61 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index aecd9a9b549f..b8e5383eab0c 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -549,21 +549,34 @@ acpi_status wmi_install_notify_handler(const char *guid,
549wmi_notify_handler handler, void *data) 549wmi_notify_handler handler, void *data)
550{ 550{
551 struct wmi_block *block; 551 struct wmi_block *block;
552 acpi_status status; 552 acpi_status status = AE_NOT_EXIST;
553 char tmp[16], guid_input[16];
554 struct list_head *p;
553 555
554 if (!guid || !handler) 556 if (!guid || !handler)
555 return AE_BAD_PARAMETER; 557 return AE_BAD_PARAMETER;
556 558
557 if (!find_guid(guid, &block)) 559 wmi_parse_guid(guid, tmp);
558 return AE_NOT_EXIST; 560 wmi_swap_bytes(tmp, guid_input);
559 561
560 if (block->handler && block->handler != wmi_notify_debug) 562 list_for_each(p, &wmi_block_list) {
561 return AE_ALREADY_ACQUIRED; 563 acpi_status wmi_status;
564 block = list_entry(p, struct wmi_block, list);
562 565
563 block->handler = handler; 566 if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
564 block->handler_data = data; 567 if (block->handler &&
568 block->handler != wmi_notify_debug)
569 return AE_ALREADY_ACQUIRED;
565 570
566 status = wmi_method_enable(block, 1); 571 block->handler = handler;
572 block->handler_data = data;
573
574 wmi_status = wmi_method_enable(block, 1);
575 if ((wmi_status != AE_OK) ||
576 ((wmi_status == AE_OK) && (status == AE_NOT_EXIST)))
577 status = wmi_status;
578 }
579 }
567 580
568 return status; 581 return status;
569} 582}
@@ -577,24 +590,40 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
577acpi_status wmi_remove_notify_handler(const char *guid) 590acpi_status wmi_remove_notify_handler(const char *guid)
578{ 591{
579 struct wmi_block *block; 592 struct wmi_block *block;
580 acpi_status status = AE_OK; 593 acpi_status status = AE_NOT_EXIST;
594 char tmp[16], guid_input[16];
595 struct list_head *p;
581 596
582 if (!guid) 597 if (!guid)
583 return AE_BAD_PARAMETER; 598 return AE_BAD_PARAMETER;
584 599
585 if (!find_guid(guid, &block)) 600 wmi_parse_guid(guid, tmp);
586 return AE_NOT_EXIST; 601 wmi_swap_bytes(tmp, guid_input);
587 602
588 if (!block->handler || block->handler == wmi_notify_debug) 603 list_for_each(p, &wmi_block_list) {
589 return AE_NULL_ENTRY; 604 acpi_status wmi_status;
605 block = list_entry(p, struct wmi_block, list);
590 606
591 if (debug_event) { 607 if (memcmp(block->gblock.guid, guid_input, 16) == 0) {
592 block->handler = wmi_notify_debug; 608 if (!block->handler ||
593 } else { 609 block->handler == wmi_notify_debug)
594 status = wmi_method_enable(block, 0); 610 return AE_NULL_ENTRY;
595 block->handler = NULL; 611
596 block->handler_data = NULL; 612 if (debug_event) {
613 block->handler = wmi_notify_debug;
614 status = AE_OK;
615 } else {
616 wmi_status = wmi_method_enable(block, 0);
617 block->handler = NULL;
618 block->handler_data = NULL;
619 if ((wmi_status != AE_OK) ||
620 ((wmi_status == AE_OK) &&
621 (status == AE_NOT_EXIST)))
622 status = wmi_status;
623 }
624 }
597 } 625 }
626
598 return status; 627 return status;
599} 628}
600EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); 629EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
@@ -705,22 +734,11 @@ static struct class wmi_class = {
705 .dev_attrs = wmi_dev_attrs, 734 .dev_attrs = wmi_dev_attrs,
706}; 735};
707 736
708static struct wmi_block *wmi_create_device(const struct guid_block *gblock, 737static int wmi_create_device(const struct guid_block *gblock,
709 acpi_handle handle) 738 struct wmi_block *wblock, acpi_handle handle)
710{ 739{
711 struct wmi_block *wblock;
712 int error;
713 char guid_string[37]; 740 char guid_string[37];
714 741
715 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
716 if (!wblock) {
717 error = -ENOMEM;
718 goto err_out;
719 }
720
721 wblock->handle = handle;
722 wblock->gblock = *gblock;
723
724 wblock->dev.class = &wmi_class; 742 wblock->dev.class = &wmi_class;
725 743
726 wmi_gtoa(gblock->guid, guid_string); 744 wmi_gtoa(gblock->guid, guid_string);
@@ -728,17 +746,7 @@ static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
728 746
729 dev_set_drvdata(&wblock->dev, wblock); 747 dev_set_drvdata(&wblock->dev, wblock);
730 748
731 error = device_register(&wblock->dev); 749 return device_register(&wblock->dev);
732 if (error)
733 goto err_free;
734
735 list_add_tail(&wblock->list, &wmi_block_list);
736 return wblock;
737
738err_free:
739 kfree(wblock);
740err_out:
741 return ERR_PTR(error);
742} 750}
743 751
744static void wmi_free_devices(void) 752static void wmi_free_devices(void)
@@ -747,7 +755,8 @@ static void wmi_free_devices(void)
747 755
748 /* Delete devices for all the GUIDs */ 756 /* Delete devices for all the GUIDs */
749 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) 757 list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
750 device_unregister(&wblock->dev); 758 if (wblock->dev.class)
759 device_unregister(&wblock->dev);
751} 760}
752 761
753static bool guid_already_parsed(const char *guid_string) 762static bool guid_already_parsed(const char *guid_string)
@@ -770,7 +779,6 @@ static acpi_status parse_wdg(acpi_handle handle)
770 union acpi_object *obj; 779 union acpi_object *obj;
771 const struct guid_block *gblock; 780 const struct guid_block *gblock;
772 struct wmi_block *wblock; 781 struct wmi_block *wblock;
773 char guid_string[37];
774 acpi_status status; 782 acpi_status status;
775 int retval; 783 int retval;
776 u32 i, total; 784 u32 i, total;
@@ -792,28 +800,31 @@ static acpi_status parse_wdg(acpi_handle handle)
792 total = obj->buffer.length / sizeof(struct guid_block); 800 total = obj->buffer.length / sizeof(struct guid_block);
793 801
794 for (i = 0; i < total; i++) { 802 for (i = 0; i < total; i++) {
803 if (debug_dump_wdg)
804 wmi_dump_wdg(&gblock[i]);
805
806 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
807 if (!wblock)
808 return AE_NO_MEMORY;
809
810 wblock->handle = handle;
811 wblock->gblock = gblock[i];
812
795 /* 813 /*
796 Some WMI devices, like those for nVidia hooks, have a 814 Some WMI devices, like those for nVidia hooks, have a
797 duplicate GUID. It's not clear what we should do in this 815 duplicate GUID. It's not clear what we should do in this
798 case yet, so for now, we'll just ignore the duplicate. 816 case yet, so for now, we'll just ignore the duplicate
799 Anyone who wants to add support for that device can come 817 for device creation.
800 up with a better workaround for the mess then.
801 */ 818 */
802 if (guid_already_parsed(gblock[i].guid) == true) { 819 if (!guid_already_parsed(gblock[i].guid)) {
803 wmi_gtoa(gblock[i].guid, guid_string); 820 retval = wmi_create_device(&gblock[i], wblock, handle);
804 pr_info("Skipping duplicate GUID %s\n", guid_string); 821 if (retval) {
805 continue; 822 wmi_free_devices();
823 break;
824 }
806 } 825 }
807 826
808 if (debug_dump_wdg) 827 list_add_tail(&wblock->list, &wmi_block_list);
809 wmi_dump_wdg(&gblock[i]);
810
811 wblock = wmi_create_device(&gblock[i], handle);
812 if (IS_ERR(wblock)) {
813 retval = PTR_ERR(wblock);
814 wmi_free_devices();
815 break;
816 }
817 828
818 if (debug_event) { 829 if (debug_event) {
819 wblock->handler = wmi_notify_debug; 830 wblock->handler = wmi_notify_debug;