aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/wmi.c
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2015-11-24 22:49:23 -0500
committerDarren Hart (VMware) <dvhart@infradead.org>2017-06-06 13:15:18 -0400
commit844af950da946cfab227a04b950614da04cb6275 (patch)
tree4bb4e0aa002cc1566cfc08b87ec274c094b06bbe /drivers/platform/x86/wmi.c
parentb0e86302973d9e710c722a8436cc7e099d2a5b0d (diff)
platform/x86: wmi: Turn WMI into a bus driver
WMI is logically a bus: the WMI driver binds to an ACPI node (or more than one), and each instance of the WMI driver enumerates its children and hopes that drivers will attach to the children that are useful. This patch gives WMI a driver model bus type and the ability to match to drivers. The bus itself is a device in the new "wmi_bus" class, and all of the individual WMI devices are slotted into the device hierarchy correctly. Signed-off-by: Andy Lutomirski <luto@kernel.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Mario Limonciello <mario_limonciello@dell.com> Cc: Pali Rohár <pali.rohar@gmail.com> Cc: linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org Cc: linux-acpi@vger.kernel.org Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Darren Hart (VMware) <dvhart@infradead.org>
Diffstat (limited to 'drivers/platform/x86/wmi.c')
-rw-r--r--drivers/platform/x86/wmi.c197
1 files changed, 154 insertions, 43 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index faaa9a7c9c2e..f06b7c00339d 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -37,6 +37,7 @@
37#include <linux/acpi.h> 37#include <linux/acpi.h>
38#include <linux/slab.h> 38#include <linux/slab.h>
39#include <linux/module.h> 39#include <linux/module.h>
40#include <linux/wmi.h>
40#include <linux/uuid.h> 41#include <linux/uuid.h>
41 42
42ACPI_MODULE_NAME("wmi"); 43ACPI_MODULE_NAME("wmi");
@@ -44,8 +45,6 @@ MODULE_AUTHOR("Carlos Corbacho");
44MODULE_DESCRIPTION("ACPI-WMI Mapping Driver"); 45MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
45MODULE_LICENSE("GPL"); 46MODULE_LICENSE("GPL");
46 47
47#define ACPI_WMI_CLASS "wmi"
48
49static LIST_HEAD(wmi_block_list); 48static LIST_HEAD(wmi_block_list);
50 49
51struct guid_block { 50struct guid_block {
@@ -62,12 +61,12 @@ struct guid_block {
62}; 61};
63 62
64struct wmi_block { 63struct wmi_block {
64 struct wmi_device dev;
65 struct list_head list; 65 struct list_head list;
66 struct guid_block gblock; 66 struct guid_block gblock;
67 struct acpi_device *acpi_device; 67 struct acpi_device *acpi_device;
68 wmi_notify_handler handler; 68 wmi_notify_handler handler;
69 void *handler_data; 69 void *handler_data;
70 struct device dev;
71}; 70};
72 71
73 72
@@ -102,8 +101,8 @@ static const struct acpi_device_id wmi_device_ids[] = {
102MODULE_DEVICE_TABLE(acpi, wmi_device_ids); 101MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
103 102
104static struct acpi_driver acpi_wmi_driver = { 103static struct acpi_driver acpi_wmi_driver = {
105 .name = "wmi", 104 .name = "acpi-wmi",
106 .class = ACPI_WMI_CLASS, 105 .owner = THIS_MODULE,
107 .ids = wmi_device_ids, 106 .ids = wmi_device_ids,
108 .ops = { 107 .ops = {
109 .add = acpi_wmi_add, 108 .add = acpi_wmi_add,
@@ -545,77 +544,146 @@ bool wmi_has_guid(const char *guid_string)
545} 544}
546EXPORT_SYMBOL_GPL(wmi_has_guid); 545EXPORT_SYMBOL_GPL(wmi_has_guid);
547 546
547static struct wmi_block *dev_to_wblock(struct device *dev)
548{
549 return container_of(dev, struct wmi_block, dev.dev);
550}
551
552static struct wmi_device *dev_to_wdev(struct device *dev)
553{
554 return container_of(dev, struct wmi_device, dev);
555}
556
548/* 557/*
549 * sysfs interface 558 * sysfs interface
550 */ 559 */
551static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, 560static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
552 char *buf) 561 char *buf)
553{ 562{
554 struct wmi_block *wblock; 563 struct wmi_block *wblock = dev_to_wblock(dev);
555
556 wblock = dev_get_drvdata(dev);
557 if (!wblock) {
558 strcat(buf, "\n");
559 return strlen(buf);
560 }
561 564
562 return sprintf(buf, "wmi:%pUL\n", wblock->gblock.guid); 565 return sprintf(buf, "wmi:%pUL\n", wblock->gblock.guid);
563} 566}
564static DEVICE_ATTR_RO(modalias); 567static DEVICE_ATTR_RO(modalias);
565 568
569static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
570 char *buf)
571{
572 struct wmi_block *wblock = dev_to_wblock(dev);
573
574 return sprintf(buf, "%pUL\n", wblock->gblock.guid);
575}
576static DEVICE_ATTR_RO(guid);
577
566static struct attribute *wmi_attrs[] = { 578static struct attribute *wmi_attrs[] = {
567 &dev_attr_modalias.attr, 579 &dev_attr_modalias.attr,
580 &dev_attr_guid.attr,
568 NULL, 581 NULL,
569}; 582};
570ATTRIBUTE_GROUPS(wmi); 583ATTRIBUTE_GROUPS(wmi);
571 584
572static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) 585static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
573{ 586{
574 char guid_string[37]; 587 struct wmi_block *wblock = dev_to_wblock(dev);
575
576 struct wmi_block *wblock;
577 588
578 if (add_uevent_var(env, "MODALIAS=")) 589 if (add_uevent_var(env, "MODALIAS=wmi:%pUL", wblock->gblock.guid))
579 return -ENOMEM; 590 return -ENOMEM;
580 591
581 wblock = dev_get_drvdata(dev); 592 if (add_uevent_var(env, "WMI_GUID=%pUL", wblock->gblock.guid))
582 if (!wblock)
583 return -ENOMEM; 593 return -ENOMEM;
584 594
585 sprintf(guid_string, "%pUL", wblock->gblock.guid); 595 return 0;
596}
597
598static void wmi_dev_release(struct device *dev)
599{
600 struct wmi_block *wblock = dev_to_wblock(dev);
601
602 kfree(wblock);
603}
604
605static int wmi_dev_match(struct device *dev, struct device_driver *driver)
606{
607 struct wmi_driver *wmi_driver =
608 container_of(driver, struct wmi_driver, driver);
609 struct wmi_block *wblock = dev_to_wblock(dev);
610 const struct wmi_device_id *id = wmi_driver->id_table;
586 611
587 strcpy(&env->buf[env->buflen - 1], "wmi:"); 612 while (id->guid_string) {
588 memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36); 613 uuid_le driver_guid;
589 env->buflen += 40; 614
615 if (WARN_ON(uuid_le_to_bin(id->guid_string, &driver_guid)))
616 continue;
617 if (!memcmp(&driver_guid, wblock->gblock.guid, 16))
618 return 1;
619
620 id++;
621 }
590 622
591 return 0; 623 return 0;
592} 624}
593 625
594static void wmi_dev_free(struct device *dev) 626static int wmi_dev_probe(struct device *dev)
595{ 627{
596 struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev); 628 struct wmi_block *wblock = dev_to_wblock(dev);
629 struct wmi_driver *wdriver =
630 container_of(dev->driver, struct wmi_driver, driver);
631 int ret = 0;
632
633 if (ACPI_FAILURE(wmi_method_enable(wblock, 1)))
634 dev_warn(dev, "failed to enable device -- probing anyway\n");
635
636 if (wdriver->probe) {
637 ret = wdriver->probe(dev_to_wdev(dev));
638 if (ret != 0 && ACPI_FAILURE(wmi_method_enable(wblock, 0)))
639 dev_warn(dev, "failed to disable device\n");
640 }
641
642 return ret;
643}
644
645static int wmi_dev_remove(struct device *dev)
646{
647 struct wmi_block *wblock = dev_to_wblock(dev);
648 struct wmi_driver *wdriver =
649 container_of(dev->driver, struct wmi_driver, driver);
650 int ret = 0;
651
652 if (wdriver->remove)
653 ret = wdriver->remove(dev_to_wdev(dev));
654
655 if (ACPI_FAILURE(wmi_method_enable(wblock, 0)))
656 dev_warn(dev, "failed to disable device\n");
597 657
598 kfree(wmi_block); 658 return ret;
599} 659}
600 660
601static struct class wmi_class = { 661static struct class wmi_bus_class = {
662 .name = "wmi_bus",
663};
664
665static struct bus_type wmi_bus_type = {
602 .name = "wmi", 666 .name = "wmi",
603 .dev_release = wmi_dev_free,
604 .dev_uevent = wmi_dev_uevent,
605 .dev_groups = wmi_groups, 667 .dev_groups = wmi_groups,
668 .match = wmi_dev_match,
669 .uevent = wmi_dev_uevent,
670 .probe = wmi_dev_probe,
671 .remove = wmi_dev_remove,
606}; 672};
607 673
608static int wmi_create_device(const struct guid_block *gblock, 674static int wmi_create_device(struct device *wmi_bus_dev,
675 const struct guid_block *gblock,
609 struct wmi_block *wblock, 676 struct wmi_block *wblock,
610 struct acpi_device *device) 677 struct acpi_device *device)
611{ 678{
612 wblock->dev.class = &wmi_class; 679 wblock->dev.dev.bus = &wmi_bus_type;
680 wblock->dev.dev.parent = wmi_bus_dev;
613 681
614 dev_set_name(&wblock->dev, "%pUL", gblock->guid); 682 dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid);
615 683
616 dev_set_drvdata(&wblock->dev, wblock); 684 wblock->dev.dev.release = wmi_dev_release;
617 685
618 return device_register(&wblock->dev); 686 return device_register(&wblock->dev.dev);
619} 687}
620 688
621static void wmi_free_devices(struct acpi_device *device) 689static void wmi_free_devices(struct acpi_device *device)
@@ -626,8 +694,8 @@ static void wmi_free_devices(struct acpi_device *device)
626 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { 694 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
627 if (wblock->acpi_device == device) { 695 if (wblock->acpi_device == device) {
628 list_del(&wblock->list); 696 list_del(&wblock->list);
629 if (wblock->dev.class) 697 if (wblock->dev.dev.bus)
630 device_unregister(&wblock->dev); 698 device_unregister(&wblock->dev.dev);
631 else 699 else
632 kfree(wblock); 700 kfree(wblock);
633 } 701 }
@@ -659,7 +727,7 @@ static bool guid_already_parsed(struct acpi_device *device,
659/* 727/*
660 * Parse the _WDG method for the GUID data blocks 728 * Parse the _WDG method for the GUID data blocks
661 */ 729 */
662static int parse_wdg(struct acpi_device *device) 730static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
663{ 731{
664 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 732 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
665 union acpi_object *obj; 733 union acpi_object *obj;
@@ -703,7 +771,8 @@ static int parse_wdg(struct acpi_device *device)
703 for device creation. 771 for device creation.
704 */ 772 */
705 if (!guid_already_parsed(device, gblock[i].guid)) { 773 if (!guid_already_parsed(device, gblock[i].guid)) {
706 retval = wmi_create_device(&gblock[i], wblock, device); 774 retval = wmi_create_device(wmi_bus_dev, &gblock[i],
775 wblock, device);
707 if (retval) { 776 if (retval) {
708 wmi_free_devices(device); 777 wmi_free_devices(device);
709 goto out_free_pointer; 778 goto out_free_pointer;
@@ -803,12 +872,15 @@ static int acpi_wmi_remove(struct acpi_device *device)
803 acpi_remove_address_space_handler(device->handle, 872 acpi_remove_address_space_handler(device->handle,
804 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); 873 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
805 wmi_free_devices(device); 874 wmi_free_devices(device);
875 device_unregister((struct device *)acpi_driver_data(device));
876 device->driver_data = NULL;
806 877
807 return 0; 878 return 0;
808} 879}
809 880
810static int acpi_wmi_add(struct acpi_device *device) 881static int acpi_wmi_add(struct acpi_device *device)
811{ 882{
883 struct device *wmi_bus_dev;
812 acpi_status status; 884 acpi_status status;
813 int error; 885 int error;
814 886
@@ -821,14 +893,25 @@ static int acpi_wmi_add(struct acpi_device *device)
821 return -ENODEV; 893 return -ENODEV;
822 } 894 }
823 895
824 error = parse_wdg(device); 896 wmi_bus_dev = device_create(&wmi_bus_class, &device->dev, MKDEV(0, 0),
897 NULL, "wmi_bus-%s", dev_name(&device->dev));
898 if (IS_ERR(wmi_bus_dev)) {
899 error = PTR_ERR(wmi_bus_dev);
900 goto err_remove_handler;
901 }
902 device->driver_data = wmi_bus_dev;
903
904 error = parse_wdg(wmi_bus_dev, device);
825 if (error) { 905 if (error) {
826 pr_err("Failed to parse WDG method\n"); 906 pr_err("Failed to parse WDG method\n");
827 goto err_remove_handler; 907 goto err_remove_busdev;
828 } 908 }
829 909
830 return 0; 910 return 0;
831 911
912err_remove_busdev:
913 device_unregister(wmi_bus_dev);
914
832err_remove_handler: 915err_remove_handler:
833 acpi_remove_address_space_handler(device->handle, 916 acpi_remove_address_space_handler(device->handle,
834 ACPI_ADR_SPACE_EC, 917 ACPI_ADR_SPACE_EC,
@@ -837,6 +920,22 @@ err_remove_handler:
837 return error; 920 return error;
838} 921}
839 922
923int __must_check __wmi_driver_register(struct wmi_driver *driver,
924 struct module *owner)
925{
926 driver->driver.owner = owner;
927 driver->driver.bus = &wmi_bus_type;
928
929 return driver_register(&driver->driver);
930}
931EXPORT_SYMBOL(__wmi_driver_register);
932
933void wmi_driver_unregister(struct wmi_driver *driver)
934{
935 driver_unregister(&driver->driver);
936}
937EXPORT_SYMBOL(wmi_driver_unregister);
938
840static int __init acpi_wmi_init(void) 939static int __init acpi_wmi_init(void)
841{ 940{
842 int error; 941 int error;
@@ -844,24 +943,36 @@ static int __init acpi_wmi_init(void)
844 if (acpi_disabled) 943 if (acpi_disabled)
845 return -ENODEV; 944 return -ENODEV;
846 945
847 error = class_register(&wmi_class); 946 error = class_register(&wmi_bus_class);
848 if (error) 947 if (error)
849 return error; 948 return error;
850 949
950 error = bus_register(&wmi_bus_type);
951 if (error)
952 goto err_unreg_class;
953
851 error = acpi_bus_register_driver(&acpi_wmi_driver); 954 error = acpi_bus_register_driver(&acpi_wmi_driver);
852 if (error) { 955 if (error) {
853 pr_err("Error loading mapper\n"); 956 pr_err("Error loading mapper\n");
854 class_unregister(&wmi_class); 957 goto err_unreg_bus;
855 return error;
856 } 958 }
857 959
858 return 0; 960 return 0;
961
962err_unreg_class:
963 class_unregister(&wmi_bus_class);
964
965err_unreg_bus:
966 bus_unregister(&wmi_bus_type);
967
968 return error;
859} 969}
860 970
861static void __exit acpi_wmi_exit(void) 971static void __exit acpi_wmi_exit(void)
862{ 972{
863 acpi_bus_unregister_driver(&acpi_wmi_driver); 973 acpi_bus_unregister_driver(&acpi_wmi_driver);
864 class_unregister(&wmi_class); 974 class_unregister(&wmi_bus_class);
975 bus_unregister(&wmi_bus_type);
865} 976}
866 977
867subsys_initcall(acpi_wmi_init); 978subsys_initcall(acpi_wmi_init);