Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ACPI / button: Do not propagate wakeup-from-suspend events

During system suspend mark ACPI buttons (other than the lid) as
"suspended" and if in that state, report wakeup events on button
events, but do not propagate those events up the stack.

This prevents systems from being turned off after a button-triggered
wakeup from the "freeze" sleep state.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=77611
Tested-on: Acer Aspire S5, Toshiba Portege R500
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

+21 -4
+21 -4
drivers/acpi/button.c
··· 79 79 static void acpi_button_notify(struct acpi_device *device, u32 event); 80 80 81 81 #ifdef CONFIG_PM_SLEEP 82 + static int acpi_button_suspend(struct device *dev); 82 83 static int acpi_button_resume(struct device *dev); 83 84 #else 85 + #define acpi_button_suspend NULL 84 86 #define acpi_button_resume NULL 85 87 #endif 86 - static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume); 88 + static SIMPLE_DEV_PM_OPS(acpi_button_pm, acpi_button_suspend, acpi_button_resume); 87 89 88 90 static struct acpi_driver acpi_button_driver = { 89 91 .name = "button", ··· 104 102 struct input_dev *input; 105 103 char phys[32]; /* for input device */ 106 104 unsigned long pushed; 105 + bool suspended; 107 106 }; 108 107 109 108 static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); ··· 296 293 if (button->type == ACPI_BUTTON_TYPE_LID) { 297 294 acpi_lid_send_state(device); 298 295 } else { 299 - int keycode = test_bit(KEY_SLEEP, input->keybit) ? 300 - KEY_SLEEP : KEY_POWER; 296 + int keycode; 301 297 298 + pm_wakeup_event(&device->dev, 0); 299 + if (button->suspended) 300 + break; 301 + 302 + keycode = test_bit(KEY_SLEEP, input->keybit) ? 303 + KEY_SLEEP : KEY_POWER; 302 304 input_report_key(input, keycode, 1); 303 305 input_sync(input); 304 306 input_report_key(input, keycode, 0); 305 307 input_sync(input); 306 308 307 - pm_wakeup_event(&device->dev, 0); 308 309 acpi_bus_generate_netlink_event( 309 310 device->pnp.device_class, 310 311 dev_name(&device->dev), ··· 323 316 } 324 317 325 318 #ifdef CONFIG_PM_SLEEP 319 + static int acpi_button_suspend(struct device *dev) 320 + { 321 + struct acpi_device *device = to_acpi_device(dev); 322 + struct acpi_button *button = acpi_driver_data(device); 323 + 324 + button->suspended = true; 325 + return 0; 326 + } 327 + 326 328 static int acpi_button_resume(struct device *dev) 327 329 { 328 330 struct acpi_device *device = to_acpi_device(dev); 329 331 struct acpi_button *button = acpi_driver_data(device); 330 332 333 + button->suspended = false; 331 334 if (button->type == ACPI_BUTTON_TYPE_LID) 332 335 return acpi_lid_send_state(device); 333 336 return 0;