From 4fd5556608bfa9c2bf276fc115ef04288331aded Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 29 Apr 2023 12:38:41 +0200 Subject: ACPI: button: Add lid disable DMI quirk for Nextbook Ares 8A The LID0 device on the Nextbook Ares 8A tablet always reports lid closed causing userspace to suspend the device as soon as booting is complete. Add a DMI quirk to disable the broken lid functionality. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/acpi/button.c') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 475e1eddfa3b..ef77c14c72a9 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -77,6 +77,15 @@ static const struct dmi_system_id dmi_lid_quirks[] = { }, .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED, }, + { + /* Nextbook Ares 8A tablet, _LID device always reports lid closed */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"), + DMI_MATCH(DMI_BIOS_VERSION, "M882"), + }, + .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED, + }, { /* * Lenovo Yoga 9 14ITL5, initial notification of the LID device -- cgit v1.2.3 From 0d51157dfaac05ea66616d8a250dce04bef49a4f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 4 Jun 2023 17:19:06 +0200 Subject: ACPI: button: Eliminate the driver notify callback Rework the ACPI button driver to install notify handlers or fixed event handlers for the devices it binds to by itself, reduce the indentation level in its notify handler routine and drop its notify callback. This will allow acpi_device_install_notify_handler() and acpi_device_remove_notify_handler() to be simplified going forward and it will allow the driver to use different notify handlers for the lid and for the power and sleep buttons. Signed-off-by: Rafael J. Wysocki Reviewed-by: Michal Wilczynski --- drivers/acpi/button.c | 140 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 96 insertions(+), 44 deletions(-) (limited to 'drivers/acpi/button.c') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 475e1eddfa3b..d9e51001ec91 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -126,7 +126,6 @@ static const struct dmi_system_id dmi_lid_quirks[] = { static int acpi_button_add(struct acpi_device *device); static void acpi_button_remove(struct acpi_device *device); -static void acpi_button_notify(struct acpi_device *device, u32 event); #ifdef CONFIG_PM_SLEEP static int acpi_button_suspend(struct device *dev); @@ -144,7 +143,6 @@ static struct acpi_driver acpi_button_driver = { .ops = { .add = acpi_button_add, .remove = acpi_button_remove, - .notify = acpi_button_notify, }, .drv.pm = &acpi_button_pm, }; @@ -400,45 +398,55 @@ static void acpi_lid_initialize_state(struct acpi_device *device) button->lid_state_initialized = true; } -static void acpi_button_notify(struct acpi_device *device, u32 event) +static void acpi_button_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_button *button = acpi_driver_data(device); + struct acpi_device *device = data; + struct acpi_button *button; struct input_dev *input; + int keycode; - switch (event) { - case ACPI_FIXED_HARDWARE_EVENT: - event = ACPI_BUTTON_NOTIFY_STATUS; - fallthrough; - case ACPI_BUTTON_NOTIFY_STATUS: - input = button->input; - if (button->type == ACPI_BUTTON_TYPE_LID) { - if (button->lid_state_initialized) - acpi_lid_update_state(device, true); - } else { - int keycode; - - acpi_pm_wakeup_event(&device->dev); - if (button->suspended) - break; - - 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); - - acpi_bus_generate_netlink_event( - device->pnp.device_class, - dev_name(&device->dev), - event, ++button->pushed); - } - break; - default: + if (event != ACPI_BUTTON_NOTIFY_STATUS) { acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", event); - break; + return; } + + button = acpi_driver_data(device); + + if (button->type == ACPI_BUTTON_TYPE_LID) { + if (button->lid_state_initialized) + acpi_lid_update_state(device, true); + + return; + } + + acpi_pm_wakeup_event(&device->dev); + + if (button->suspended) + return; + + 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); + + acpi_bus_generate_netlink_event(device->pnp.device_class, + dev_name(&device->dev), + event, ++button->pushed); +} + +static void acpi_button_notify_run(void *data) +{ + acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data); +} + +static u32 acpi_button_event(void *data) +{ + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_button_notify_run, data); + return ACPI_INTERRUPT_HANDLED; } #ifdef CONFIG_PM_SLEEP @@ -483,8 +491,9 @@ static int acpi_button_add(struct acpi_device *device) struct acpi_button *button; struct input_dev *input; const char *hid = acpi_device_hid(device); + acpi_status status; char *name, *class; - int error; + int error = 0; if (!strcmp(hid, ACPI_BUTTON_HID_LID) && lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED) @@ -526,12 +535,15 @@ static int acpi_button_add(struct acpi_device *device) } else { pr_info("Unsupported hid [%s]\n", hid); error = -ENODEV; - goto err_free_input; } - error = acpi_button_add_fs(device); - if (error) - goto err_free_input; + if (!error) + error = acpi_button_add_fs(device); + + if (error) { + input_free_device(input); + goto err_free_button; + } snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); @@ -559,6 +571,30 @@ static int acpi_button_add(struct acpi_device *device) error = input_register_device(input); if (error) goto err_remove_fs; + + switch (device->device_type) { + case ACPI_BUS_TYPE_POWER_BUTTON: + status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + acpi_button_event, + device); + break; + case ACPI_BUS_TYPE_SLEEP_BUTTON: + status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + acpi_button_event, + device); + break; + default: + status = acpi_install_notify_handler(device->handle, + ACPI_DEVICE_NOTIFY, + acpi_button_notify, + device); + break; + } + if (ACPI_FAILURE(status)) { + error = -ENODEV; + goto err_input_unregister; + } + if (button->type == ACPI_BUTTON_TYPE_LID) { /* * This assumes there's only one lid device, or if there are @@ -571,11 +607,11 @@ static int acpi_button_add(struct acpi_device *device) pr_info("%s [%s]\n", name, acpi_device_bid(device)); return 0; - err_remove_fs: +err_input_unregister: + input_unregister_device(input); +err_remove_fs: acpi_button_remove_fs(device); - err_free_input: - input_free_device(input); - err_free_button: +err_free_button: kfree(button); return error; } @@ -584,6 +620,22 @@ static void acpi_button_remove(struct acpi_device *device) { struct acpi_button *button = acpi_driver_data(device); + switch (device->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: + acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_button_notify); + break; + } + acpi_os_wait_events_complete(); + acpi_button_remove_fs(device); input_unregister_device(button->input); kfree(button); -- cgit v1.2.3 From e4e62d5fd8ecb0ea4174afda654432927d248a8a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 4 Jun 2023 17:20:27 +0200 Subject: ACPI: button: Use different notify handlers for lid and buttons Since the lid handling in acpi_button_notify() is special, introduce acpi_lid_notify() specifically for handling lid notifications. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'drivers/acpi/button.c') diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index d9e51001ec91..952ecfa1cf85 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -398,12 +398,10 @@ static void acpi_lid_initialize_state(struct acpi_device *device) button->lid_state_initialized = true; } -static void acpi_button_notify(acpi_handle handle, u32 event, void *data) +static void acpi_lid_notify(acpi_handle handle, u32 event, void *data) { struct acpi_device *device = data; struct acpi_button *button; - struct input_dev *input; - int keycode; if (event != ACPI_BUTTON_NOTIFY_STATUS) { acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", @@ -412,16 +410,28 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data) } button = acpi_driver_data(device); + if (!button->lid_state_initialized) + return; - if (button->type == ACPI_BUTTON_TYPE_LID) { - if (button->lid_state_initialized) - acpi_lid_update_state(device, true); + acpi_lid_update_state(device, true); +} +static void acpi_button_notify(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *device = data; + struct acpi_button *button; + struct input_dev *input; + int keycode; + + if (event != ACPI_BUTTON_NOTIFY_STATUS) { + acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", + event); return; } acpi_pm_wakeup_event(&device->dev); + button = acpi_driver_data(device); if (button->suspended) return; @@ -488,6 +498,7 @@ static int acpi_lid_input_open(struct input_dev *input) static int acpi_button_add(struct acpi_device *device) { + acpi_notify_handler handler; struct acpi_button *button; struct input_dev *input; const char *hid = acpi_device_hid(device); @@ -517,17 +528,20 @@ static int acpi_button_add(struct acpi_device *device) if (!strcmp(hid, ACPI_BUTTON_HID_POWER) || !strcmp(hid, ACPI_BUTTON_HID_POWERF)) { button->type = ACPI_BUTTON_TYPE_POWER; + handler = acpi_button_notify; strcpy(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; strcpy(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; + handler = acpi_lid_notify; strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID); sprintf(class, "%s/%s", ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); @@ -585,8 +599,7 @@ static int acpi_button_add(struct acpi_device *device) break; default: status = acpi_install_notify_handler(device->handle, - ACPI_DEVICE_NOTIFY, - acpi_button_notify, + ACPI_DEVICE_NOTIFY, handler, device); break; } @@ -631,7 +644,9 @@ static void acpi_button_remove(struct acpi_device *device) break; default: acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, - acpi_button_notify); + button->type == ACPI_BUTTON_TYPE_LID ? + acpi_lid_notify : + acpi_button_notify); break; } acpi_os_wait_events_complete(); -- cgit v1.2.3