[PATCH v2] ACPI: button: Evaluate _PSB to determine power button state

From: liujinlong176

Date: Tue Oct 13 2026 - 21:51:08 EST


From: liujinlong <liujinlong@xxxxxxxxxx>

The ACPI button driver always synthesizes a press followed by an
immediate release upon receiving a 0x80 notify. This prevents
userspace from determining the actual duration of a power button
press.

When the 0x80 notification is received, evaluate the _PSB control
method if present. If _PSB returns 1, report only a key press; if
it returns 0, report only a key release. If _PSB is not available,
fall back to the existing press+release behavior for compatibility
with firmware that does not implement it.

Signed-off-by: liujinlong <liujinlong@xxxxxxxxxx>

--- changes in v2:
- Dropped the new ACPI notify values 0x81/0x82 per Rafael's
feedback, as they would require an ACPI specification update.
- Instead, evaluate the _PSB control method upon receiving the
existing 0x80 notification to determine the real button state.
- No longer touches include/acpi/button.h.
---
drivers/acpi/button.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index cdbb1023a8ee..2d079703899b 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -456,12 +456,25 @@ static void acpi_lid_notify(acpi_handle handle, u32 event, void *data)
acpi_lid_update_state(button, true);
}

+static int acpi_button_evaluate_state(acpi_handle handle)
+{
+ unsigned long long state;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(handle, "_PSB", NULL, &state);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ return !!state;
+}
+
static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_button *button = data;
struct acpi_device *device = button->adev;
struct input_dev *input;
int keycode;
+ int state;

switch (event) {
case ACPI_BUTTON_NOTIFY_STATUS:
@@ -482,10 +495,18 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
input = button->input;
keycode = test_bit(KEY_SLEEP, input->keybit) ? KEY_SLEEP : KEY_POWER;

- input_report_key(input, keycode, 1);
- input_sync(input);
- input_report_key(input, keycode, 0);
- input_sync(input);
+ state = acpi_button_evaluate_state(device->handle);
+ if (state < 0) {
+ /* No _PSB method, synthesize a press+release */
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+ } else {
+ /* _PSB returns 1 = pressed, 0 = released */
+ input_report_key(input, keycode, state ? 1 : 0);
+ input_sync(input);
+ }

acpi_bus_generate_netlink_event(button->class, dev_name(&device->dev),
event, ++button->pushed);
--
2.25.1


No virus found
Checked by Hillstone Network AntiVirus