diff options
author | Armin Wolf <W_Armin@gmx.de> | 2024-10-05 23:38:25 +0200 |
---|---|---|
committer | Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> | 2024-10-09 12:04:48 +0300 |
commit | d12586e1072d92070783c854819a0ca8c82c5439 (patch) | |
tree | 5e269c19be1b5049fdb965d482e773c63abffcbf /drivers/platform/x86 | |
parent | 066c779b094b63754e0742ad8675d72d6c0a46f6 (diff) |
platform/x86: wmi: Implement proper shutdown handling
When performing a system shutdown under Windows, all WMI clients are
terminated. This means that the ACPI BIOS might expect all WMI devices
to be disabled when shutting down.
Emulate this behaviour by disabling all active WMI devices during
shutdown. Also introduce a new WMI driver callback to allow WMI drivers
to perform any device-specific actions before disabling the WMI device.
Tested on a Dell Inspiron 3505.
Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://lore.kernel.org/r/20241005213825.701887-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/x86')
-rw-r--r-- | drivers/platform/x86/wmi.c | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 3cbe180c3fc0..a01223c23d10 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -884,6 +884,32 @@ static void wmi_dev_remove(struct device *dev) dev_warn(dev, "failed to disable device\n"); } +static void wmi_dev_shutdown(struct device *dev) +{ + struct wmi_driver *wdriver; + struct wmi_block *wblock; + + if (dev->driver) { + wdriver = drv_to_wdrv(dev->driver); + wblock = dev_to_wblock(dev); + + /* + * Some machines return bogus WMI event data when disabling + * the WMI event. Because of this we must prevent the associated + * WMI driver from receiving new WMI events before disabling it. + */ + down_write(&wblock->notify_lock); + wblock->driver_ready = false; + up_write(&wblock->notify_lock); + + if (wdriver->shutdown) + wdriver->shutdown(to_wmi_device(dev)); + + if (ACPI_FAILURE(wmi_method_enable(wblock, false))) + dev_warn(dev, "Failed to disable device\n"); + } +} + static struct class wmi_bus_class = { .name = "wmi_bus", }; @@ -895,6 +921,7 @@ static const struct bus_type wmi_bus_type = { .uevent = wmi_dev_uevent, .probe = wmi_dev_probe, .remove = wmi_dev_remove, + .shutdown = wmi_dev_shutdown, }; static const struct device_type wmi_type_event = { |