1 // SPDX-License-Identifier: GPL-2.0-or-later 2 #include <linux/module.h> 3 #include <linux/sched/signal.h> 4 #include <linux/acpi.h> 5 #include <acpi/button.h> 6 7 MODULE_AUTHOR("Josh Triplett"); 8 MODULE_DESCRIPTION("ACPI Tiny Power Button Driver"); 9 MODULE_LICENSE("GPL"); 10 11 static int power_signal __read_mostly = CONFIG_ACPI_TINY_POWER_BUTTON_SIGNAL; 12 module_param(power_signal, int, 0644); 13 MODULE_PARM_DESC(power_signal, "Power button sends this signal to init"); 14 15 static const struct acpi_device_id tiny_power_button_device_ids[] = { 16 { ACPI_BUTTON_HID_POWER, 0 }, 17 { ACPI_BUTTON_HID_POWERF, 0 }, 18 { "", 0 }, 19 }; 20 MODULE_DEVICE_TABLE(acpi, tiny_power_button_device_ids); 21 22 static void acpi_tiny_power_button_notify(acpi_handle handle, u32 event, void *data) 23 { 24 kill_cad_pid(power_signal, 1); 25 } 26 27 static void acpi_tiny_power_button_notify_run(void *not_used) 28 { 29 acpi_tiny_power_button_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, NULL); 30 } 31 32 static u32 acpi_tiny_power_button_event(void *not_used) 33 { 34 acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_tiny_power_button_notify_run, NULL); 35 return ACPI_INTERRUPT_HANDLED; 36 } 37 38 static int acpi_tiny_power_button_add(struct acpi_device *device) 39 { 40 acpi_status status; 41 42 if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) { 43 status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, 44 acpi_tiny_power_button_event, 45 NULL); 46 } else { 47 status = acpi_install_notify_handler(device->handle, 48 ACPI_DEVICE_NOTIFY, 49 acpi_tiny_power_button_notify, 50 NULL); 51 } 52 if (ACPI_FAILURE(status)) 53 return -ENODEV; 54 55 return 0; 56 } 57 58 static void acpi_tiny_power_button_remove(struct acpi_device *device) 59 { 60 if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) { 61 acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, 62 acpi_tiny_power_button_event); 63 } else { 64 acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, 65 acpi_tiny_power_button_notify); 66 } 67 acpi_os_wait_events_complete(); 68 } 69 70 static struct acpi_driver acpi_tiny_power_button_driver = { 71 .name = "tiny-power-button", 72 .class = "tiny-power-button", 73 .ids = tiny_power_button_device_ids, 74 .ops = { 75 .add = acpi_tiny_power_button_add, 76 .remove = acpi_tiny_power_button_remove, 77 }, 78 }; 79 80 module_acpi_driver(acpi_tiny_power_button_driver); 81