[PATCH 6/6] platform/wmi: Replace .no_notify_data with .min_event_size

From: Armin Wolf

Date: Mon Apr 06 2026 - 17:20:31 EST


WMI drivers using the buffer-based WMI API are expected to reject
undersized event payloads. Extend the WMI driver core to allow
such drivers to specify their minimum supported event payload size.
Also remove the now redundant .no_notify_data field.

Signed-off-by: Armin Wolf <W_Armin@xxxxxx>
---
Documentation/wmi/driver-development-guide.rst | 8 +++++---
drivers/platform/wmi/core.c | 12 ++++++++----
drivers/platform/x86/bitland-mifs-wmi.c | 8 ++------
drivers/platform/x86/dell/dell-wmi-base.c | 1 +
drivers/platform/x86/lenovo/ideapad-laptop.c | 1 +
drivers/platform/x86/lenovo/wmi-camera.c | 1 +
drivers/platform/x86/lenovo/wmi-events.c | 1 +
drivers/platform/x86/lenovo/ymc.c | 1 +
drivers/platform/x86/lenovo/yogabook.c | 2 +-
drivers/platform/x86/redmi-wmi.c | 1 +
drivers/platform/x86/uniwill/uniwill-wmi.c | 1 +
drivers/platform/x86/xiaomi-wmi.c | 1 +
include/linux/wmi.h | 7 +++++--
13 files changed, 29 insertions(+), 16 deletions(-)

diff --git a/Documentation/wmi/driver-development-guide.rst b/Documentation/wmi/driver-development-guide.rst
index 5b94402874c4..387f508d57ad 100644
--- a/Documentation/wmi/driver-development-guide.rst
+++ b/Documentation/wmi/driver-development-guide.rst
@@ -71,7 +71,7 @@ to matching WMI devices using a struct wmi_device_id table:
.remove = foo_remove, /* optional, devres is preferred */
.shutdown = foo_shutdown, /* optional, called during shutdown */
.notify_new = foo_notify, /* optional, for event handling */
- .no_notify_data = true, /* optional, enables events containing no additional data */
+ .min_event_size = X, /* optional, simplifies event payload size verification */
.no_singleton = true, /* required for new WMI drivers */
};
module_wmi_driver(foo_driver);
@@ -142,8 +142,10 @@ right before and after calling its remove() or shutdown() callback.
However WMI driver developers should be aware that multiple WMI events can be received concurrently,
so any locking (if necessary) needs to be provided by the WMI driver itself.

-In order to be able to receive WMI events containing no additional event data,
-the ``no_notify_data`` flag inside struct wmi_driver should be set to ``true``.
+The WMI driver can furthermore instruct the WMI driver core to automatically reject WMI events
+that contain a undersized event payload by populating the ``min_event_size`` field inside
+struct wmi_driver. Setting this field to 0 will thus enable the WMI driver to receive WMI events
+without any event payload.

Take a look at drivers/platform/x86/xiaomi-wmi.c for an example WMI event driver.

diff --git a/drivers/platform/wmi/core.c b/drivers/platform/wmi/core.c
index 87b0e54dde5a..7df50c8238e5 100644
--- a/drivers/platform/wmi/core.c
+++ b/drivers/platform/wmi/core.c
@@ -1040,7 +1040,7 @@ static int wmi_dev_probe(struct device *dev)
}

if (wdriver->notify || wdriver->notify_new) {
- if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && !wdriver->no_notify_data)
+ if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags) && wdriver->min_event_size)
return -ENODEV;
}

