From f8600e0d1ac60e6eac34bc9c7e8cf78f7a4c368f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 18:55:15 +0200 Subject: [PATCH 01/15] ACPI: button: Fix lid_device value leak past driver removal Static variable lid_device is set when the ACPI button driver probes the last lid device (under the assumptions that there will be only one lid device in the system) and never cleared, but in principle it should be reset when the driver unbinds from the lid device pointed to by it. Address that and add locking that is needed to clear and set that variable safely. Fixes: 7e12715ecc47 ("ACPI button: provide lid status functions") Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/6281379.lOV4Wx5bFT@rafael.j.wysocki --- drivers/acpi/button.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index d80276368b81..5df470eea754 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -182,7 +182,6 @@ struct acpi_button { bool gpe_enabled; }; -static struct acpi_device *lid_device; static long lid_init_state = -1; static unsigned long lid_report_interval __read_mostly = 500; @@ -378,9 +377,29 @@ static int acpi_button_remove_fs(struct acpi_button *button) return 0; } +static struct acpi_device *lid_device; +static DEFINE_MUTEX(acpi_lid_lock); + +static void acpi_lid_save(struct acpi_device *adev) +{ + guard(mutex)(&acpi_lid_lock); + + lid_device = adev; +} + +static void acpi_lid_forget(struct acpi_device *adev) +{ + guard(mutex)(&acpi_lid_lock); + + if (lid_device == adev) + lid_device = NULL; +} + /* Driver Interface */ int acpi_lid_open(void) { + guard(mutex)(&acpi_lid_lock); + if (!lid_device) return -ENODEV; @@ -674,7 +693,7 @@ static int acpi_button_probe(struct platform_device *pdev) * This assumes there's only one lid device, or if there are * more we only care about the last one... */ - lid_device = device; + acpi_lid_save(device); } pr_info("%s [%s]\n", name, acpi_device_bid(device)); @@ -696,6 +715,9 @@ static void acpi_button_remove(struct platform_device *pdev) struct acpi_button *button = platform_get_drvdata(pdev); struct acpi_device *adev = button->adev; + if (button->type == ACPI_BUTTON_TYPE_LID) + acpi_lid_forget(adev); + switch (adev->device_type) { case ACPI_BUS_TYPE_POWER_BUTTON: acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, From c64db50c13719a38e0ea290f686aa9cf79dc0342 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 18:55:53 +0200 Subject: [PATCH 02/15] ACPI: button: Pass ACPI handle to acpi_lid_evaluate_state() Make it clear that acpi_lid_evaluate_state() only uses the ACPI handle of the lid by changing its argument to acpi_handle and adjust its callers accordingly. Also save the ACPI handle of the lid, that later may be passed to acpi_lid_evaluate_state(), in a static variable instead of saving a pointer to the ACPI device object containing that handle. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/4747530.LvFx2qVVIh@rafael.j.wysocki --- drivers/acpi/button.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 5df470eea754..0b96db762bea 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -192,12 +192,12 @@ MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events"); static struct proc_dir_entry *acpi_button_dir; static struct proc_dir_entry *acpi_lid_dir; -static int acpi_lid_evaluate_state(struct acpi_device *device) +static int acpi_lid_evaluate_state(acpi_handle lid_handle) { unsigned long long lid_state; acpi_status status; - status = acpi_evaluate_integer(device->handle, "_LID", NULL, &lid_state); + status = acpi_evaluate_integer(lid_handle, "_LID", NULL, &lid_state); if (ACPI_FAILURE(status)) return -ENODEV; @@ -292,7 +292,7 @@ static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq, struct acpi_button *button = seq->private; int state; - state = acpi_lid_evaluate_state(button->adev); + state = acpi_lid_evaluate_state(button->adev->handle); seq_printf(seq, "state: %s\n", state < 0 ? "unsupported" : (state ? "open" : "closed")); return 0; @@ -377,22 +377,22 @@ static int acpi_button_remove_fs(struct acpi_button *button) return 0; } -static struct acpi_device *lid_device; +static acpi_handle saved_lid_handle; static DEFINE_MUTEX(acpi_lid_lock); static void acpi_lid_save(struct acpi_device *adev) { guard(mutex)(&acpi_lid_lock); - lid_device = adev; + saved_lid_handle = adev->handle; } static void acpi_lid_forget(struct acpi_device *adev) { guard(mutex)(&acpi_lid_lock); - if (lid_device == adev) - lid_device = NULL; + if (saved_lid_handle == adev->handle) + saved_lid_handle = NULL; } /* Driver Interface */ @@ -400,20 +400,19 @@ int acpi_lid_open(void) { guard(mutex)(&acpi_lid_lock); - if (!lid_device) + if (!saved_lid_handle) return -ENODEV; - return acpi_lid_evaluate_state(lid_device); + return acpi_lid_evaluate_state(saved_lid_handle); } EXPORT_SYMBOL(acpi_lid_open); static int acpi_lid_update_state(struct acpi_button *button, bool signal_wakeup) { - struct acpi_device *device = button->adev; int state; - state = acpi_lid_evaluate_state(device); + state = acpi_lid_evaluate_state(button->adev->handle); if (state < 0) return state; @@ -516,12 +515,11 @@ 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 acpi_device *device = ACPI_COMPANION(dev); struct input_dev *input; button->suspended = false; if (button->type == ACPI_BUTTON_TYPE_LID) { - button->last_state = !!acpi_lid_evaluate_state(device); + button->last_state = !!acpi_lid_evaluate_state(ACPI_HANDLE(dev)); button->last_time = ktime_get(); acpi_lid_initialize_state(button); } @@ -540,9 +538,8 @@ static int acpi_button_resume(struct device *dev) static int acpi_lid_input_open(struct input_dev *input) { struct acpi_button *button = input_get_drvdata(input); - struct acpi_device *device = button->adev; - button->last_state = !!acpi_lid_evaluate_state(device); + button->last_state = !!acpi_lid_evaluate_state(button->adev->handle); button->last_time = ktime_get(); acpi_lid_initialize_state(button); From 21d822d603ab2a84211651aa39b65e6118add51b Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 18:56:33 +0200 Subject: [PATCH 03/15] ACPI: button: Improve warning message regarding lid state The warning message regarding an unexpected lid state printed by acpi_lid_notify_state() is quite cryptic and there is no information in it to indicate that it is about a platform firmware defect. In fact, it can only be understood after reading the comment below the statement printing it. For this reason, replace it with a more direct one including FW_BUG so its connection to a firmware issue is clearer. While at it, fix up a comment preceding the statement printing the message in question. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/5084775.GXAFRqVoOG@rafael.j.wysocki --- drivers/acpi/button.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 0b96db762bea..d2c2b8105639 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -227,8 +227,8 @@ static int acpi_lid_notify_state(struct acpi_button *button, int state) ms_to_ktime(lid_report_interval)); if (button->last_state == !!state && ktime_after(ktime_get(), next_report)) { - /* Complain the buggy firmware */ - pr_warn_once("The lid device is not compliant to SW_LID.\n"); + /* Complain about the buggy firmware. */ + pr_warn_once(FW_BUG "Unexpected lid state reported by firmware\n"); /* * Send the unreliable complement switch event: From c0e0b84d9e6fd74f9390aa4014dd265947f1c0d7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 18:58:13 +0200 Subject: [PATCH 04/15] ACPI: button: Use bool for representing boolean values Change the data type of the last_state field in struct acpi_button and the data type of the acpi_lid_notify_state() second argument to bool because they both are used for storing boolean values. Update the callers of acpi_lid_notify_state() accordingly and while at it, remove the unnecessary (void) cast from the acpi_lid_update_state() call in acpi_lid_initialize_state() for consistency. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2274778.irdbgypaU6@rafael.j.wysocki --- drivers/acpi/button.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index d2c2b8105639..21a10da8b60b 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -175,7 +175,7 @@ struct acpi_button { struct input_dev *input; char phys[32]; /* for input device */ unsigned long pushed; - int last_state; + bool last_state; ktime_t last_time; bool suspended; bool lid_state_initialized; @@ -204,7 +204,7 @@ static int acpi_lid_evaluate_state(acpi_handle lid_handle) return lid_state ? 1 : 0; } -static int acpi_lid_notify_state(struct acpi_button *button, int state) +static int acpi_lid_notify_state(struct acpi_button *button, bool state) { struct acpi_device *device = button->adev; ktime_t next_report; @@ -218,14 +218,14 @@ static int acpi_lid_notify_state(struct acpi_button *button, int state) * switch. */ if (lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE || - button->last_state != !!state) + button->last_state != state) do_update = true; else do_update = false; next_report = ktime_add(button->last_time, ms_to_ktime(lid_report_interval)); - if (button->last_state == !!state && + if (button->last_state == state && ktime_after(ktime_get(), next_report)) { /* Complain about the buggy firmware. */ pr_warn_once(FW_BUG "Unexpected lid state reported by firmware\n"); @@ -279,7 +279,7 @@ static int acpi_lid_notify_state(struct acpi_button *button, int state) state ? "open" : "closed"); input_report_switch(button->input, SW_LID, !state); input_sync(button->input); - button->last_state = !!state; + button->last_state = state; button->last_time = ktime_get(); } @@ -426,10 +426,10 @@ static void acpi_lid_initialize_state(struct acpi_button *button) { switch (lid_init_state) { case ACPI_BUTTON_LID_INIT_OPEN: - (void)acpi_lid_notify_state(button, 1); + acpi_lid_notify_state(button, true); break; case ACPI_BUTTON_LID_INIT_METHOD: - (void)acpi_lid_update_state(button, false); + acpi_lid_update_state(button, false); break; case ACPI_BUTTON_LID_INIT_IGNORE: default: From a2a3659829b1062fa86eeecb7cb575fd3ba0338e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 18:59:06 +0200 Subject: [PATCH 05/15] ACPI: button: Eliminate ternary operator from acpi_lid_evaluate_state() The ternary operator in acpi_lid_evaluate_state() is not actually needed because the same result can be achieved by applying the !! operator to the lid_state value, so update the code accordingly. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3055906.e9J7NaK4W3@rafael.j.wysocki --- drivers/acpi/button.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 21a10da8b60b..ae97c83bae2c 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -201,7 +201,7 @@ static int acpi_lid_evaluate_state(acpi_handle lid_handle) if (ACPI_FAILURE(status)) return -ENODEV; - return lid_state ? 1 : 0; + return !!lid_state; } static int acpi_lid_notify_state(struct acpi_button *button, bool state) From 06bc0064ad53be6b8f13b166b2fccbebe9eb6735 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:00:00 +0200 Subject: [PATCH 06/15] ACPI: button: Change return type of two functions to void The return value of acpi_lid_notify_state() is always 0, so change its return type to void. Moreover, the return value of the only caller of that function, acpi_lid_update_state(), is never used, so change its return type to void either. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3429748.44csPzL39Z@rafael.j.wysocki --- drivers/acpi/button.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index ae97c83bae2c..fcb2eed823c1 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -204,7 +204,7 @@ static int acpi_lid_evaluate_state(acpi_handle lid_handle) return !!lid_state; } -static int acpi_lid_notify_state(struct acpi_button *button, bool state) +static void acpi_lid_notify_state(struct acpi_button *button, bool state) { struct acpi_device *device = button->adev; ktime_t next_report; @@ -282,8 +282,6 @@ static int acpi_lid_notify_state(struct acpi_button *button, bool state) button->last_state = state; button->last_time = ktime_get(); } - - return 0; } static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq, @@ -407,19 +405,18 @@ int acpi_lid_open(void) } EXPORT_SYMBOL(acpi_lid_open); -static int acpi_lid_update_state(struct acpi_button *button, - bool signal_wakeup) +static void acpi_lid_update_state(struct acpi_button *button, bool signal_wakeup) { int state; state = acpi_lid_evaluate_state(button->adev->handle); if (state < 0) - return state; + return; if (state && signal_wakeup) acpi_pm_wakeup_event(button->dev); - return acpi_lid_notify_state(button, state); + acpi_lid_notify_state(button, state); } static void acpi_lid_initialize_state(struct acpi_button *button) From d9fa7b95d11d7cdf2930ebac155f7ee8f2d6ebdd Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:00:47 +0200 Subject: [PATCH 07/15] ACPI: button: Eliminate redundant conditional statement Simplify do_update initialization in acpi_lid_notify_state() by assigning the value of the condition it depends on directly to it. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/10868292.nUPlyArG6x@rafael.j.wysocki --- drivers/acpi/button.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index fcb2eed823c1..236eb025bb0d 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -217,12 +217,8 @@ static void acpi_lid_notify_state(struct acpi_button *button, bool state) * So "last_time" is only updated after a timeout or an actual * switch. */ - if (lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE || - button->last_state != state) - do_update = true; - else - do_update = false; - + do_update = lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE || + button->last_state != state; next_report = ktime_add(button->last_time, ms_to_ktime(lid_report_interval)); if (button->last_state == state && From 1ad8cdd308da9f9ff044ac49cbe1a375f96c3404 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:01:41 +0200 Subject: [PATCH 08/15] ACPI: button: Use local pointer to platform device dev field in probe To avoid dereferencing pdev to get to the target platform device's dev field in multiple places in acpi_button_probe(), use a local pointer to that field. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2049596.PYKUYFuaPT@rafael.j.wysocki --- drivers/acpi/button.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 236eb025bb0d..9fe8d212b606 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -541,6 +541,7 @@ static int acpi_lid_input_open(struct input_dev *input) static int acpi_button_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; acpi_notify_handler handler; struct acpi_device *device; struct acpi_button *button; @@ -550,7 +551,7 @@ static int acpi_button_probe(struct platform_device *pdev) const char *hid; int error = 0; - device = ACPI_COMPANION(&pdev->dev); + device = ACPI_COMPANION(dev); if (!device) return -ENODEV; @@ -565,7 +566,7 @@ static int acpi_button_probe(struct platform_device *pdev) platform_set_drvdata(pdev, button); - button->dev = &pdev->dev; + button->dev = dev; button->adev = device; button->input = input = input_allocate_device(); if (!input) { @@ -615,7 +616,7 @@ static int acpi_button_probe(struct platform_device *pdev) input->phys = button->phys; input->id.bustype = BUS_HOST; input->id.product = button->type; - input->dev.parent = &pdev->dev; + input->dev.parent = dev; switch (button->type) { case ACPI_BUTTON_TYPE_POWER: From c16c205aeb16e586f645750153064cf9275aafb2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:03:24 +0200 Subject: [PATCH 09/15] ACPI: button: Rework device verification during probe Instead of manually comparing the primary ID of the device (retuned by _HID) with each of the device IDs supported by the driver, use acpi_match_acpi_device() (which includes the ACPI companion device pointer check against NULL) and store the ACPI button type as driver_data in button_device_ids[], which allows a multi-branch conditional statement to be replaced with a switch () one. However, to continue preventing successful probing of devices that only have one of the supported device IDs in their _CID lists, compare the matched device ID with the primary ID of the device and return an error if they don't match. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/7960518.EvYhyI6sBW@rafael.j.wysocki [ rjw: Fixed button memory leak on probe failure ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 84 ++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 9fe8d212b606..00c56f840744 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -59,11 +59,11 @@ MODULE_DESCRIPTION("ACPI Button Driver"); MODULE_LICENSE("GPL"); static const struct acpi_device_id button_device_ids[] = { - {ACPI_BUTTON_HID_LID, 0}, - {ACPI_BUTTON_HID_SLEEP, 0}, - {ACPI_BUTTON_HID_SLEEPF, 0}, - {ACPI_BUTTON_HID_POWER, 0}, - {ACPI_BUTTON_HID_POWERF, 0}, + {ACPI_BUTTON_HID_LID, ACPI_BUTTON_TYPE_LID}, + {ACPI_BUTTON_HID_SLEEP, ACPI_BUTTON_TYPE_SLEEP}, + {ACPI_BUTTON_HID_SLEEPF, ACPI_BUTTON_TYPE_SLEEP}, + {ACPI_BUTTON_HID_POWER, ACPI_BUTTON_TYPE_POWER}, + {ACPI_BUTTON_HID_POWERF, ACPI_BUTTON_TYPE_POWER}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, button_device_ids); @@ -542,22 +542,23 @@ static int acpi_lid_input_open(struct input_dev *input) static int acpi_button_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct acpi_device *device = ACPI_COMPANION(dev); + const struct acpi_device_id *id; acpi_notify_handler handler; - struct acpi_device *device; struct acpi_button *button; struct input_dev *input; acpi_status status; char *name, *class; - const char *hid; + u8 button_type; int error = 0; - device = ACPI_COMPANION(dev); - if (!device) - return -ENODEV; + id = acpi_match_acpi_device(button_device_ids, device); + if (!id || strcmp(acpi_device_hid(device), id->id)) + return dev_err_probe(dev, -ENODEV, "Unsupported device\n"); - hid = acpi_device_hid(device); - if (!strcmp(hid, ACPI_BUTTON_HID_LID) && - lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED) + button_type = id->driver_data; + if (button_type == ACPI_BUTTON_TYPE_LID && + lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED) return -ENODEV; button = kzalloc_obj(struct acpi_button); @@ -568,57 +569,60 @@ static int acpi_button_probe(struct platform_device *pdev) button->dev = dev; button->adev = device; - button->input = input = input_allocate_device(); + input = input_allocate_device(); if (!input) { error = -ENOMEM; goto err_free_button; } + button->input = input; + button->type = button_type; class = acpi_device_class(device); - if (!strcmp(hid, ACPI_BUTTON_HID_POWER) || - !strcmp(hid, ACPI_BUTTON_HID_POWERF)) { - button->type = ACPI_BUTTON_TYPE_POWER; - handler = acpi_button_notify; - name = ACPI_BUTTON_DEVICE_NAME_POWER; - sprintf(class, "%s/%s", - ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); - } else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) || - !strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) { - button->type = ACPI_BUTTON_TYPE_SLEEP; - handler = acpi_button_notify; - name = ACPI_BUTTON_DEVICE_NAME_SLEEP; - sprintf(class, "%s/%s", - ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); - } else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) { - button->type = ACPI_BUTTON_TYPE_LID; + switch (button_type) { + case ACPI_BUTTON_TYPE_LID: handler = acpi_lid_notify; name = ACPI_BUTTON_DEVICE_NAME_LID; sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); input->open = acpi_lid_input_open; - } else { - pr_info("Unsupported hid [%s]\n", hid); - error = -ENODEV; + break; + + case ACPI_BUTTON_TYPE_POWER: + handler = acpi_button_notify; + name = ACPI_BUTTON_DEVICE_NAME_POWER; + sprintf(class, "%s/%s", + ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); + break; + + case ACPI_BUTTON_TYPE_SLEEP: + handler = acpi_button_notify; + name = ACPI_BUTTON_DEVICE_NAME_SLEEP; + sprintf(class, "%s/%s", + ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); + break; + + default: + input_free_device(input); + error = dev_err_probe(dev, -ENODEV, "Unrecognized button type\n"); + goto err_free_button; } - if (!error) - error = acpi_button_add_fs(button); - + error = acpi_button_add_fs(button); if (error) { input_free_device(input); goto err_free_button; } - snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); + snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id); input->name = name; input->phys = button->phys; input->id.bustype = BUS_HOST; - input->id.product = button->type; + input->id.product = button_type; input->dev.parent = dev; - switch (button->type) { + switch (button_type) { case ACPI_BUTTON_TYPE_POWER: input_set_capability(input, EV_KEY, KEY_POWER); input_set_capability(input, EV_KEY, KEY_WAKEUP); @@ -679,7 +683,7 @@ static int acpi_button_probe(struct platform_device *pdev) goto err_input_unregister; } - if (button->type == ACPI_BUTTON_TYPE_LID) { + if (button_type == ACPI_BUTTON_TYPE_LID) { /* * This assumes there's only one lid device, or if there are * more we only care about the last one... From aa7d6c079958afb37e21bd439fa989b7155c45d4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:04:04 +0200 Subject: [PATCH 10/15] ACPI: button: Drop redundant variable from acpi_button_probe() Local char pointer called "name" in acpi_button_probe() is redundant because its value can be assigned directly to input->name and the latter can be used in the only other place where "name" is read, so get rid of it. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3706239.iIbC2pHGDl@rafael.j.wysocki --- drivers/acpi/button.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 00c56f840744..a8c43f1951cd 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -548,7 +548,7 @@ static int acpi_button_probe(struct platform_device *pdev) struct acpi_button *button; struct input_dev *input; acpi_status status; - char *name, *class; + char *class; u8 button_type; int error = 0; @@ -581,23 +581,23 @@ static int acpi_button_probe(struct platform_device *pdev) switch (button_type) { case ACPI_BUTTON_TYPE_LID: + input->name = ACPI_BUTTON_DEVICE_NAME_LID; handler = acpi_lid_notify; - name = ACPI_BUTTON_DEVICE_NAME_LID; sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); input->open = acpi_lid_input_open; break; case ACPI_BUTTON_TYPE_POWER: + input->name = ACPI_BUTTON_DEVICE_NAME_POWER; handler = acpi_button_notify; - name = ACPI_BUTTON_DEVICE_NAME_POWER; sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); break; case ACPI_BUTTON_TYPE_SLEEP: + input->name = ACPI_BUTTON_DEVICE_NAME_SLEEP; handler = acpi_button_notify; - name = ACPI_BUTTON_DEVICE_NAME_SLEEP; sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); break; @@ -616,7 +616,6 @@ static int acpi_button_probe(struct platform_device *pdev) snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id); - input->name = name; input->phys = button->phys; input->id.bustype = BUS_HOST; input->id.product = button_type; @@ -691,7 +690,7 @@ static int acpi_button_probe(struct platform_device *pdev) acpi_lid_save(device); } - pr_info("%s [%s]\n", name, acpi_device_bid(device)); + pr_info("%s [%s]\n", input->name, acpi_device_bid(device)); return 0; err_input_unregister: From a99d758f2b2c83808348908aab00b06f5043aac0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:05:31 +0200 Subject: [PATCH 11/15] ACPI: button: Merge two switch () statements in acpi_button_probe() Two switch () statements in acpi_button_probe() operate on the same value and the statements between them can be reordered with respect to the second one, so merge them. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/3352815.5fSG56mABF@rafael.j.wysocki --- drivers/acpi/button.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index a8c43f1951cd..0946995c93aa 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -582,14 +582,19 @@ static int acpi_button_probe(struct platform_device *pdev) switch (button_type) { case ACPI_BUTTON_TYPE_LID: input->name = ACPI_BUTTON_DEVICE_NAME_LID; + input_set_capability(input, EV_SW, SW_LID); + input->open = acpi_lid_input_open; + handler = acpi_lid_notify; sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); - input->open = acpi_lid_input_open; break; case ACPI_BUTTON_TYPE_POWER: input->name = ACPI_BUTTON_DEVICE_NAME_POWER; + input_set_capability(input, EV_KEY, KEY_POWER); + input_set_capability(input, EV_KEY, KEY_WAKEUP); + handler = acpi_button_notify; sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); @@ -597,6 +602,8 @@ static int acpi_button_probe(struct platform_device *pdev) case ACPI_BUTTON_TYPE_SLEEP: input->name = ACPI_BUTTON_DEVICE_NAME_SLEEP; + input_set_capability(input, EV_KEY, KEY_SLEEP); + handler = acpi_button_notify; sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); @@ -614,28 +621,14 @@ static int acpi_button_probe(struct platform_device *pdev) goto err_free_button; } - snprintf(button->phys, sizeof(button->phys), "%s/button/input0", id->id); + snprintf(button->phys, sizeof(button->phys), "%s/button/input0", + acpi_device_hid(device)); input->phys = button->phys; input->id.bustype = BUS_HOST; input->id.product = button_type; input->dev.parent = dev; - switch (button_type) { - case ACPI_BUTTON_TYPE_POWER: - input_set_capability(input, EV_KEY, KEY_POWER); - input_set_capability(input, EV_KEY, KEY_WAKEUP); - break; - - case ACPI_BUTTON_TYPE_SLEEP: - input_set_capability(input, EV_KEY, KEY_SLEEP); - break; - - case ACPI_BUTTON_TYPE_LID: - input_set_capability(input, EV_SW, SW_LID); - break; - } - input_set_drvdata(input, button); error = input_register_device(input); if (error) { From b398eee7d98ccd7294ce5a1a7ced65f3d9a6c1d0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:07:14 +0200 Subject: [PATCH 12/15] ACPI: button: Clean up adding and removing lid procfs interface The procfs interface is only used with lid devices which only becomes clear after looking into the function bodies of acpi_button_add_fs() and acpi_button_remove_fs(). Moreover, the only error code returned by the former of these functions is -ENODEV, so the ret local variable in it is redundant, and the return type of the latter one can be changed to void. Accordingly, rename these functions to acpi_button_add_fs() and acpi_button_remove_fs(), respectively, move the button->type checks against ACPI_BUTTON_TYPE_LID from them to their callers, and make code simplifications as per the above. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/1869050.VLH7GnMWUR@rafael.j.wysocki --- drivers/acpi/button.c | 54 ++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 0946995c93aa..b1a6ec2ae8f2 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -292,15 +292,10 @@ static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq, return 0; } -static int acpi_button_add_fs(struct acpi_button *button) +static int acpi_lid_add_fs(struct acpi_button *button) { struct acpi_device *device = button->adev; struct proc_dir_entry *entry = NULL; - int ret = 0; - - /* procfs I/F for ACPI lid device only */ - if (button->type != ACPI_BUTTON_TYPE_LID) - return 0; if (acpi_button_dir || acpi_lid_dir) { pr_info("More than one Lid device found!\n"); @@ -314,33 +309,25 @@ static int acpi_button_add_fs(struct acpi_button *button) /* create /proc/acpi/button/lid */ acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); - if (!acpi_lid_dir) { - ret = -ENODEV; + if (!acpi_lid_dir) goto remove_button_dir; - } /* create /proc/acpi/button/lid/LID/ */ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_lid_dir); - if (!acpi_device_dir(device)) { - ret = -ENODEV; + if (!acpi_device_dir(device)) goto remove_lid_dir; - } /* create /proc/acpi/button/lid/LID/state */ entry = proc_create_single_data(ACPI_BUTTON_FILE_STATE, S_IRUGO, acpi_device_dir(device), acpi_button_state_seq_show, button); - if (!entry) { - ret = -ENODEV; + if (!entry) goto remove_dev_dir; - } -done: - return ret; + return 0; remove_dev_dir: - remove_proc_entry(acpi_device_bid(device), - acpi_lid_dir); + remove_proc_entry(acpi_device_bid(device), acpi_lid_dir); acpi_device_dir(device) = NULL; remove_lid_dir: remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); @@ -348,16 +335,13 @@ static int acpi_button_add_fs(struct acpi_button *button) remove_button_dir: remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); acpi_button_dir = NULL; - goto done; + return -ENODEV; } -static int acpi_button_remove_fs(struct acpi_button *button) +static void acpi_lid_remove_fs(struct acpi_button *button) { struct acpi_device *device = button->adev; - if (button->type != ACPI_BUTTON_TYPE_LID) - return 0; - remove_proc_entry(ACPI_BUTTON_FILE_STATE, acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), @@ -367,8 +351,6 @@ static int acpi_button_remove_fs(struct acpi_button *button) acpi_lid_dir = NULL; remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); acpi_button_dir = NULL; - - return 0; } static acpi_handle saved_lid_handle; @@ -588,6 +570,12 @@ static int acpi_button_probe(struct platform_device *pdev) handler = acpi_lid_notify; sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); + + error = acpi_lid_add_fs(button); + if (error) { + input_free_device(input); + goto err_free_button; + } break; case ACPI_BUTTON_TYPE_POWER: @@ -615,12 +603,6 @@ static int acpi_button_probe(struct platform_device *pdev) goto err_free_button; } - error = acpi_button_add_fs(button); - if (error) { - input_free_device(input); - goto err_free_button; - } - snprintf(button->phys, sizeof(button->phys), "%s/button/input0", acpi_device_hid(device)); @@ -690,7 +672,9 @@ static int acpi_button_probe(struct platform_device *pdev) device_init_wakeup(button->dev, false); input_unregister_device(input); err_remove_fs: - acpi_button_remove_fs(button); + if (button_type == ACPI_BUTTON_TYPE_LID) + acpi_lid_remove_fs(button); + err_free_button: kfree(button); memset(acpi_device_class(device), 0, sizeof(acpi_device_class)); @@ -731,8 +715,10 @@ static void acpi_button_remove(struct platform_device *pdev) device_init_wakeup(button->dev, false); - acpi_button_remove_fs(button); input_unregister_device(button->input); + if (button->type == ACPI_BUTTON_TYPE_LID) + acpi_lid_remove_fs(button); + kfree(button); memset(acpi_device_class(adev), 0, sizeof(acpi_device_class)); From dddc802afd5a895c7db94c5076045dc71156fd56 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:07:57 +0200 Subject: [PATCH 13/15] ACPI: button: Use string literals for generating netlink messages Instead of storing strings that never change later under acpi_device_class(device) and using them for generating netlink messages, use pointers to string literals with the same content. This also allows the clearing of the acpi_device_class(device) area during driver removal and in the probe rollback path to be dropped. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2070791.usQuhbGJ8B@rafael.j.wysocki --- drivers/acpi/button.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index b1a6ec2ae8f2..a77e0b4eb7f8 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -28,14 +28,15 @@ #define ACPI_BUTTON_NOTIFY_WAKE 0x02 #define ACPI_BUTTON_NOTIFY_STATUS 0x80 -#define ACPI_BUTTON_SUBCLASS_POWER "power" +#define ACPI_BUTTON_CLASS_POWER "button/power" #define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button" #define ACPI_BUTTON_TYPE_POWER 0x01 -#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" +#define ACPI_BUTTON_CLASS_SLEEP "button/sleep" #define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button" #define ACPI_BUTTON_TYPE_SLEEP 0x03 +#define ACPI_BUTTON_CLASS_LID "button/lid" #define ACPI_BUTTON_SUBCLASS_LID "lid" #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" #define ACPI_BUTTON_TYPE_LID 0x05 @@ -173,6 +174,7 @@ struct acpi_button { struct device *dev; /* physical button device */ unsigned int type; struct input_dev *input; + const char *class; /* for netlink messages */ char phys[32]; /* for input device */ unsigned long pushed; bool last_state; @@ -462,8 +464,7 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) input_report_key(input, keycode, 0); input_sync(input); - acpi_bus_generate_netlink_event(acpi_device_class(device), - dev_name(&device->dev), + acpi_bus_generate_netlink_event(button->class, dev_name(&device->dev), event, ++button->pushed); } @@ -530,7 +531,6 @@ static int acpi_button_probe(struct platform_device *pdev) struct acpi_button *button; struct input_dev *input; acpi_status status; - char *class; u8 button_type; int error = 0; @@ -559,17 +559,15 @@ static int acpi_button_probe(struct platform_device *pdev) button->input = input; button->type = button_type; - class = acpi_device_class(device); - switch (button_type) { case ACPI_BUTTON_TYPE_LID: + button->class = ACPI_BUTTON_CLASS_LID; + input->name = ACPI_BUTTON_DEVICE_NAME_LID; input_set_capability(input, EV_SW, SW_LID); input->open = acpi_lid_input_open; handler = acpi_lid_notify; - sprintf(class, "%s/%s", - ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); error = acpi_lid_add_fs(button); if (error) { @@ -579,22 +577,22 @@ static int acpi_button_probe(struct platform_device *pdev) break; case ACPI_BUTTON_TYPE_POWER: + button->class = ACPI_BUTTON_CLASS_POWER; + input->name = ACPI_BUTTON_DEVICE_NAME_POWER; input_set_capability(input, EV_KEY, KEY_POWER); input_set_capability(input, EV_KEY, KEY_WAKEUP); handler = acpi_button_notify; - sprintf(class, "%s/%s", - ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); break; case ACPI_BUTTON_TYPE_SLEEP: + button->class = ACPI_BUTTON_CLASS_SLEEP; + input->name = ACPI_BUTTON_DEVICE_NAME_SLEEP; input_set_capability(input, EV_KEY, KEY_SLEEP); handler = acpi_button_notify; - sprintf(class, "%s/%s", - ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); break; default: @@ -677,7 +675,6 @@ static int acpi_button_probe(struct platform_device *pdev) err_free_button: kfree(button); - memset(acpi_device_class(device), 0, sizeof(acpi_device_class)); return error; } @@ -720,8 +717,6 @@ static void acpi_button_remove(struct platform_device *pdev) acpi_lid_remove_fs(button); kfree(button); - - memset(acpi_device_class(adev), 0, sizeof(acpi_device_class)); } static int param_set_lid_init_state(const char *val, From 0da41a4c6aa860128d3f224b904aebe41d6bad9d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:12:19 +0200 Subject: [PATCH 14/15] ACPI: button: Reorganize installing and removing event handlers To facilitate subsequent changes, move the code installing and removing button event handlers into two separate functions called acpi_button_add_event_handler() and acpi_button_remove_event_handler(), respectively, and rearrange it to reduce code duplication. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2714170.Lt9SDvczpP@rafael.j.wysocki --- drivers/acpi/button.c | 155 ++++++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 66 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index a77e0b4eb7f8..a948d046fbcb 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -522,15 +522,99 @@ static int acpi_lid_input_open(struct input_dev *input) return 0; } +static acpi_notify_handler acpi_button_notify_handler(struct acpi_button *button) +{ + if (button->type == ACPI_BUTTON_TYPE_LID) + return acpi_lid_notify; + + return acpi_button_notify; +} + +static void acpi_button_remove_event_handler(struct acpi_button *button) +{ + struct acpi_device *adev = button->adev; + + switch (adev->device_type) { + case ACPI_BUS_TYPE_POWER_BUTTON: + acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + acpi_button_event); + break; + + case ACPI_BUS_TYPE_SLEEP_BUTTON: + acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + acpi_button_event); + break; + + default: + if (button->gpe_enabled) { + dev_dbg(button->dev, "Disabling ACPI GPE%02llx\n", + adev->wakeup.gpe_number); + acpi_disable_gpe(adev->wakeup.gpe_device, + adev->wakeup.gpe_number); + } + acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, + acpi_button_notify_handler(button)); + break; + } + acpi_os_wait_events_complete(); +} + +static int acpi_button_add_fixed_event_handler(u32 event, + struct acpi_button *button) +{ + acpi_status status; + + status = acpi_install_fixed_event_handler(event, acpi_button_event, button); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return 0; +} + +static int acpi_button_add_event_handler(struct acpi_button *button) +{ + struct acpi_device *adev = button->adev; + acpi_status status; + + if (adev->device_type == ACPI_BUS_TYPE_POWER_BUTTON) + return acpi_button_add_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + button); + + if (adev->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) + return acpi_button_add_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + button); + + status = acpi_install_notify_handler(adev->handle, ACPI_ALL_NOTIFY, + acpi_button_notify_handler(button), + button); + if (ACPI_FAILURE(status)) + return -ENODEV; + + if (!adev->wakeup.flags.valid) + return 0; + + /* + * If the wakeup GPE has a handler method, enable it in case it is also + * used for signaling runtime events. + */ + status = acpi_enable_gpe_cond(adev->wakeup.gpe_device, + adev->wakeup.gpe_number, + ACPI_GPE_DISPATCH_METHOD); + button->gpe_enabled = ACPI_SUCCESS(status); + if (button->gpe_enabled) + dev_dbg(button->dev, "Enabled ACPI GPE%02llx\n", + adev->wakeup.gpe_number); + + return 0; +} + static int acpi_button_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acpi_device *device = ACPI_COMPANION(dev); const struct acpi_device_id *id; - acpi_notify_handler handler; struct acpi_button *button; struct input_dev *input; - acpi_status status; u8 button_type; int error = 0; @@ -567,8 +651,6 @@ static int acpi_button_probe(struct platform_device *pdev) input_set_capability(input, EV_SW, SW_LID); input->open = acpi_lid_input_open; - handler = acpi_lid_notify; - error = acpi_lid_add_fs(button); if (error) { input_free_device(input); @@ -582,8 +664,6 @@ static int acpi_button_probe(struct platform_device *pdev) input->name = ACPI_BUTTON_DEVICE_NAME_POWER; input_set_capability(input, EV_KEY, KEY_POWER); input_set_capability(input, EV_KEY, KEY_WAKEUP); - - handler = acpi_button_notify; break; case ACPI_BUTTON_TYPE_SLEEP: @@ -591,8 +671,6 @@ static int acpi_button_probe(struct platform_device *pdev) input->name = ACPI_BUTTON_DEVICE_NAME_SLEEP; input_set_capability(input, EV_KEY, KEY_SLEEP); - - handler = acpi_button_notify; break; default: @@ -618,42 +696,9 @@ static int acpi_button_probe(struct platform_device *pdev) device_init_wakeup(button->dev, true); - switch (device->device_type) { - case ACPI_BUS_TYPE_POWER_BUTTON: - status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_button_event, - button); - break; - case ACPI_BUS_TYPE_SLEEP_BUTTON: - status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_button_event, - button); - break; - default: - status = acpi_install_notify_handler(device->handle, - ACPI_ALL_NOTIFY, handler, - button); - if (ACPI_SUCCESS(status) && device->wakeup.flags.valid) { - acpi_status st; - - /* - * If the wakeup GPE has a handler method, enable it in - * case it is also used for signaling runtime events. - */ - st = acpi_enable_gpe_cond(device->wakeup.gpe_device, - device->wakeup.gpe_number, - ACPI_GPE_DISPATCH_METHOD); - button->gpe_enabled = ACPI_SUCCESS(st); - if (button->gpe_enabled) - dev_dbg(button->dev, "Enabled ACPI GPE%02llx\n", - device->wakeup.gpe_number); - } - break; - } - if (ACPI_FAILURE(status)) { - error = -ENODEV; + error = acpi_button_add_event_handler(button); + if (error) goto err_input_unregister; - } if (button_type == ACPI_BUTTON_TYPE_LID) { /* @@ -686,29 +731,7 @@ static void acpi_button_remove(struct platform_device *pdev) if (button->type == ACPI_BUTTON_TYPE_LID) acpi_lid_forget(adev); - switch (adev->device_type) { - case ACPI_BUS_TYPE_POWER_BUTTON: - acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_button_event); - break; - case ACPI_BUS_TYPE_SLEEP_BUTTON: - acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_button_event); - break; - default: - if (button->gpe_enabled) { - dev_dbg(button->dev, "Disabling ACPI GPE%02llx\n", - adev->wakeup.gpe_number); - acpi_disable_gpe(adev->wakeup.gpe_device, - adev->wakeup.gpe_number); - } - acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, - button->type == ACPI_BUTTON_TYPE_LID ? - acpi_lid_notify : - acpi_button_notify); - break; - } - acpi_os_wait_events_complete(); + acpi_button_remove_event_handler(button); device_init_wakeup(button->dev, false); From ec60aaade71b94a6840b467e656b07f456bf2f60 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 1 Jun 2026 19:12:58 +0200 Subject: [PATCH 15/15] ACPI: button: Switch over to devres-based resource management Switch over the ACPI button driver to devres-based resource management by making the following changes: * Use devm_kzalloc() for allocating button object memory. * Use devm_input_allocate_device() for allocating the input class device object. * Turn acpi_lid_remove_fs() into a devm cleanup action added by devm_acpi_lid_add_fs() which is a new wrapper around acpi_lid_add_fs(). * Add devm_acpi_button_init_wakeup() for initializing the wakeup source and make it add a custom devm action that will automatically remove the wakeup source registered by it. * Turn acpi_button_remove_event_handler() into a devm cleanup action added by devm_acpi_button_add_event_handler() which is a new wrapper around acpi_button_add_event_handler(). No intentional functional impact. Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/2283436.Mh6RI2rZIc@rafael.j.wysocki [ rjw: Rebased and removed unnecessary input device parent assignment ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 109 +++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index a948d046fbcb..3836ee75dd66 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -340,8 +340,9 @@ static int acpi_lid_add_fs(struct acpi_button *button) return -ENODEV; } -static void acpi_lid_remove_fs(struct acpi_button *button) +static void acpi_lid_remove_fs(void *data) { + struct acpi_button *button = data; struct acpi_device *device = button->adev; remove_proc_entry(ACPI_BUTTON_FILE_STATE, @@ -355,6 +356,17 @@ static void acpi_lid_remove_fs(struct acpi_button *button) acpi_button_dir = NULL; } +static int devm_acpi_lid_add_fs(struct device *dev, struct acpi_button *button) +{ + int ret; + + ret = acpi_lid_add_fs(button); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, acpi_lid_remove_fs, button); +} + static acpi_handle saved_lid_handle; static DEFINE_MUTEX(acpi_lid_lock); @@ -530,8 +542,20 @@ static acpi_notify_handler acpi_button_notify_handler(struct acpi_button *button return acpi_button_notify; } -static void acpi_button_remove_event_handler(struct acpi_button *button) +static void acpi_button_wakeup_cleanup(void *data) { + device_init_wakeup(data, false); +} + +static int devm_acpi_button_init_wakeup(struct device *dev) +{ + device_init_wakeup(dev, true); + return devm_add_action_or_reset(dev, acpi_button_wakeup_cleanup, dev); +} + +static void acpi_button_remove_event_handler(void *data) +{ + struct acpi_button *button = data; struct acpi_device *adev = button->adev; switch (adev->device_type) { @@ -608,6 +632,19 @@ static int acpi_button_add_event_handler(struct acpi_button *button) return 0; } +static int devm_acpi_button_add_event_handler(struct device *dev, + struct acpi_button *button) +{ + int ret; + + ret = acpi_button_add_event_handler(button); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, acpi_button_remove_event_handler, + button); +} + static int acpi_button_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -627,7 +664,7 @@ static int acpi_button_probe(struct platform_device *pdev) lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED) return -ENODEV; - button = kzalloc_obj(struct acpi_button); + button = devm_kzalloc(dev, sizeof(*button), GFP_KERNEL); if (!button) return -ENOMEM; @@ -635,11 +672,10 @@ static int acpi_button_probe(struct platform_device *pdev) button->dev = dev; button->adev = device; - input = input_allocate_device(); - if (!input) { - error = -ENOMEM; - goto err_free_button; - } + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + button->input = input; button->type = button_type; @@ -651,11 +687,10 @@ static int acpi_button_probe(struct platform_device *pdev) input_set_capability(input, EV_SW, SW_LID); input->open = acpi_lid_input_open; - error = acpi_lid_add_fs(button); - if (error) { - input_free_device(input); - goto err_free_button; - } + error = devm_acpi_lid_add_fs(dev, button); + if (error) + return error; + break; case ACPI_BUTTON_TYPE_POWER: @@ -674,9 +709,7 @@ static int acpi_button_probe(struct platform_device *pdev) break; default: - input_free_device(input); - error = dev_err_probe(dev, -ENODEV, "Unrecognized button type\n"); - goto err_free_button; + return dev_err_probe(dev, -ENODEV, "Unrecognized button type\n"); } snprintf(button->phys, sizeof(button->phys), "%s/button/input0", @@ -685,20 +718,19 @@ static int acpi_button_probe(struct platform_device *pdev) input->phys = button->phys; input->id.bustype = BUS_HOST; input->id.product = button_type; - input->dev.parent = dev; input_set_drvdata(input, button); error = input_register_device(input); - if (error) { - input_free_device(input); - goto err_remove_fs; - } - - device_init_wakeup(button->dev, true); - - error = acpi_button_add_event_handler(button); if (error) - goto err_input_unregister; + return error; + + error = devm_acpi_button_init_wakeup(dev); + if (error) + return error; + + error = devm_acpi_button_add_event_handler(dev, button); + if (error) + return error; if (button_type == ACPI_BUTTON_TYPE_LID) { /* @@ -709,37 +741,16 @@ static int acpi_button_probe(struct platform_device *pdev) } pr_info("%s [%s]\n", input->name, acpi_device_bid(device)); + return 0; - -err_input_unregister: - device_init_wakeup(button->dev, false); - input_unregister_device(input); -err_remove_fs: - if (button_type == ACPI_BUTTON_TYPE_LID) - acpi_lid_remove_fs(button); - -err_free_button: - kfree(button); - return error; } static void acpi_button_remove(struct platform_device *pdev) { struct acpi_button *button = platform_get_drvdata(pdev); - struct acpi_device *adev = button->adev; if (button->type == ACPI_BUTTON_TYPE_LID) - acpi_lid_forget(adev); - - acpi_button_remove_event_handler(button); - - device_init_wakeup(button->dev, false); - - input_unregister_device(button->input); - if (button->type == ACPI_BUTTON_TYPE_LID) - acpi_lid_remove_fs(button); - - kfree(button); + acpi_lid_forget(button->adev); } static int param_set_lid_init_state(const char *val,