Commit | Line | Data |
---|---|---|
a1b93e89 JT |
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 | ||
a1b93e89 JT |
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 | ||
ff1d7aea | 22 | static void acpi_tiny_power_button_notify(acpi_handle handle, u32 event, void *data) |
a1b93e89 | 23 | { |
ff1d7aea | 24 | kill_cad_pid(power_signal, 1); |
a1b93e89 JT |
25 | } |
26 | ||
ff1d7aea | 27 | static void acpi_tiny_power_button_notify_run(void *not_used) |
6c0eb5ba | 28 | { |
ff1d7aea | 29 | acpi_tiny_power_button_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, NULL); |
6c0eb5ba DL |
30 | } |
31 | ||
ff1d7aea | 32 | static u32 acpi_tiny_power_button_event(void *not_used) |
a1b93e89 | 33 | { |
ff1d7aea RW |
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(); | |
a1b93e89 JT |
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 = { | |
ff1d7aea RW |
75 | .add = acpi_tiny_power_button_add, |
76 | .remove = acpi_tiny_power_button_remove, | |
a1b93e89 JT |
77 | }, |
78 | }; | |
79 | ||
907cc9fe | 80 | module_acpi_driver(acpi_tiny_power_button_driver); |