tiny-power-button.c 2.2 KB

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