diff options
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 = { |