diff options
author | Len Brown <len.brown@intel.com> | 2009-12-16 02:21:25 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-12-16 02:21:25 -0500 |
commit | b6202832b43abb56b90ba8d68e2b9fc53c442fa6 (patch) | |
tree | 92036b22402fb1a5e50be94073e9475f8b2824ae /drivers/platform | |
parent | 1a544d28dd2fd7c90bb23118ab0ca09b1304a50c (diff) | |
parent | 1caab3c1a90be3aa4ec3599409d8fe044b077478 (diff) |
Merge branch 'wmi' into release
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/wmi.c | 175 |
1 files changed, 173 insertions, 2 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 177f8d767df4..e425a868cd3a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/device.h> | ||
33 | #include <linux/list.h> | 34 | #include <linux/list.h> |
34 | #include <linux/acpi.h> | 35 | #include <linux/acpi.h> |
35 | #include <acpi/acpi_bus.h> | 36 | #include <acpi/acpi_bus.h> |
@@ -65,6 +66,7 @@ struct wmi_block { | |||
65 | acpi_handle handle; | 66 | acpi_handle handle; |
66 | wmi_notify_handler handler; | 67 | wmi_notify_handler handler; |
67 | void *handler_data; | 68 | void *handler_data; |
69 | struct device *dev; | ||
68 | }; | 70 | }; |
69 | 71 | ||
70 | static struct wmi_block wmi_blocks; | 72 | static struct wmi_block wmi_blocks; |
@@ -195,6 +197,34 @@ static bool wmi_parse_guid(const u8 *src, u8 *dest) | |||
195 | return true; | 197 | return true; |
196 | } | 198 | } |
197 | 199 | ||
200 | /* | ||
201 | * Convert a raw GUID to the ACII string representation | ||
202 | */ | ||
203 | static int wmi_gtoa(const char *in, char *out) | ||
204 | { | ||
205 | int i; | ||
206 | |||
207 | for (i = 3; i >= 0; i--) | ||
208 | out += sprintf(out, "%02X", in[i] & 0xFF); | ||
209 | |||
210 | out += sprintf(out, "-"); | ||
211 | out += sprintf(out, "%02X", in[5] & 0xFF); | ||
212 | out += sprintf(out, "%02X", in[4] & 0xFF); | ||
213 | out += sprintf(out, "-"); | ||
214 | out += sprintf(out, "%02X", in[7] & 0xFF); | ||
215 | out += sprintf(out, "%02X", in[6] & 0xFF); | ||
216 | out += sprintf(out, "-"); | ||
217 | out += sprintf(out, "%02X", in[8] & 0xFF); | ||
218 | out += sprintf(out, "%02X", in[9] & 0xFF); | ||
219 | out += sprintf(out, "-"); | ||
220 | |||
221 | for (i = 10; i <= 15; i++) | ||
222 | out += sprintf(out, "%02X", in[i] & 0xFF); | ||
223 | |||
224 | out = '\0'; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
198 | static bool find_guid(const char *guid_string, struct wmi_block **out) | 228 | static bool find_guid(const char *guid_string, struct wmi_block **out) |
199 | { | 229 | { |
200 | char tmp[16], guid_input[16]; | 230 | char tmp[16], guid_input[16]; |
@@ -555,6 +585,138 @@ bool wmi_has_guid(const char *guid_string) | |||
555 | EXPORT_SYMBOL_GPL(wmi_has_guid); | 585 | EXPORT_SYMBOL_GPL(wmi_has_guid); |
556 | 586 | ||
557 | /* | 587 | /* |
588 | * sysfs interface | ||
589 | */ | ||
590 | static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, | ||
591 | char *buf) | ||
592 | { | ||
593 | char guid_string[37]; | ||
594 | struct wmi_block *wblock; | ||
595 | |||
596 | wblock = dev_get_drvdata(dev); | ||
597 | if (!wblock) | ||
598 | return -ENOMEM; | ||
599 | |||
600 | wmi_gtoa(wblock->gblock.guid, guid_string); | ||
601 | |||
602 | return sprintf(buf, "wmi:%s\n", guid_string); | ||
603 | } | ||
604 | static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); | ||
605 | |||
606 | static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
607 | { | ||
608 | char guid_string[37]; | ||
609 | |||
610 | struct wmi_block *wblock; | ||
611 | |||
612 | if (add_uevent_var(env, "MODALIAS=")) | ||
613 | return -ENOMEM; | ||
614 | |||
615 | wblock = dev_get_drvdata(dev); | ||
616 | if (!wblock) | ||
617 | return -ENOMEM; | ||
618 | |||
619 | wmi_gtoa(wblock->gblock.guid, guid_string); | ||
620 | |||
621 | strcpy(&env->buf[env->buflen - 1], "wmi:"); | ||
622 | memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36); | ||
623 | env->buflen += 40; | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static void wmi_dev_free(struct device *dev) | ||
629 | { | ||
630 | kfree(dev); | ||
631 | } | ||
632 | |||
633 | static struct class wmi_class = { | ||
634 | .name = "wmi", | ||
635 | .dev_release = wmi_dev_free, | ||
636 | .dev_uevent = wmi_dev_uevent, | ||
637 | }; | ||
638 | |||
639 | static int wmi_create_devs(void) | ||
640 | { | ||
641 | int result; | ||
642 | char guid_string[37]; | ||
643 | struct guid_block *gblock; | ||
644 | struct wmi_block *wblock; | ||
645 | struct list_head *p; | ||
646 | struct device *guid_dev; | ||
647 | |||
648 | /* Create devices for all the GUIDs */ | ||
649 | list_for_each(p, &wmi_blocks.list) { | ||
650 | wblock = list_entry(p, struct wmi_block, list); | ||
651 | |||
652 | guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
653 | if (!guid_dev) | ||
654 | return -ENOMEM; | ||
655 | |||
656 | wblock->dev = guid_dev; | ||
657 | |||
658 | guid_dev->class = &wmi_class; | ||
659 | dev_set_drvdata(guid_dev, wblock); | ||
660 | |||
661 | gblock = &wblock->gblock; | ||
662 | |||
663 | wmi_gtoa(gblock->guid, guid_string); | ||
664 | dev_set_name(guid_dev, guid_string); | ||
665 | |||
666 | result = device_register(guid_dev); | ||
667 | if (result) | ||
668 | return result; | ||
669 | |||
670 | result = device_create_file(guid_dev, &dev_attr_modalias); | ||
671 | if (result) | ||
672 | return result; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static void wmi_remove_devs(void) | ||
679 | { | ||
680 | struct guid_block *gblock; | ||
681 | struct wmi_block *wblock; | ||
682 | struct list_head *p; | ||
683 | struct device *guid_dev; | ||
684 | |||
685 | /* Delete devices for all the GUIDs */ | ||
686 | list_for_each(p, &wmi_blocks.list) { | ||
687 | wblock = list_entry(p, struct wmi_block, list); | ||
688 | |||
689 | guid_dev = wblock->dev; | ||
690 | gblock = &wblock->gblock; | ||
691 | |||
692 | device_remove_file(guid_dev, &dev_attr_modalias); | ||
693 | |||
694 | device_unregister(guid_dev); | ||
695 | } | ||
696 | } | ||
697 | |||
698 | static void wmi_class_exit(void) | ||
699 | { | ||
700 | wmi_remove_devs(); | ||
701 | class_unregister(&wmi_class); | ||
702 | } | ||
703 | |||
704 | static int wmi_class_init(void) | ||
705 | { | ||
706 | int ret; | ||
707 | |||
708 | ret = class_register(&wmi_class); | ||
709 | if (ret) | ||
710 | return ret; | ||
711 | |||
712 | ret = wmi_create_devs(); | ||
713 | if (ret) | ||
714 | wmi_class_exit(); | ||
715 | |||
716 | return ret; | ||
717 | } | ||
718 | |||
719 | /* | ||
558 | * Parse the _WDG method for the GUID data blocks | 720 | * Parse the _WDG method for the GUID data blocks |
559 | */ | 721 | */ |
560 | static __init acpi_status parse_wdg(acpi_handle handle) | 722 | static __init acpi_status parse_wdg(acpi_handle handle) |
@@ -709,10 +871,17 @@ static int __init acpi_wmi_init(void) | |||
709 | 871 | ||
710 | if (result < 0) { | 872 | if (result < 0) { |
711 | printk(KERN_INFO PREFIX "Error loading mapper\n"); | 873 | printk(KERN_INFO PREFIX "Error loading mapper\n"); |
712 | } else { | 874 | return -ENODEV; |
713 | printk(KERN_INFO PREFIX "Mapper loaded\n"); | 875 | } |
876 | |||
877 | result = wmi_class_init(); | ||
878 | if (result) { | ||
879 | acpi_bus_unregister_driver(&acpi_wmi_driver); | ||
880 | return result; | ||
714 | } | 881 | } |
715 | 882 | ||
883 | printk(KERN_INFO PREFIX "Mapper loaded\n"); | ||
884 | |||
716 | return result; | 885 | return result; |
717 | } | 886 | } |
718 | 887 | ||
@@ -721,6 +890,8 @@ static void __exit acpi_wmi_exit(void) | |||
721 | struct list_head *p, *tmp; | 890 | struct list_head *p, *tmp; |
722 | struct wmi_block *wblock; | 891 | struct wmi_block *wblock; |
723 | 892 | ||
893 | wmi_class_exit(); | ||
894 | |||
724 | acpi_bus_unregister_driver(&acpi_wmi_driver); | 895 | acpi_bus_unregister_driver(&acpi_wmi_driver); |
725 | 896 | ||
726 | list_for_each_safe(p, tmp, &wmi_blocks.list) { | 897 | list_for_each_safe(p, tmp, &wmi_blocks.list) { |