diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-08-26 03:15:30 -0400 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2010-10-21 09:36:48 -0400 |
commit | c64eefd48c44fa8145ad1f96edabf4a053fffc49 (patch) | |
tree | 6956b6d86c7253d1cd52233c3818d3041787405b /drivers/platform | |
parent | 614ef4322200086447d5e1f79e8876213c94f499 (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.c | 176 |
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 | ||
694 | static void wmi_dev_free(struct device *dev) | 694 | static 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 | ||
699 | static struct class wmi_class = { | 701 | static 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 | ||
706 | static int wmi_create_devs(void) | 708 | static 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; | 738 | err_free: |
739 | kfree(wblock); | ||
740 | err_out: | ||
741 | return ERR_PTR(error); | ||
739 | } | 742 | } |
740 | 743 | ||
741 | static void wmi_remove_devs(void) | 744 | static 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 | |||
759 | static void wmi_class_exit(void) | ||
760 | { | ||
761 | wmi_remove_devs(); | ||
762 | class_unregister(&wmi_class); | ||
763 | } | ||
764 | |||
765 | static 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 | ||
780 | static bool guid_already_parsed(const char *guid_string) | 753 | static 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 | ||
796 | static 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 | |||
867 | out_free_pointer: | 826 | out_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) | |||
956 | static int acpi_wmi_add(struct acpi_device *device) | 913 | static 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 | ||
982 | static int __init acpi_wmi_init(void) | 939 | static 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 | ||
1006 | static void __exit acpi_wmi_exit(void) | 961 | static 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 | } |