aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2010-08-26 03:15:30 -0400
committerMatthew Garrett <mjg@redhat.com>2010-10-21 09:36:48 -0400
commitc64eefd48c44fa8145ad1f96edabf4a053fffc49 (patch)
tree6956b6d86c7253d1cd52233c3818d3041787405b /drivers/platform
parent614ef4322200086447d5e1f79e8876213c94f499 (diff)
WMI: embed struct device directly into wmi_block
Instead of creating wmi_blocks and then register corresponding devices on a separate pass do it all in one shot, since lifetime rules for both objects are the same. This also takes care of leaking devices when device_create fails for one of them. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Matthew Garrett <mjg@redhat.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/wmi.c176
1 files changed, 65 insertions, 111 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index b9a60a0aabfd..104b77c87ef5 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -68,7 +68,7 @@ struct wmi_block {
68 acpi_handle handle; 68 acpi_handle handle;
69 wmi_notify_handler handler; 69 wmi_notify_handler handler;
70 void *handler_data; 70 void *handler_data;
71 struct device *dev; 71 struct device dev;
72}; 72};
73 73
74 74
@@ -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/*
@@ -693,7 +693,9 @@ static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
693 693
694static void wmi_dev_free(struct device *dev) 694static void wmi_dev_free(struct device *dev)
695{ 695{
696 kfree(dev); 696 struct wmi_block *wmi_block = container_of(dev, struct wmi_block, dev);
697
698 kfree(wmi_block);
697} 699}
698 700
699static struct class wmi_class = { 701static struct class wmi_class = {
@@ -703,104 +705,60 @@ static struct class wmi_class = {
703 .dev_attrs = wmi_dev_attrs, 705 .dev_attrs = wmi_dev_attrs,
704}; 706};
705 707
706static int wmi_create_devs(void) 708static struct wmi_block *wmi_create_device(const struct guid_block *gblock,
709 acpi_handle handle)
707{ 710{
708 int result;
709 char guid_string[37];
710 struct guid_block *gblock;
711 struct wmi_block *wblock; 711 struct wmi_block *wblock;
712 struct list_head *p; 712 int error;
713 struct device *guid_dev; 713 char guid_string[37];
714 714
715 /* Create devices for all the GUIDs */ 715 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
716 list_for_each(p, &wmi_block_list) { 716 if (!wblock) {
717 wblock = list_entry(p, struct wmi_block, list); 717 error = -ENOMEM;
718 goto err_out;
719 }
718 720
719 guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL); 721 wblock->handle = handle;
720 if (!guid_dev) 722 wblock->gblock = *gblock;
721 return -ENOMEM;
722 723
723 wblock->dev = guid_dev; 724 wblock->dev.class = &wmi_class;
724 725
725 guid_dev->class = &wmi_class; 726 wmi_gtoa(gblock->guid, guid_string);
726 dev_set_drvdata(guid_dev, wblock); 727 dev_set_name(&wblock->dev, guid_string);
727 728
728 gblock = &wblock->gblock; 729 dev_set_drvdata(&wblock->dev, wblock);
729 730
730 wmi_gtoa(gblock->guid, guid_string); 731 error = device_register(&wblock->dev);
731 dev_set_name(guid_dev, guid_string); 732 if (error)
733 goto err_free;
732 734
733 result = device_register(guid_dev); 735 list_add_tail(&wblock->list, &wmi_block_list);
734 if (result) 736 return wblock;
735 return result;
736 }
737 737
738 return 0; 738err_free:
739 kfree(wblock);
740err_out:
741 return ERR_PTR(error);
739} 742}
740 743
741static void wmi_remove_devs(void) 744static void wmi_free_devices(void)
742{ 745{
743 struct guid_block *gblock; 746 struct wmi_block *wblock, *next;
744 struct wmi_block *wblock;
745 struct list_head *p;
746 struct device *guid_dev;
747 747
748 /* Delete devices for all the GUIDs */ 748 /* Delete devices for all the GUIDs */
749 list_for_each(p, &wmi_block_list) { 749 list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
750 wblock = list_entry(p, struct wmi_block, list); 750 device_unregister(&wblock->dev);
751
752 guid_dev = wblock->dev;
753 gblock = &wblock->gblock;
754
755 device_unregister(guid_dev);
756 }
757}
758
759static void wmi_class_exit(void)
760{
761 wmi_remove_devs();
762 class_unregister(&wmi_class);
763}
764
765static int wmi_class_init(void)
766{
767 int ret;
768
769 ret = class_register(&wmi_class);
770 if (ret)
771 return ret;
772
773 ret = wmi_create_devs();
774 if (ret)
775 wmi_class_exit();
776
777 return ret;
778} 751}
779 752
780static bool guid_already_parsed(const char *guid_string) 753static bool guid_already_parsed(const char *guid_string)
781{ 754{
782 struct guid_block *gblock;
783 struct wmi_block *wblock; 755 struct wmi_block *wblock;
784 struct list_head *p;
785
786 list_for_each(p, &wmi_block_list) {
787 wblock = list_entry(p, struct wmi_block, list);
788 gblock = &wblock->gblock;
789 756
790 if (strncmp(gblock->guid, guid_string, 16) == 0) 757 list_for_each_entry(wblock, &wmi_block_list, list)
758 if (strncmp(wblock->gblock.guid, guid_string, 16) == 0)
791 return true; 759 return true;
792 }
793 return false;
794}
795 760
796static void free_wmi_blocks(void) 761 return false;
797{
798 struct wmi_block *wblock, *next;
799
800 list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
801 list_del(&wblock->list);
802 kfree(wblock);
803 }
804} 762}
805 763
806/* 764/*
@@ -814,19 +772,19 @@ static acpi_status parse_wdg(acpi_handle handle)
814 struct wmi_block *wblock; 772 struct wmi_block *wblock;
815 char guid_string[37]; 773 char guid_string[37];
816 acpi_status status; 774 acpi_status status;
775 int retval;
817 u32 i, total; 776 u32 i, total;
818 777
819 status = acpi_evaluate_object(handle, "_WDG", NULL, &out); 778 status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
820
821 if (ACPI_FAILURE(status)) 779 if (ACPI_FAILURE(status))
822 return status; 780 return -ENXIO;
823 781
824 obj = (union acpi_object *) out.pointer; 782 obj = (union acpi_object *) out.pointer;
825 if (!obj) 783 if (!obj)
826 return AE_ERROR; 784 return -ENXIO;
827 785
828 if (obj->type != ACPI_TYPE_BUFFER) { 786 if (obj->type != ACPI_TYPE_BUFFER) {
829 status = AE_ERROR; 787 retval = -ENXIO;
830 goto out_free_pointer; 788 goto out_free_pointer;
831 } 789 }
832 790
@@ -846,31 +804,29 @@ static acpi_status parse_wdg(acpi_handle handle)
846 pr_info("Skipping duplicate GUID %s\n", guid_string); 804 pr_info("Skipping duplicate GUID %s\n", guid_string);
847 continue; 805 continue;
848 } 806 }
807
849 if (debug_dump_wdg) 808 if (debug_dump_wdg)
850 wmi_dump_wdg(&gblock[i]); 809 wmi_dump_wdg(&gblock[i]);
851 810
852 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); 811 wblock = wmi_create_device(&gblock[i], handle);
853 if (!wblock) { 812 if (IS_ERR(wblock)) {
854 status = AE_NO_MEMORY; 813 retval = PTR_ERR(wblock);
855 goto out_free_pointer; 814 wmi_free_devices();
815 break;
856 } 816 }
857 817
858 wblock->gblock = gblock[i];
859 wblock->handle = handle;
860 if (debug_event) { 818 if (debug_event) {
861 wblock->handler = wmi_notify_debug; 819 wblock->handler = wmi_notify_debug;
862 wmi_method_enable(wblock, 1); 820 wmi_method_enable(wblock, 1);
863 } 821 }
864 list_add_tail(&wblock->list, &wmi_block_list);
865 } 822 }
866 823
824 retval = 0;
825
867out_free_pointer: 826out_free_pointer:
868 kfree(out.pointer); 827 kfree(out.pointer);
869 828
870 if (ACPI_FAILURE(status)) 829 return retval;
871 free_wmi_blocks();
872
873 return status;
874} 830}
875 831
876/* 832/*
@@ -949,6 +905,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
949{ 905{
950 acpi_remove_address_space_handler(device->handle, 906 acpi_remove_address_space_handler(device->handle,
951 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler); 907 ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
908 wmi_free_devices();
952 909
953 return 0; 910 return 0;
954} 911}
@@ -956,7 +913,7 @@ static int acpi_wmi_remove(struct acpi_device *device, int type)
956static int acpi_wmi_add(struct acpi_device *device) 913static int acpi_wmi_add(struct acpi_device *device)
957{ 914{
958 acpi_status status; 915 acpi_status status;
959 int result = 0; 916 int error;
960 917
961 status = acpi_install_address_space_handler(device->handle, 918 status = acpi_install_address_space_handler(device->handle,
962 ACPI_ADR_SPACE_EC, 919 ACPI_ADR_SPACE_EC,
@@ -967,47 +924,44 @@ static int acpi_wmi_add(struct acpi_device *device)
967 return -ENODEV; 924 return -ENODEV;
968 } 925 }
969 926
970 status = parse_wdg(device->handle); 927 error = parse_wdg(device->handle);
971 if (ACPI_FAILURE(status)) { 928 if (error) {
972 acpi_remove_address_space_handler(device->handle, 929 acpi_remove_address_space_handler(device->handle,
973 ACPI_ADR_SPACE_EC, 930 ACPI_ADR_SPACE_EC,
974 &acpi_wmi_ec_space_handler); 931 &acpi_wmi_ec_space_handler);
975 pr_err("Failed to parse WDG method\n"); 932 pr_err("Failed to parse WDG method\n");
976 return -ENODEV; 933 return error;
977 } 934 }
978 935
979 return result; 936 return 0;
980} 937}
981 938
982static int __init acpi_wmi_init(void) 939static int __init acpi_wmi_init(void)
983{ 940{
984 int result; 941 int error;
985 942
986 if (acpi_disabled) 943 if (acpi_disabled)
987 return -ENODEV; 944 return -ENODEV;
988 945
989 result = acpi_bus_register_driver(&acpi_wmi_driver); 946 error = class_register(&wmi_class);
990 if (result < 0) { 947 if (error)
991 pr_err("Error loading mapper\n"); 948 return error;
992 return -ENODEV;
993 }
994 949
995 result = wmi_class_init(); 950 error = acpi_bus_register_driver(&acpi_wmi_driver);
996 if (result) { 951 if (error) {
997 acpi_bus_unregister_driver(&acpi_wmi_driver); 952 pr_err("Error loading mapper\n");
998 return result; 953 class_unregister(&wmi_class);
954 return error;
999 } 955 }
1000 956
1001 pr_info("Mapper loaded\n"); 957 pr_info("Mapper loaded\n");
1002
1003 return 0; 958 return 0;
1004} 959}
1005 960
1006static void __exit acpi_wmi_exit(void) 961static void __exit acpi_wmi_exit(void)
1007{ 962{
1008 wmi_class_exit();
1009 acpi_bus_unregister_driver(&acpi_wmi_driver); 963 acpi_bus_unregister_driver(&acpi_wmi_driver);
1010 free_wmi_blocks(); 964 class_unregister(&wmi_class);
1011 965
1012 pr_info("Mapper unloaded\n"); 966 pr_info("Mapper unloaded\n");
1013} 967}