[PATCH] ACPI: button: Report wakeup key only for power button wakeups

Baorui Liu <[email protected]>
Newsgroups org.kernel.vger.linux-acpi,dev.linux.lists.acpica-devel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Commit 16f70feaabe9 ("ACPI: button: trigger wakeup key events")
makes the ACPI power button driver report KEY_WAKEUP from its resume
callback. However, that callback is run whenever the ACPI button device
is resumed, regardless of the actual system wakeup source.

As a result, userspace may receive a KEY_WAKEUP event after resumes
caused by unrelated wakeup sources.

Avoid reporting the input event from acpi_button_resume(). Instead,
report it only when the ACPI fixed power button status indicates that
the power button was the wakeup source.

Fixes: 16f70feaabe9 ("ACPI: button: trigger wakeup key events")
Signed-off-by: Baorui Liu <[email protected]>
---
 drivers/acpi/button.c     | 23 +++++++++++++++--------
 drivers/acpi/sleep.c      | 21 +++++++++++++++++++++
 drivers/acpi/sleep.h      |  1 +
 drivers/acpi/x86/s2idle.c |  4 +++-
 include/acpi/button.h     |  5 +++++
 5 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 3836ee75dd66..700510f6e5d0 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -480,6 +480,21 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
 					event, ++button->pushed);
 }
 
+void acpi_power_button_wakeup(struct acpi_device *device)
+{
+	struct acpi_button *button = acpi_driver_data(device);
+	struct input_dev *input;
+
+	if (button->type == ACPI_BUTTON_TYPE_POWER) {
+		input = button->input;
+		input_report_key(input, KEY_WAKEUP, 1);
+		input_sync(input);
+		input_report_key(input, KEY_WAKEUP, 0);
+		input_sync(input);
+	}
+}
+EXPORT_SYMBOL(acpi_power_button_wakeup);
+
 static void acpi_button_notify_run(void *data)
 {
 	acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data);
@@ -503,7 +518,6 @@ static int acpi_button_suspend(struct device *dev)
 static int acpi_button_resume(struct device *dev)
 {
 	struct acpi_button *button = dev_get_drvdata(dev);
-	struct input_dev *input;
 
 	button->suspended = false;
 	if (button->type == ACPI_BUTTON_TYPE_LID) {
@@ -512,13 +526,6 @@ static int acpi_button_resume(struct device *dev)
 		acpi_lid_initialize_state(button);
 	}
 
-	if (button->type == ACPI_BUTTON_TYPE_POWER) {
-		input = button->input;
-		input_report_key(input, KEY_WAKEUP, 1);
-		input_sync(input);
-		input_report_key(input, KEY_WAKEUP, 0);
-		input_sync(input);
-	}
 	return 0;
 }
 #endif
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 132a9df98471..26bbecd0c166 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -22,6 +22,7 @@
 #include <linux/syscore_ops.h>
 #include <asm/io.h>
 #include <trace/events/power.h>
+#include <acpi/button.h>
 
 #include "internal.h"
 #include "sleep.h"
@@ -518,6 +519,7 @@ static void acpi_pm_finish(void)
 						    NULL, -1);
 	if (pwr_btn_adev) {
 		pm_wakeup_event(&pwr_btn_adev->dev, 0);
+		acpi_power_button_wakeup(pwr_btn_adev);
 		acpi_dev_put(pwr_btn_adev);
 	}
 }
@@ -818,6 +820,24 @@ bool acpi_s2idle_wake(void)
 	return false;
 }
 
+void acpi_s2idle_restore_check_powerkey(void)
+{
+	struct acpi_device *pwr_btn_adev;
+	acpi_event_status pwr_btn_status = ACPI_EVENT_FLAG_DISABLED;
+
+	acpi_get_event_status(ACPI_EVENT_POWER_BUTTON, &pwr_btn_status);
+
+	if (pwr_btn_status & ACPI_EVENT_FLAG_STATUS_SET) {
+		pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF,
+							    NULL, -1);
+		if (pwr_btn_adev) {
+			pm_wakeup_event(&pwr_btn_adev->dev, 0);
+			acpi_power_button_wakeup(pwr_btn_adev);
+			acpi_dev_put(pwr_btn_adev);
+		}
+	}
+}
+
 void acpi_s2idle_restore(void)
 {
 	/*
@@ -849,6 +869,7 @@ static const struct platform_s2idle_ops acpi_s2idle_ops = {
 	.begin = acpi_s2idle_begin,
 	.prepare = acpi_s2idle_prepare,
 	.wake = acpi_s2idle_wake,
+	.restore_early = acpi_s2idle_restore_check_powerkey,
 	.restore = acpi_s2idle_restore,
 	.end = acpi_s2idle_end,
 };
diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h
index 9c3cb109c5d2..50382c90446c 100644
--- a/drivers/acpi/sleep.h
+++ b/drivers/acpi/sleep.h
@@ -18,6 +18,7 @@ static inline acpi_status acpi_set_waking_vector(u32 wakeup_address)
 extern int acpi_s2idle_begin(void);
 extern int acpi_s2idle_prepare(void);
 extern bool acpi_s2idle_wake(void);
+extern void acpi_s2idle_restore_check_powerkey(void);
 extern void acpi_s2idle_restore(void);
 extern void acpi_s2idle_end(void);
 
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index b6b1dd76a06b..ce6663c1ef70 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -598,8 +598,10 @@ static void acpi_s2idle_restore_early_lps0(void)
 {
 	struct acpi_s2idle_dev_ops *handler;
 
-	if (!lps0_device_handle || sleep_no_lps0)
+	if (!lps0_device_handle || sleep_no_lps0) {
+		acpi_s2idle_restore_check_powerkey();
 		return;
+	}
 
 	list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node)
 		if (handler->restore)
diff --git a/include/acpi/button.h b/include/acpi/button.h
index af2fce5d2ee3..3cbf3272371e 100644
--- a/include/acpi/button.h
+++ b/include/acpi/button.h
@@ -8,11 +8,16 @@
 
 #if IS_ENABLED(CONFIG_ACPI_BUTTON)
 extern int acpi_lid_open(void);
+extern void acpi_power_button_wakeup(struct acpi_device *device);
 #else
 static inline int acpi_lid_open(void)
 {
 	return 1;
 }
+
+static inline void acpi_power_button_wakeup(struct acpi_device *device)
+{
+}
 #endif /* IS_ENABLED(CONFIG_ACPI_BUTTON) */
 
 #endif /* ACPI_BUTTON_H */

base-commit: 4d823c9d06aaa91476b58e56e4d44c4112da2811
-- 
2.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.