summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarren Hart (VMware) <dvhart@infradead.org>2017-05-19 22:28:36 -0400
committerDarren Hart (VMware) <dvhart@infradead.org>2017-06-06 13:15:20 -0400
commitfd70da6a6267c91fbdda9c560f098cfd52fba00f (patch)
tree378c9c14573ce622164b455e5fb48c4a80b5cbea
parentf63019861cd1192e546397b13f926876a93450fd (diff)
platform/x86: wmi: Require query for data blocks, rename writable to setable
The Microsoft WMI documentation requires all data blocks to implement the Query Control Method (WQxx). If we encounter a data block not implementing this control method, issue a warning, and ignore the data block. Remove the "readable" attribute as all data blocks must be readable (query-able). Be consistent with the language in the documentation, replace the "writable" attribute with "setable". Simplify (flatten) the control flow of wmi_create_device a bit while we are updating it for the above changes. Signed-off-by: Darren Hart (VMware) <dvhart@infradead.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>
-rw-r--r--drivers/platform/x86/wmi.c117
-rw-r--r--include/linux/wmi.h7
2 files changed, 63 insertions, 61 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 250d7b2398b4..37f6651d1bf7 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -69,7 +69,7 @@ struct wmi_block {
69 wmi_notify_handler handler; 69 wmi_notify_handler handler;
70 void *handler_data; 70 void *handler_data;
71 71
72 bool read_takes_no_args; /* only defined if readable */ 72 bool read_takes_no_args;
73}; 73};
74 74
75 75
@@ -694,28 +694,18 @@ static ssize_t object_id_show(struct device *dev, struct device_attribute *attr,
694} 694}
695static DEVICE_ATTR_RO(object_id); 695static DEVICE_ATTR_RO(object_id);
696 696
697static ssize_t readable_show(struct device *dev, struct device_attribute *attr, 697static ssize_t setable_show(struct device *dev, struct device_attribute *attr,
698 char *buf) 698 char *buf)
699{ 699{
700 struct wmi_device *wdev = dev_to_wdev(dev); 700 struct wmi_device *wdev = dev_to_wdev(dev);
701 701
702 return sprintf(buf, "%d\n", (int)wdev->readable); 702 return sprintf(buf, "%d\n", (int)wdev->setable);
703} 703}
704static DEVICE_ATTR_RO(readable); 704static DEVICE_ATTR_RO(setable);
705
706static ssize_t writeable_show(struct device *dev, struct device_attribute *attr,
707 char *buf)
708{
709 struct wmi_device *wdev = dev_to_wdev(dev);
710
711 return sprintf(buf, "%d\n", (int)wdev->writeable);
712}
713static DEVICE_ATTR_RO(writeable);
714 705
715static struct attribute *wmi_data_attrs[] = { 706static struct attribute *wmi_data_attrs[] = {
716 &dev_attr_object_id.attr, 707 &dev_attr_object_id.attr,
717 &dev_attr_readable.attr, 708 &dev_attr_setable.attr,
718 &dev_attr_writeable.attr,
719 NULL, 709 NULL,
720}; 710};
721ATTRIBUTE_GROUPS(wmi_data); 711ATTRIBUTE_GROUPS(wmi_data);
@@ -833,63 +823,74 @@ static struct device_type wmi_type_data = {
833 .release = wmi_dev_release, 823 .release = wmi_dev_release,
834}; 824};
835 825
836static void wmi_create_device(struct device *wmi_bus_dev, 826static int wmi_create_device(struct device *wmi_bus_dev,
837 const struct guid_block *gblock, 827 const struct guid_block *gblock,
838 struct wmi_block *wblock, 828 struct wmi_block *wblock,
839 struct acpi_device *device) 829 struct acpi_device *device)
840{ 830{
841 wblock->dev.dev.bus = &wmi_bus_type; 831 struct acpi_device_info *info;
842 wblock->dev.dev.parent = wmi_bus_dev; 832 char method[5];
843 833 int result;
844 dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid);
845 834
846 if (gblock->flags & ACPI_WMI_EVENT) { 835 if (gblock->flags & ACPI_WMI_EVENT) {
847 wblock->dev.dev.type = &wmi_type_event; 836 wblock->dev.dev.type = &wmi_type_event;
848 } else if (gblock->flags & ACPI_WMI_METHOD) { 837 goto out_init;
838 }
839
840 if (gblock->flags & ACPI_WMI_METHOD) {
849 wblock->dev.dev.type = &wmi_type_method; 841 wblock->dev.dev.type = &wmi_type_method;
850 } else { 842 goto out_init;
851 struct acpi_device_info *info; 843 }
852 char method[5];
853 int result;
854 844
855 wblock->dev.dev.type = &wmi_type_data; 845 /*
846 * Data Block Query Control Method (WQxx by convention) is
847 * required per the WMI documentation. If it is not present,
848 * we ignore this data block.
849 */
850 strcpy(method, "WQ");
851 strncat(method, wblock->gblock.object_id, 2);
852 result = get_subobj_info(device->handle, method, &info);
853
854 if (result) {
855 dev_warn(wmi_bus_dev,
856 "%s data block query control method not found",
857 method);
858 return result;
859 }
856 860
857 strcpy(method, "WQ"); 861 wblock->dev.dev.type = &wmi_type_data;
858 strncat(method, wblock->gblock.object_id, 2);
859 result = get_subobj_info(device->handle, method, &info);
860 862
861 if (result == 0) { 863 /*
862 wblock->dev.readable = true; 864 * The Microsoft documentation specifically states:
865 *
866 * Data blocks registered with only a single instance
867 * can ignore the parameter.
868 *
869 * ACPICA will get mad at us if we call the method with the wrong number
870 * of arguments, so check what our method expects. (On some Dell
871 * laptops, WQxx may not be a method at all.)
872 */
873 if (info->type != ACPI_TYPE_METHOD || info->param_count == 0)
874 wblock->read_takes_no_args = true;
863 875
864 /* 876 kfree(info);
865 * The Microsoft documentation specifically states:
866 *
867 * Data blocks registered with only a single instance
868 * can ignore the parameter.
869 *
870 * ACPICA will get mad at us if we call the method
871 * with the wrong number of arguments, so check what
872 * our method expects. (On some Dell laptops, WQxx
873 * may not be a method at all.)
874 */
875 if (info->type != ACPI_TYPE_METHOD ||
876 info->param_count == 0)
877 wblock->read_takes_no_args = true;
878 877
879 kfree(info); 878 strcpy(method, "WS");
880 } 879 strncat(method, wblock->gblock.object_id, 2);
880 result = get_subobj_info(device->handle, method, NULL);
881 881
882 strcpy(method, "WS"); 882 if (result == 0)
883 strncat(method, wblock->gblock.object_id, 2); 883 wblock->dev.setable = true;
884 result = get_subobj_info(device->handle, method, NULL);
885 884
886 if (result == 0) { 885 out_init:
887 wblock->dev.writeable = true; 886 wblock->dev.dev.bus = &wmi_bus_type;
888 } 887 wblock->dev.dev.parent = wmi_bus_dev;
889 888
890 } 889 dev_set_name(&wblock->dev.dev, "%pUL", gblock->guid);
891 890
892 device_initialize(&wblock->dev.dev); 891 device_initialize(&wblock->dev.dev);
892
893 return 0;
893} 894}
894 895
895static void wmi_free_devices(struct acpi_device *device) 896static void wmi_free_devices(struct acpi_device *device)
@@ -978,7 +979,11 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
978 wblock->acpi_device = device; 979 wblock->acpi_device = device;
979 wblock->gblock = gblock[i]; 980 wblock->gblock = gblock[i];
980 981
981 wmi_create_device(wmi_bus_dev, &gblock[i], wblock, device); 982 retval = wmi_create_device(wmi_bus_dev, &gblock[i], wblock, device);
983 if (retval) {
984 kfree(wblock);
985 continue;
986 }
982 987
983 list_add_tail(&wblock->list, &wmi_block_list); 988 list_add_tail(&wblock->list, &wmi_block_list);
984 989
diff --git a/include/linux/wmi.h b/include/linux/wmi.h
index a283768afb7e..cd0d7734dc49 100644
--- a/include/linux/wmi.h
+++ b/include/linux/wmi.h
@@ -22,11 +22,8 @@
22struct wmi_device { 22struct wmi_device {
23 struct device dev; 23 struct device dev;
24 24
25 /* 25 /* True for data blocks implementing the Set Control Method */
26 * These are true for data objects that support reads and writes, 26 bool setable;
27 * respectively.
28 */
29 bool readable, writeable;
30}; 27};
31 28
32/* Caller must kfree the result. */ 29/* Caller must kfree the result. */