diff options
Diffstat (limited to 'drivers/platform/x86/wmi.c')
-rw-r--r-- | drivers/platform/x86/wmi.c | 385 |
1 files changed, 168 insertions, 217 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index b2978a04317f..f23d5a84e7b1 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c | |||
@@ -27,6 +27,8 @@ | |||
27 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 27 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
31 | |||
30 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
31 | #include <linux/init.h> | 33 | #include <linux/init.h> |
32 | #include <linux/types.h> | 34 | #include <linux/types.h> |
@@ -44,9 +46,8 @@ MODULE_LICENSE("GPL"); | |||
44 | 46 | ||
45 | #define ACPI_WMI_CLASS "wmi" | 47 | #define ACPI_WMI_CLASS "wmi" |
46 | 48 | ||
47 | #define PREFIX "ACPI: WMI: " | ||
48 | |||
49 | static DEFINE_MUTEX(wmi_data_lock); | 49 | static DEFINE_MUTEX(wmi_data_lock); |
50 | static LIST_HEAD(wmi_block_list); | ||
50 | 51 | ||
51 | struct guid_block { | 52 | struct guid_block { |
52 | char guid[16]; | 53 | char guid[16]; |
@@ -67,10 +68,9 @@ struct wmi_block { | |||
67 | acpi_handle handle; | 68 | acpi_handle handle; |
68 | wmi_notify_handler handler; | 69 | wmi_notify_handler handler; |
69 | void *handler_data; | 70 | void *handler_data; |
70 | struct device *dev; | 71 | struct device dev; |
71 | }; | 72 | }; |
72 | 73 | ||
73 | static struct wmi_block wmi_blocks; | ||
74 | 74 | ||
75 | /* | 75 | /* |
76 | * If the GUID data block is marked as expensive, we must enable and | 76 | * If the GUID data block is marked as expensive, we must enable and |
@@ -110,7 +110,7 @@ static struct acpi_driver acpi_wmi_driver = { | |||
110 | .add = acpi_wmi_add, | 110 | .add = acpi_wmi_add, |
111 | .remove = acpi_wmi_remove, | 111 | .remove = acpi_wmi_remove, |
112 | .notify = acpi_wmi_notify, | 112 | .notify = acpi_wmi_notify, |
113 | }, | 113 | }, |
114 | }; | 114 | }; |
115 | 115 | ||
116 | /* | 116 | /* |
@@ -128,30 +128,18 @@ static struct acpi_driver acpi_wmi_driver = { | |||
128 | */ | 128 | */ |
129 | static int wmi_parse_hexbyte(const u8 *src) | 129 | static int wmi_parse_hexbyte(const u8 *src) |
130 | { | 130 | { |
131 | unsigned int x; /* For correct wrapping */ | ||
132 | int h; | 131 | int h; |
132 | int value; | ||
133 | 133 | ||
134 | /* high part */ | 134 | /* high part */ |
135 | x = src[0]; | 135 | h = value = hex_to_bin(src[0]); |
136 | if (x - '0' <= '9' - '0') { | 136 | if (value < 0) |
137 | h = x - '0'; | ||
138 | } else if (x - 'a' <= 'f' - 'a') { | ||
139 | h = x - 'a' + 10; | ||
140 | } else if (x - 'A' <= 'F' - 'A') { | ||
141 | h = x - 'A' + 10; | ||
142 | } else { | ||
143 | return -1; | 137 | return -1; |
144 | } | ||
145 | h <<= 4; | ||
146 | 138 | ||
147 | /* low part */ | 139 | /* low part */ |
148 | x = src[1]; | 140 | value = hex_to_bin(src[1]); |
149 | if (x - '0' <= '9' - '0') | 141 | if (value >= 0) |
150 | return h | (x - '0'); | 142 | return (h << 4) | value; |
151 | if (x - 'a' <= 'f' - 'a') | ||
152 | return h | (x - 'a' + 10); | ||
153 | if (x - 'A' <= 'F' - 'A') | ||
154 | return h | (x - 'A' + 10); | ||
155 | return -1; | 143 | return -1; |
156 | } | 144 | } |
157 | 145 | ||
@@ -232,7 +220,7 @@ static int wmi_gtoa(const char *in, char *out) | |||
232 | for (i = 10; i <= 15; i++) | 220 | for (i = 10; i <= 15; i++) |
233 | out += sprintf(out, "%02X", in[i] & 0xFF); | 221 | out += sprintf(out, "%02X", in[i] & 0xFF); |
234 | 222 | ||
235 | out = '\0'; | 223 | *out = '\0'; |
236 | return 0; | 224 | return 0; |
237 | } | 225 | } |
238 | 226 | ||
@@ -246,7 +234,7 @@ static bool find_guid(const char *guid_string, struct wmi_block **out) | |||
246 | wmi_parse_guid(guid_string, tmp); | 234 | wmi_parse_guid(guid_string, tmp); |
247 | wmi_swap_bytes(tmp, guid_input); | 235 | wmi_swap_bytes(tmp, guid_input); |
248 | 236 | ||
249 | list_for_each(p, &wmi_blocks.list) { | 237 | list_for_each(p, &wmi_block_list) { |
250 | wblock = list_entry(p, struct wmi_block, list); | 238 | wblock = list_entry(p, struct wmi_block, list); |
251 | block = &wblock->gblock; | 239 | block = &wblock->gblock; |
252 | 240 | ||
@@ -487,30 +475,29 @@ const struct acpi_buffer *in) | |||
487 | } | 475 | } |
488 | EXPORT_SYMBOL_GPL(wmi_set_block); | 476 | EXPORT_SYMBOL_GPL(wmi_set_block); |
489 | 477 | ||
490 | static void wmi_dump_wdg(struct guid_block *g) | 478 | static void wmi_dump_wdg(const struct guid_block *g) |
491 | { | 479 | { |
492 | char guid_string[37]; | 480 | char guid_string[37]; |
493 | 481 | ||
494 | wmi_gtoa(g->guid, guid_string); | 482 | wmi_gtoa(g->guid, guid_string); |
495 | printk(KERN_INFO PREFIX "%s:\n", guid_string); | 483 | |
496 | printk(KERN_INFO PREFIX "\tobject_id: %c%c\n", | 484 | pr_info("%s:\n", guid_string); |
497 | g->object_id[0], g->object_id[1]); | 485 | pr_info("\tobject_id: %c%c\n", g->object_id[0], g->object_id[1]); |
498 | printk(KERN_INFO PREFIX "\tnotify_id: %02X\n", g->notify_id); | 486 | pr_info("\tnotify_id: %02X\n", g->notify_id); |
499 | printk(KERN_INFO PREFIX "\treserved: %02X\n", g->reserved); | 487 | pr_info("\treserved: %02X\n", g->reserved); |
500 | printk(KERN_INFO PREFIX "\tinstance_count: %d\n", g->instance_count); | 488 | pr_info("\tinstance_count: %d\n", g->instance_count); |
501 | printk(KERN_INFO PREFIX "\tflags: %#x", g->flags); | 489 | pr_info("\tflags: %#x", g->flags); |
502 | if (g->flags) { | 490 | if (g->flags) { |
503 | printk(" "); | ||
504 | if (g->flags & ACPI_WMI_EXPENSIVE) | 491 | if (g->flags & ACPI_WMI_EXPENSIVE) |
505 | printk("ACPI_WMI_EXPENSIVE "); | 492 | pr_cont(" ACPI_WMI_EXPENSIVE"); |
506 | if (g->flags & ACPI_WMI_METHOD) | 493 | if (g->flags & ACPI_WMI_METHOD) |
507 | printk("ACPI_WMI_METHOD "); | 494 | pr_cont(" ACPI_WMI_METHOD"); |
508 | if (g->flags & ACPI_WMI_STRING) | 495 | if (g->flags & ACPI_WMI_STRING) |
509 | printk("ACPI_WMI_STRING "); | 496 | pr_cont(" ACPI_WMI_STRING"); |
510 | if (g->flags & ACPI_WMI_EVENT) | 497 | if (g->flags & ACPI_WMI_EVENT) |
511 | printk("ACPI_WMI_EVENT "); | 498 | pr_cont(" ACPI_WMI_EVENT"); |
512 | } | 499 | } |
513 | printk("\n"); | 500 | pr_cont("\n"); |
514 | 501 | ||
515 | } | 502 | } |
516 | 503 | ||
@@ -522,7 +509,7 @@ static void wmi_notify_debug(u32 value, void *context) | |||
522 | 509 | ||
523 | status = wmi_get_event_data(value, &response); | 510 | status = wmi_get_event_data(value, &response); |
524 | if (status != AE_OK) { | 511 | if (status != AE_OK) { |
525 | printk(KERN_INFO "wmi: bad event status 0x%x\n", status); | 512 | pr_info("bad event status 0x%x\n", status); |
526 | return; | 513 | return; |
527 | } | 514 | } |
528 | 515 | ||
@@ -531,22 +518,22 @@ static void wmi_notify_debug(u32 value, void *context) | |||
531 | if (!obj) | 518 | if (!obj) |
532 | return; | 519 | return; |
533 | 520 | ||
534 | printk(KERN_INFO PREFIX "DEBUG Event "); | 521 | pr_info("DEBUG Event "); |
535 | switch(obj->type) { | 522 | switch(obj->type) { |
536 | case ACPI_TYPE_BUFFER: | 523 | case ACPI_TYPE_BUFFER: |
537 | printk("BUFFER_TYPE - length %d\n", obj->buffer.length); | 524 | pr_cont("BUFFER_TYPE - length %d\n", obj->buffer.length); |
538 | break; | 525 | break; |
539 | case ACPI_TYPE_STRING: | 526 | case ACPI_TYPE_STRING: |
540 | printk("STRING_TYPE - %s\n", obj->string.pointer); | 527 | pr_cont("STRING_TYPE - %s\n", obj->string.pointer); |
541 | break; | 528 | break; |
542 | case ACPI_TYPE_INTEGER: | 529 | case ACPI_TYPE_INTEGER: |
543 | printk("INTEGER_TYPE - %llu\n", obj->integer.value); | 530 | pr_cont("INTEGER_TYPE - %llu\n", obj->integer.value); |
544 | break; | 531 | break; |
545 | case ACPI_TYPE_PACKAGE: | 532 | case ACPI_TYPE_PACKAGE: |
546 | printk("PACKAGE_TYPE - %d elements\n", obj->package.count); | 533 | pr_cont("PACKAGE_TYPE - %d elements\n", obj->package.count); |
547 | break; | 534 | break; |
548 | default: | 535 | default: |
549 | printk("object type 0x%X\n", obj->type); | 536 | pr_cont("object type 0x%X\n", obj->type); |
550 | } | 537 | } |
551 | kfree(obj); | 538 | kfree(obj); |
552 | } | 539 | } |
@@ -562,21 +549,34 @@ acpi_status wmi_install_notify_handler(const char *guid, | |||
562 | wmi_notify_handler handler, void *data) | 549 | wmi_notify_handler handler, void *data) |
563 | { | 550 | { |
564 | struct wmi_block *block; | 551 | struct wmi_block *block; |
565 | acpi_status status; | 552 | acpi_status status = AE_NOT_EXIST; |
553 | char tmp[16], guid_input[16]; | ||
554 | struct list_head *p; | ||
566 | 555 | ||
567 | if (!guid || !handler) | 556 | if (!guid || !handler) |
568 | return AE_BAD_PARAMETER; | 557 | return AE_BAD_PARAMETER; |
569 | 558 | ||
570 | if (!find_guid(guid, &block)) | 559 | wmi_parse_guid(guid, tmp); |
571 | return AE_NOT_EXIST; | 560 | wmi_swap_bytes(tmp, guid_input); |
572 | 561 | ||
573 | if (block->handler && block->handler != wmi_notify_debug) | 562 | list_for_each(p, &wmi_block_list) { |
574 | return AE_ALREADY_ACQUIRED; | 563 | acpi_status wmi_status; |
564 | block = list_entry(p, struct wmi_block, list); | ||
575 | 565 | ||
576 | block->handler = handler; | 566 | if (memcmp(block->gblock.guid, guid_input, 16) == 0) { |
577 | block->handler_data = data; | 567 | if (block->handler && |
568 | block->handler != wmi_notify_debug) | ||
569 | return AE_ALREADY_ACQUIRED; | ||
578 | 570 | ||
579 | 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 | } | ||
580 | 580 | ||
581 | return status; | 581 | return status; |
582 | } | 582 | } |
@@ -590,24 +590,40 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler); | |||
590 | acpi_status wmi_remove_notify_handler(const char *guid) | 590 | acpi_status wmi_remove_notify_handler(const char *guid) |
591 | { | 591 | { |
592 | struct wmi_block *block; | 592 | struct wmi_block *block; |
593 | acpi_status status = AE_OK; | 593 | acpi_status status = AE_NOT_EXIST; |
594 | char tmp[16], guid_input[16]; | ||
595 | struct list_head *p; | ||
594 | 596 | ||
595 | if (!guid) | 597 | if (!guid) |
596 | return AE_BAD_PARAMETER; | 598 | return AE_BAD_PARAMETER; |
597 | 599 | ||
598 | if (!find_guid(guid, &block)) | 600 | wmi_parse_guid(guid, tmp); |
599 | return AE_NOT_EXIST; | 601 | wmi_swap_bytes(tmp, guid_input); |
600 | 602 | ||
601 | if (!block->handler || block->handler == wmi_notify_debug) | 603 | list_for_each(p, &wmi_block_list) { |
602 | return AE_NULL_ENTRY; | 604 | acpi_status wmi_status; |
605 | block = list_entry(p, struct wmi_block, list); | ||
603 | 606 | ||
604 | if (debug_event) { | 607 | if (memcmp(block->gblock.guid, guid_input, 16) == 0) { |
605 | block->handler = wmi_notify_debug; | 608 | if (!block->handler || |
606 | } else { | 609 | block->handler == wmi_notify_debug) |
607 | status = wmi_method_enable(block, 0); | 610 | return AE_NULL_ENTRY; |
608 | block->handler = NULL; | 611 | |
609 | 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 | } | ||
610 | } | 625 | } |
626 | |||
611 | return status; | 627 | return status; |
612 | } | 628 | } |
613 | EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); | 629 | EXPORT_SYMBOL_GPL(wmi_remove_notify_handler); |
@@ -633,7 +649,7 @@ acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out) | |||
633 | params[0].type = ACPI_TYPE_INTEGER; | 649 | params[0].type = ACPI_TYPE_INTEGER; |
634 | params[0].integer.value = event; | 650 | params[0].integer.value = event; |
635 | 651 | ||
636 | list_for_each(p, &wmi_blocks.list) { | 652 | list_for_each(p, &wmi_block_list) { |
637 | wblock = list_entry(p, struct wmi_block, list); | 653 | wblock = list_entry(p, struct wmi_block, list); |
638 | gblock = &wblock->gblock; | 654 | gblock = &wblock->gblock; |
639 | 655 | ||
@@ -662,7 +678,7 @@ EXPORT_SYMBOL_GPL(wmi_has_guid); | |||
662 | /* | 678 | /* |
663 | * sysfs interface | 679 | * sysfs interface |
664 | */ | 680 | */ |
665 | static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, | 681 | static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, |
666 | char *buf) | 682 | char *buf) |
667 | { | 683 | { |
668 | char guid_string[37]; | 684 | char guid_string[37]; |
@@ -676,7 +692,11 @@ static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, | |||
676 | 692 | ||
677 | return sprintf(buf, "wmi:%s\n", guid_string); | 693 | return sprintf(buf, "wmi:%s\n", guid_string); |
678 | } | 694 | } |
679 | static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); | 695 | |
696 | static struct device_attribute wmi_dev_attrs[] = { | ||
697 | __ATTR_RO(modalias), | ||
698 | __ATTR_NULL | ||
699 | }; | ||
680 | 700 | ||
681 | static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | 701 | static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) |
682 | { | 702 | { |
@@ -702,108 +722,51 @@ static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
702 | 722 | ||
703 | static void wmi_dev_free(struct device *dev) | 723 | static void wmi_dev_free(struct device *dev) |
704 | { | 724 | { |
705 | kfree(dev); | 725 | struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev); |
726 | |||
727 | kfree(wmi_block); | ||
706 | } | 728 | } |
707 | 729 | ||
708 | static struct class wmi_class = { | 730 | static struct class wmi_class = { |
709 | .name = "wmi", | 731 | .name = "wmi", |
710 | .dev_release = wmi_dev_free, | 732 | .dev_release = wmi_dev_free, |
711 | .dev_uevent = wmi_dev_uevent, | 733 | .dev_uevent = wmi_dev_uevent, |
734 | .dev_attrs = wmi_dev_attrs, | ||
712 | }; | 735 | }; |
713 | 736 | ||
714 | static int wmi_create_devs(void) | 737 | static int wmi_create_device(const struct guid_block *gblock, |
738 | struct wmi_block *wblock, acpi_handle handle) | ||
715 | { | 739 | { |
716 | int result; | ||
717 | char guid_string[37]; | 740 | char guid_string[37]; |
718 | struct guid_block *gblock; | ||
719 | struct wmi_block *wblock; | ||
720 | struct list_head *p; | ||
721 | struct device *guid_dev; | ||
722 | |||
723 | /* Create devices for all the GUIDs */ | ||
724 | list_for_each(p, &wmi_blocks.list) { | ||
725 | wblock = list_entry(p, struct wmi_block, list); | ||
726 | |||
727 | guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
728 | if (!guid_dev) | ||
729 | return -ENOMEM; | ||
730 | |||
731 | wblock->dev = guid_dev; | ||
732 | |||
733 | guid_dev->class = &wmi_class; | ||
734 | dev_set_drvdata(guid_dev, wblock); | ||
735 | |||
736 | gblock = &wblock->gblock; | ||
737 | 741 | ||
738 | wmi_gtoa(gblock->guid, guid_string); | 742 | wblock->dev.class = &wmi_class; |
739 | dev_set_name(guid_dev, guid_string); | ||
740 | 743 | ||
741 | result = device_register(guid_dev); | 744 | wmi_gtoa(gblock->guid, guid_string); |
742 | if (result) | 745 | dev_set_name(&wblock->dev, guid_string); |
743 | return result; | ||
744 | 746 | ||
745 | result = device_create_file(guid_dev, &dev_attr_modalias); | 747 | dev_set_drvdata(&wblock->dev, wblock); |
746 | if (result) | ||
747 | return result; | ||
748 | } | ||
749 | 748 | ||
750 | return 0; | 749 | return device_register(&wblock->dev); |
751 | } | 750 | } |
752 | 751 | ||
753 | static void wmi_remove_devs(void) | 752 | static void wmi_free_devices(void) |
754 | { | 753 | { |
755 | struct guid_block *gblock; | 754 | struct wmi_block *wblock, *next; |
756 | struct wmi_block *wblock; | ||
757 | struct list_head *p; | ||
758 | struct device *guid_dev; | ||
759 | 755 | ||
760 | /* Delete devices for all the GUIDs */ | 756 | /* Delete devices for all the GUIDs */ |
761 | list_for_each(p, &wmi_blocks.list) { | 757 | list_for_each_entry_safe(wblock, next, &wmi_block_list, list) |
762 | wblock = list_entry(p, struct wmi_block, list); | 758 | if (wblock->dev.class) |
763 | 759 | device_unregister(&wblock->dev); | |
764 | guid_dev = wblock->dev; | ||
765 | gblock = &wblock->gblock; | ||
766 | |||
767 | device_remove_file(guid_dev, &dev_attr_modalias); | ||
768 | |||
769 | device_unregister(guid_dev); | ||
770 | } | ||
771 | } | ||
772 | |||
773 | static void wmi_class_exit(void) | ||
774 | { | ||
775 | wmi_remove_devs(); | ||
776 | class_unregister(&wmi_class); | ||
777 | } | ||
778 | |||
779 | static int wmi_class_init(void) | ||
780 | { | ||
781 | int ret; | ||
782 | |||
783 | ret = class_register(&wmi_class); | ||
784 | if (ret) | ||
785 | return ret; | ||
786 | |||
787 | ret = wmi_create_devs(); | ||
788 | if (ret) | ||
789 | wmi_class_exit(); | ||
790 | |||
791 | return ret; | ||
792 | } | 760 | } |
793 | 761 | ||
794 | static bool guid_already_parsed(const char *guid_string) | 762 | static bool guid_already_parsed(const char *guid_string) |
795 | { | 763 | { |
796 | struct guid_block *gblock; | ||
797 | struct wmi_block *wblock; | 764 | struct wmi_block *wblock; |
798 | struct list_head *p; | ||
799 | 765 | ||
800 | list_for_each(p, &wmi_blocks.list) { | 766 | list_for_each_entry(wblock, &wmi_block_list, list) |
801 | wblock = list_entry(p, struct wmi_block, list); | 767 | if (memcmp(wblock->gblock.guid, guid_string, 16) == 0) |
802 | gblock = &wblock->gblock; | ||
803 | |||
804 | if (strncmp(gblock->guid, guid_string, 16) == 0) | ||
805 | return true; | 768 | return true; |
806 | } | 769 | |
807 | return false; | 770 | return false; |
808 | } | 771 | } |
809 | 772 | ||
@@ -814,68 +777,67 @@ static acpi_status parse_wdg(acpi_handle handle) | |||
814 | { | 777 | { |
815 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; | 778 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; |
816 | union acpi_object *obj; | 779 | union acpi_object *obj; |
817 | struct guid_block *gblock; | 780 | const struct guid_block *gblock; |
818 | struct wmi_block *wblock; | 781 | struct wmi_block *wblock; |
819 | char guid_string[37]; | ||
820 | acpi_status status; | 782 | acpi_status status; |
783 | int retval; | ||
821 | u32 i, total; | 784 | u32 i, total; |
822 | 785 | ||
823 | status = acpi_evaluate_object(handle, "_WDG", NULL, &out); | 786 | status = acpi_evaluate_object(handle, "_WDG", NULL, &out); |
824 | |||
825 | if (ACPI_FAILURE(status)) | 787 | if (ACPI_FAILURE(status)) |
826 | return status; | 788 | return -ENXIO; |
827 | 789 | ||
828 | obj = (union acpi_object *) out.pointer; | 790 | obj = (union acpi_object *) out.pointer; |
791 | if (!obj) | ||
792 | return -ENXIO; | ||
829 | 793 | ||
830 | if (obj->type != ACPI_TYPE_BUFFER) | 794 | if (obj->type != ACPI_TYPE_BUFFER) { |
831 | return AE_ERROR; | 795 | retval = -ENXIO; |
832 | |||
833 | total = obj->buffer.length / sizeof(struct guid_block); | ||
834 | |||
835 | gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL); | ||
836 | if (!gblock) { | ||
837 | status = AE_NO_MEMORY; | ||
838 | goto out_free_pointer; | 796 | goto out_free_pointer; |
839 | } | 797 | } |
840 | 798 | ||
799 | gblock = (const struct guid_block *)obj->buffer.pointer; | ||
800 | total = obj->buffer.length / sizeof(struct guid_block); | ||
801 | |||
841 | 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 | |||
842 | /* | 813 | /* |
843 | Some WMI devices, like those for nVidia hooks, have a | 814 | Some WMI devices, like those for nVidia hooks, have a |
844 | 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 |
845 | case yet, so for now, we'll just ignore the duplicate. | 816 | case yet, so for now, we'll just ignore the duplicate |
846 | Anyone who wants to add support for that device can come | 817 | for device creation. |
847 | up with a better workaround for the mess then. | ||
848 | */ | 818 | */ |
849 | if (guid_already_parsed(gblock[i].guid) == true) { | 819 | if (!guid_already_parsed(gblock[i].guid)) { |
850 | wmi_gtoa(gblock[i].guid, guid_string); | 820 | retval = wmi_create_device(&gblock[i], wblock, handle); |
851 | printk(KERN_INFO PREFIX "Skipping duplicate GUID %s\n", | 821 | if (retval) { |
852 | guid_string); | 822 | wmi_free_devices(); |
853 | continue; | 823 | goto out_free_pointer; |
824 | } | ||
854 | } | 825 | } |
855 | if (debug_dump_wdg) | ||
856 | wmi_dump_wdg(&gblock[i]); | ||
857 | 826 | ||
858 | wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); | 827 | list_add_tail(&wblock->list, &wmi_block_list); |
859 | if (!wblock) { | ||
860 | status = AE_NO_MEMORY; | ||
861 | goto out_free_gblock; | ||
862 | } | ||
863 | 828 | ||
864 | wblock->gblock = gblock[i]; | ||
865 | wblock->handle = handle; | ||
866 | if (debug_event) { | 829 | if (debug_event) { |
867 | wblock->handler = wmi_notify_debug; | 830 | wblock->handler = wmi_notify_debug; |
868 | status = wmi_method_enable(wblock, 1); | 831 | wmi_method_enable(wblock, 1); |
869 | } | 832 | } |
870 | list_add_tail(&wblock->list, &wmi_blocks.list); | ||
871 | } | 833 | } |
872 | 834 | ||
873 | out_free_gblock: | 835 | retval = 0; |
874 | kfree(gblock); | 836 | |
875 | out_free_pointer: | 837 | out_free_pointer: |
876 | kfree(out.pointer); | 838 | kfree(out.pointer); |
877 | 839 | ||
878 | return status; | 840 | return retval; |
879 | } | 841 | } |
880 | 842 | ||
881 | /* | 843 | /* |
@@ -929,7 +891,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event) | |||
929 | struct list_head *p; | 891 | struct list_head *p; |
930 | char guid_string[37]; | 892 | char guid_string[37]; |
931 | 893 | ||
932 | list_for_each(p, &wmi_blocks.list) { | 894 | list_for_each(p, &wmi_block_list) { |
933 | wblock = list_entry(p, struct wmi_block, list); | 895 | wblock = list_entry(p, struct wmi_block, list); |
934 | block = &wblock->gblock; | 896 | block = &wblock->gblock; |
935 | 897 | ||
@@ -939,8 +901,7 @@ static void acpi_wmi_notify(struct acpi_device *device, u32 event) | |||
939 | wblock->handler(event, wblock->handler_data); | 901 | wblock->handler(event, wblock->handler_data); |
940 | if (debug_event) { | 902 | if (debug_event) { |
941 | wmi_gtoa(wblock->gblock.guid, guid_string); | 903 | wmi_gtoa(wblock->gblock.guid, guid_string); |
942 | printk(KERN_INFO PREFIX "DEBUG Event GUID:" | 904 | pr_info("DEBUG Event GUID: %s\n", guid_string); |
943 | " %s\n", guid_string); | ||
944 | } | 905 | } |
945 | 906 | ||
946 | acpi_bus_generate_netlink_event( | 907 | acpi_bus_generate_netlink_event( |
@@ -955,6 +916,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type) | |||
955 | { | 916 | { |
956 | acpi_remove_address_space_handler(device->handle, | 917 | acpi_remove_address_space_handler(device->handle, |
957 | ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); | 918 | ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); |
919 | wmi_free_devices(); | ||
958 | 920 | ||
959 | return 0; | 921 | return 0; |
960 | } | 922 | } |
@@ -962,68 +924,57 @@ static int acpi_wmi_remove(struct acpi_device *device, int type) | |||
962 | static int acpi_wmi_add(struct acpi_device *device) | 924 | static int acpi_wmi_add(struct acpi_device *device) |
963 | { | 925 | { |
964 | acpi_status status; | 926 | acpi_status status; |
965 | int result = 0; | 927 | int error; |
966 | 928 | ||
967 | status = acpi_install_address_space_handler(device->handle, | 929 | status = acpi_install_address_space_handler(device->handle, |
968 | ACPI_ADR_SPACE_EC, | 930 | ACPI_ADR_SPACE_EC, |
969 | &acpi_wmi_ec_space_handler, | 931 | &acpi_wmi_ec_space_handler, |
970 | NULL, NULL); | 932 | NULL, NULL); |
971 | if (ACPI_FAILURE(status)) | ||
972 | return -ENODEV; | ||
973 | |||
974 | status = parse_wdg(device->handle); | ||
975 | if (ACPI_FAILURE(status)) { | 933 | if (ACPI_FAILURE(status)) { |
976 | printk(KERN_ERR PREFIX "Error installing EC region handler\n"); | 934 | pr_err("Error installing EC region handler\n"); |
977 | return -ENODEV; | 935 | return -ENODEV; |
978 | } | 936 | } |
979 | 937 | ||
980 | return result; | 938 | error = parse_wdg(device->handle); |
939 | if (error) { | ||
940 | acpi_remove_address_space_handler(device->handle, | ||
941 | ACPI_ADR_SPACE_EC, | ||
942 | &acpi_wmi_ec_space_handler); | ||
943 | pr_err("Failed to parse WDG method\n"); | ||
944 | return error; | ||
945 | } | ||
946 | |||
947 | return 0; | ||
981 | } | 948 | } |
982 | 949 | ||
983 | static int __init acpi_wmi_init(void) | 950 | static int __init acpi_wmi_init(void) |
984 | { | 951 | { |
985 | int result; | 952 | int error; |
986 | |||
987 | INIT_LIST_HEAD(&wmi_blocks.list); | ||
988 | 953 | ||
989 | if (acpi_disabled) | 954 | if (acpi_disabled) |
990 | return -ENODEV; | 955 | return -ENODEV; |
991 | 956 | ||
992 | result = acpi_bus_register_driver(&acpi_wmi_driver); | 957 | error = class_register(&wmi_class); |
993 | 958 | if (error) | |
994 | if (result < 0) { | 959 | return error; |
995 | printk(KERN_INFO PREFIX "Error loading mapper\n"); | ||
996 | return -ENODEV; | ||
997 | } | ||
998 | 960 | ||
999 | result = wmi_class_init(); | 961 | error = acpi_bus_register_driver(&acpi_wmi_driver); |
1000 | if (result) { | 962 | if (error) { |
1001 | acpi_bus_unregister_driver(&acpi_wmi_driver); | 963 | pr_err("Error loading mapper\n"); |
1002 | return result; | 964 | class_unregister(&wmi_class); |
965 | return error; | ||
1003 | } | 966 | } |
1004 | 967 | ||
1005 | printk(KERN_INFO PREFIX "Mapper loaded\n"); | 968 | pr_info("Mapper loaded\n"); |
1006 | 969 | return 0; | |
1007 | return result; | ||
1008 | } | 970 | } |
1009 | 971 | ||
1010 | static void __exit acpi_wmi_exit(void) | 972 | static void __exit acpi_wmi_exit(void) |
1011 | { | 973 | { |
1012 | struct list_head *p, *tmp; | ||
1013 | struct wmi_block *wblock; | ||
1014 | |||
1015 | wmi_class_exit(); | ||
1016 | |||
1017 | acpi_bus_unregister_driver(&acpi_wmi_driver); | 974 | acpi_bus_unregister_driver(&acpi_wmi_driver); |
975 | class_unregister(&wmi_class); | ||
1018 | 976 | ||
1019 | list_for_each_safe(p, tmp, &wmi_blocks.list) { | 977 | pr_info("Mapper unloaded\n"); |
1020 | wblock = list_entry(p, struct wmi_block, list); | ||
1021 | |||
1022 | list_del(p); | ||
1023 | kfree(wblock); | ||
1024 | } | ||
1025 | |||
1026 | printk(KERN_INFO PREFIX "Mapper unloaded\n"); | ||
1027 | } | 978 | } |
1028 | 979 | ||
1029 | subsys_initcall(acpi_wmi_init); | 980 | subsys_initcall(acpi_wmi_init); |