@@ -1398,10 +1398,14 @@ static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj
static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)
{
struct wmi_driver *driver = to_wmi_driver(wblock->dev.dev.driver);
+ struct wmi_buffer dummy = {
+ .length = 0,
+ .data = ZERO_SIZE_PTR,
+ };
struct wmi_buffer buffer;
int ret;

- if (!obj && !driver->no_notify_data) {
+ if (!obj && driver->min_event_size) {
dev_warn(&wblock->dev.dev, "Event contains no event data\n");
return;
}
@@ -1411,11 +1415,11 @@ static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)

if (driver->notify_new) {
if (!obj) {
- driver->notify_new(&wblock->dev, NULL);
+ driver->notify_new(&wblock->dev, &dummy);
return;
}

- ret = wmi_unmarshal_acpi_object(obj, &buffer, 0);
+ ret = wmi_unmarshal_acpi_object(obj, &buffer, driver->min_event_size);
if (ret < 0) {
dev_warn(&wblock->dev.dev, "Failed to unmarshal event data: %d\n", ret);
return;
diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c
index 78639407d67e..b0d06a80e89e 100644
--- a/drivers/platform/x86/bitland-mifs-wmi.c
+++ b/drivers/platform/x86/bitland-mifs-wmi.c
@@ -734,15 +734,10 @@ static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
const struct wmi_buffer *buffer)
{
struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev);
- const struct bitland_mifs_event *event;
+ const struct bitland_mifs_event *event = buffer->data;
struct bitland_fan_notify_data fan_data;
u8 brightness;

- if (buffer->length < sizeof(*event))
- return;
-
- event = buffer->data;
-
/* Validate event type */
if (event->event_type != WMI_EVENT_TYPE_HOTKEY)
return;
@@ -830,6 +825,7 @@ static struct wmi_driver bitland_mifs_wmi_driver = {
.pm = pm_sleep_ptr(&bitland_mifs_wmi_pm_ops),
},
.id_table = bitland_mifs_wmi_id_table,
+ .min_event_size = sizeof(struct bitland_mifs_event),
.probe = bitland_mifs_wmi_probe,
.notify_new = bitland_mifs_wmi_notify,
};
diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c
index e7a411ae9ca1..2a5804efd3ea 100644
--- a/drivers/platform/x86/dell/dell-wmi-base.c
+++ b/drivers/platform/x86/dell/dell-wmi-base.c
@@ -825,6 +825,7 @@ static struct wmi_driver dell_wmi_driver = {
.name = "dell-wmi",
},
.id_table = dell_wmi_id_table,
+ .min_event_size = sizeof(u16),
.probe = dell_wmi_probe,
.remove = dell_wmi_remove,
.notify = dell_wmi_notify,
diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c
index ae1ebb071fab..4fbc904f1fc3 100644
--- a/drivers/platform/x86/lenovo/ideapad-laptop.c
+++ b/drivers/platform/x86/lenovo/ideapad-laptop.c
@@ -2340,6 +2340,7 @@ static struct wmi_driver ideapad_wmi_driver = {
.name = "ideapad_wmi",
},
.id_table = ideapad_wmi_ids,
+ .min_event_size = sizeof(u32),
.probe = ideapad_wmi_probe,
.notify = ideapad_wmi_notify,
};
diff --git a/drivers/platform/x86/lenovo/wmi-camera.c b/drivers/platform/x86/lenovo/wmi-camera.c
index eb60fb9a5b3f..89ecbce60bf4 100644
--- a/drivers/platform/x86/lenovo/wmi-camera.c
+++ b/drivers/platform/x86/lenovo/wmi-camera.c
@@ -134,6 +134,7 @@ static struct wmi_driver lenovo_wmi_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = lenovo_wmi_id_table,
+ .min_event_size = sizeof(u8),
.no_singleton = true,
.probe = lenovo_wmi_probe,
.notify = lenovo_wmi_notify,
diff --git a/drivers/platform/x86/lenovo/wmi-events.c b/drivers/platform/x86/lenovo/wmi-events.c
index 0994cd7dd504..4a6a2c82413a 100644
--- a/drivers/platform/x86/lenovo/wmi-events.c
+++ b/drivers/platform/x86/lenovo/wmi-events.c
@@ -183,6 +183,7 @@ static struct wmi_driver lwmi_events_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = lwmi_events_id_table,
+ .min_event_size = sizeof(u32),
.probe = lwmi_events_probe,
.notify = lwmi_events_notify,
.no_singleton = true,
diff --git a/drivers/platform/x86/lenovo/ymc.c b/drivers/platform/x86/lenovo/ymc.c
index 470d53e3c9d2..1b73a55f1b89 100644
--- a/drivers/platform/x86/lenovo/ymc.c
+++ b/drivers/platform/x86/lenovo/ymc.c
@@ -153,6 +153,7 @@ static struct wmi_driver lenovo_ymc_driver = {
.name = "lenovo-ymc",
},
.id_table = lenovo_ymc_wmi_id_table,
+ .min_event_size = sizeof(u32),
.probe = lenovo_ymc_probe,
.notify = lenovo_ymc_notify,
};
diff --git a/drivers/platform/x86/lenovo/yogabook.c b/drivers/platform/x86/lenovo/yogabook.c
index 69887de36c9b..1a4b2ab1f35d 100644
--- a/drivers/platform/x86/lenovo/yogabook.c
+++ b/drivers/platform/x86/lenovo/yogabook.c
@@ -411,8 +411,8 @@ static struct wmi_driver yogabook_wmi_driver = {
.name = "yogabook-wmi",
.pm = pm_sleep_ptr(&yogabook_pm_ops),
},
- .no_notify_data = true,
.id_table = yogabook_wmi_id_table,
+ .min_event_size = 0,
.probe = yogabook_wmi_probe,
.remove = yogabook_wmi_remove,
.notify = yogabook_wmi_notify,
diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c
index e5cb348e3a39..58898630eda6 100644
--- a/drivers/platform/x86/redmi-wmi.c
+++ b/drivers/platform/x86/redmi-wmi.c
@@ -141,6 +141,7 @@ static struct wmi_driver redmi_wmi_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = redmi_wmi_id_table,
+ .min_event_size = 32,
.probe = redmi_wmi_probe,
.notify = redmi_wmi_notify,
.no_singleton = true,
diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.c b/drivers/platform/x86/uniwill/uniwill-wmi.c
index 31d9c39f14ab..097882f10b1e 100644
--- a/drivers/platform/x86/uniwill/uniwill-wmi.c
+++ b/drivers/platform/x86/uniwill/uniwill-wmi.c
@@ -77,6 +77,7 @@ static struct wmi_driver uniwill_wmi_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.id_table = uniwill_wmi_id_table,
+ .min_event_size = sizeof(u32),
.notify = uniwill_wmi_notify,
.no_singleton = true,
};
diff --git a/drivers/platform/x86/xiaomi-wmi.c b/drivers/platform/x86/xiaomi-wmi.c
index badf9e42e015..3874f3336a0d 100644
--- a/drivers/platform/x86/xiaomi-wmi.c
+++ b/drivers/platform/x86/xiaomi-wmi.c
@@ -83,6 +83,7 @@ static struct wmi_driver xiaomi_wmi_driver = {
.name = "xiaomi-wmi",
},
.id_table = xiaomi_wmi_id_table,
+ .min_event_size = 0,
.probe = xiaomi_wmi_probe,
.notify_new = xiaomi_wmi_notify,
.no_singleton = true,
diff --git a/include/linux/wmi.h b/include/linux/wmi.h
index da94580572a9..2d242575a8b3 100644
--- a/include/linux/wmi.h
+++ b/include/linux/wmi.h
@@ -91,7 +91,7 @@ u8 wmidev_instance_count(struct wmi_device *wdev);
* struct wmi_driver - WMI driver structure
* @driver: Driver model structure
* @id_table: List of WMI GUIDs supported by this driver
- * @no_notify_data: Driver supports WMI events which provide no event data
+ * @min_event_size: Minimum event payload size supported by this driver
* @no_singleton: Driver can be instantiated multiple times
* @probe: Callback for device binding
* @remove: Callback for device unbinding
@@ -101,11 +101,14 @@ u8 wmidev_instance_count(struct wmi_device *wdev);
*
* This represents WMI drivers which handle WMI devices. The data inside the buffer
* passed to the @notify_new callback is guaranteed to be aligned on a 8-byte boundary.
+ * The minimum supported size for said buffer can be specified using @min_event_size.
+ * WMI drivers that still use the deprecated @notify callback can still set @min_event_size
+ * to 0 in order to signal that they support WMI events which provide no event data.
*/
struct wmi_driver {
struct device_driver driver;
const struct wmi_device_id *id_table;
- bool no_notify_data;
+ size_t min_event_size;
bool no_singleton;

int (*probe)(struct wmi_device *wdev, const void *context);
--
2.39.5