ACPI: Add new tiny-power-button driver to directly signal init
authorJosh Triplett <josh@joshtriplett.org>
Tue, 11 Feb 2020 23:38:06 +0000 (15:38 -0800)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 13 Feb 2020 22:36:23 +0000 (23:36 +0100)
Virtual machines often use an ACPI power button event to tell the
machine to shut down gracefully.

Provide an extremely lightweight "tiny power button" driver to handle
this event by signaling init directly, rather than running a separate
daemon (such as acpid or systemd-logind) that adds to startup time and
VM image complexity.

The kernel configuration defines the default signal to send init, and
userspace can change this signal via a module parameter.

Suggested-by: "Rafael J. Wysocki" <rafael@kernel.org>
Signed-off-by: Josh Triplett <josh@joshtriplett.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/tiny-power-button.c [new file with mode: 0644]

index cc57bab146b5c23dbbb264874879a3d19df54a57..ce2730d61a8fc8e81cb579c2a0e37fd80c7c0690 100644 (file)
@@ -190,6 +190,30 @@ config ACPI_BUTTON
          To compile this driver as a module, choose M here:
          the module will be called button.
 
+config ACPI_TINY_POWER_BUTTON
+       tristate "Tiny Power Button Driver"
+       depends on !ACPI_BUTTON
+       help
+         This driver provides a tiny alternative to the ACPI Button driver.
+         The tiny power button driver only handles the power button. Rather
+         than notifying userspace via the input layer or a netlink event, this
+         driver directly signals the init process to shut down.
+
+         This driver is particularly suitable for cloud and VM environments,
+         which use a simulated power button to initiate a controlled poweroff,
+         but which may not want to run a separate userspace daemon to process
+         input events.
+
+config ACPI_TINY_POWER_BUTTON_SIGNAL
+       int "Tiny Power Button Signal"
+       depends on ACPI_TINY_POWER_BUTTON
+       default 38
+       help
+         Default signal to send to init in response to the power button.
+
+         Likely values here include 38 (SIGRTMIN+4) to power off, or 2
+         (SIGINT) to simulate Ctrl+Alt+Del.
+
 config ACPI_VIDEO
        tristate "Video"
        depends on X86 && BACKLIGHT_CLASS_DEVICE
index 33fdaf67454e845bffa41c9e97e8ff2f4285bed7..e81e1ebbfb32780b4ebbea7b44cf2b1c09498766 100644 (file)
@@ -71,6 +71,7 @@ obj-$(CONFIG_ACPI_IPMI)               += acpi_ipmi.o
 
 obj-$(CONFIG_ACPI_AC)          += ac.o
 obj-$(CONFIG_ACPI_BUTTON)      += button.o
+obj-$(CONFIG_ACPI_TINY_POWER_BUTTON)   += tiny-power-button.o
 obj-$(CONFIG_ACPI_FAN)         += fan.o
 obj-$(CONFIG_ACPI_VIDEO)       += video.o
 obj-$(CONFIG_ACPI_TAD)         += acpi_tad.o
diff --git a/drivers/acpi/tiny-power-button.c b/drivers/acpi/tiny-power-button.c
new file mode 100644 (file)
index 0000000..6273d73
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/module.h>
+#include <linux/sched/signal.h>
+#include <linux/acpi.h>
+#include <acpi/button.h>
+
+ACPI_MODULE_NAME("tiny-power-button");
+MODULE_AUTHOR("Josh Triplett");
+MODULE_DESCRIPTION("ACPI Tiny Power Button Driver");
+MODULE_LICENSE("GPL");
+
+static int power_signal __read_mostly = CONFIG_ACPI_TINY_POWER_BUTTON_SIGNAL;
+module_param(power_signal, int, 0644);
+MODULE_PARM_DESC(power_signal, "Power button sends this signal to init");
+
+static const struct acpi_device_id tiny_power_button_device_ids[] = {
+       { ACPI_BUTTON_HID_POWER, 0 },
+       { ACPI_BUTTON_HID_POWERF, 0 },
+       { "", 0 },
+};
+MODULE_DEVICE_TABLE(acpi, tiny_power_button_device_ids);
+
+static int acpi_noop_add_remove(struct acpi_device *device)
+{
+       return 0;
+}
+
+static void acpi_tiny_power_button_notify(struct acpi_device *device, u32 event)
+{
+       kill_cad_pid(power_signal, 1);
+}
+
+static struct acpi_driver acpi_tiny_power_button_driver = {
+       .name = "tiny-power-button",
+       .class = "tiny-power-button",
+       .ids = tiny_power_button_device_ids,
+       .ops = {
+               .add = acpi_noop_add_remove,
+               .remove = acpi_noop_add_remove,
+               .notify = acpi_tiny_power_button_notify,
+       },
+};
+
+module_driver(acpi_tiny_power_button_driver,
+               acpi_bus_register_driver,
+               acpi_bus_unregister_driver);