tiny-power-button.c 2.4 KB

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