aboutsummaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorGravatar Armin Wolf <W_Armin@gmx.de> 2024-02-19 12:59:15 +0100
committerGravatar Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> 2024-02-27 14:44:14 +0200
commit4f299135d5668f56be270d224d41eb83d2002038 (patch)
treed67c61c5ee6ba4268de2143c70f3907dedeb2d78 /drivers/platform
parentplatform/x86/fujitsu-laptop: Add battery charge control support (diff)
downloadlinux-4f299135d5668f56be270d224d41eb83d2002038.tar.gz
linux-4f299135d5668f56be270d224d41eb83d2002038.tar.bz2
linux-4f299135d5668f56be270d224d41eb83d2002038.zip
platform/x86: wmi: Prevent incompatible event driver from probing
If a WMI event driver has no_notify_data set, then it indicates support for WMI events which provide no notify data, otherwise the notify() callback expects a valid ACPI object as notify data. However if a WMI event driver which requires notify data is bound to a WMI event device which cannot retrieve such data due to the _WED ACPI method being absent, then the driver will be dysfunctional since all WMI events will be dropped due to the missing notify data. Fix this by not allowing such WMI event drivers to bind to WMI event devices which do not support retrieving of notify data. Also reword the description of no_notify_data a bit. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Link: https://lore.kernel.org/r/20240219115919.16526-2-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/wmi.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 5a613b06b269..8fb90b726f50 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -57,6 +57,7 @@ static_assert(__alignof__(struct guid_block) == 1);
enum { /* wmi_block flags */
WMI_READ_TAKES_NO_ARGS,
+ WMI_NO_EVENT_DATA,
};
struct wmi_block {
@@ -869,6 +870,11 @@ static int wmi_dev_probe(struct device *dev)
struct wmi_driver *wdriver = drv_to_wdrv(dev->driver);
int ret = 0;
+ if (wdriver->notify) {
+ if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && !wdriver->no_notify_data)
+ return -ENODEV;
+ }
+
if (ACPI_FAILURE(wmi_method_enable(wblock, true)))
dev_warn(dev, "failed to enable device -- probing anyway\n");
@@ -1094,6 +1100,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
const struct guid_block *gblock;
+ bool event_data_available;
struct wmi_block *wblock;
union acpi_object *obj;
acpi_status status;
@@ -1113,6 +1120,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
return -ENXIO;
}
+ event_data_available = acpi_has_method(device->handle, "_WED");
gblock = (const struct guid_block *)obj->buffer.pointer;
total = obj->buffer.length / sizeof(struct guid_block);
@@ -1131,6 +1139,8 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
wblock->acpi_device = device;
wblock->gblock = gblock[i];
+ if (gblock[i].flags & ACPI_WMI_EVENT && !event_data_available)
+ set_bit(WMI_NO_EVENT_DATA, &wblock->flags);
retval = wmi_create_device(wmi_bus_dev, wblock, device);
if (retval) {