acpi-power-state: Import from gBMC

Imported from the scripts repo

Google-Bug-Id: 182214245
Upstream: d416a695e0747be61d13cb1f1ddba9de2c10238a
Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: Ib302ea4b6fb52f5579fcb91d00fd12705edc04d1
diff --git a/acpi-power-state-daemon/acpi-power-state.service.in b/acpi-power-state-daemon/acpi-power-state.service.in
new file mode 100644
index 0000000..ae111f6
--- /dev/null
+++ b/acpi-power-state-daemon/acpi-power-state.service.in
@@ -0,0 +1,10 @@
+[Unit]
+Description=Receive ACPI power state over IPMI
+
+[Service]
+Type=simple
+Restart=always
+ExecStart=@@BIN@ acpi_power_stated
+
+[Install]
+WantedBy=multi-user.target
diff --git a/acpi-power-state-daemon/acpi_power_state.cpp b/acpi-power-state-daemon/acpi_power_state.cpp
new file mode 100644
index 0000000..9b5d5d2
--- /dev/null
+++ b/acpi-power-state-daemon/acpi_power_state.cpp
@@ -0,0 +1,104 @@
+// Copyright 2021 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+ * Based off of sdbusplus:/example/calculator-server.cpp
+ */
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server.hpp>
+#include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp>
+
+#include <exception>
+#include <iostream>
+#include <optional>
+#include <string>
+
+constexpr auto hostS5Unit = "host-s5-state.target";
+constexpr auto hostS0Unit = "host-s0-state.target";
+
+constexpr auto systemdBusName = "org.freedesktop.systemd1";
+constexpr auto systemdPath = "/org/freedesktop/systemd1";
+constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
+
+constexpr auto acpiObjPath =
+    "/xyz/openbmc_project/control/host0/acpi_power_state";
+constexpr auto acpiInterface =
+    "xyz.openbmc_project.Control.Power.ACPIPowerState";
+
+using ACPIPowerStateInherit = sdbusplus::server::object_t<
+    sdbusplus::xyz::openbmc_project::Control::Power::server::ACPIPowerState>;
+
+// Pulled and modified from arcadia-leds/poll_gpio.cpp
+static void startSystemdUnit(sdbusplus::bus::bus& bus, const std::string& unit)
+{
+    auto method = bus.new_method_call(systemdBusName, systemdPath,
+                                      systemdInterface, "StartUnit");
+    method.append(unit, "replace");
+    bus.call(method);
+}
+
+struct ACPIPowerState : ACPIPowerStateInherit
+{
+    // Keep track of the bus for starting/stopping systemd units
+    sdbusplus::bus::bus& Bus;
+
+    ACPIPowerState(sdbusplus::bus::bus& bus, const char* path) :
+        ACPIPowerStateInherit(bus, path), Bus(bus)
+    {}
+
+    ACPI sysACPIStatus(ACPI value)
+    {
+        std::cout << "State change "
+                  << ACPIPowerStateInherit::convertACPIToString(value)
+                  << std::endl;
+
+        switch (value)
+        {
+            case ACPI::S5_G2:
+                std::cout << "Entered S5" << std::endl;
+                startSystemdUnit(Bus, hostS5Unit);
+                break;
+            case ACPI::S0_G0_D0:
+                std::cout << "Entered S0" << std::endl;
+                startSystemdUnit(Bus, hostS0Unit);
+                break;
+            default:
+                break;
+        }
+
+        return ACPIPowerStateInherit::sysACPIStatus(value);
+    }
+};
+
+int main()
+{
+
+    auto b = sdbusplus::bus::new_default();
+    sdbusplus::server::manager_t m{b, acpiObjPath};
+
+    // Reserve the dbus service for ACPI Power state changes coming from the
+    // BIOS
+    b.request_name(acpiInterface);
+
+    ACPIPowerState aps{b, acpiObjPath};
+
+    // Handle dbus processing forever.
+    for (;;)
+    {
+        b.process_discard(); // discard any unhandled messages
+        b.wait();
+    }
+
+    return 1;
+}
diff --git a/acpi-power-state-daemon/host-s0-state.target b/acpi-power-state-daemon/host-s0-state.target
new file mode 100644
index 0000000..05d4e02
--- /dev/null
+++ b/acpi-power-state-daemon/host-s0-state.target
@@ -0,0 +1,3 @@
+[Unit]
+Description=Host S0 state target
+Conflicts=host-s5-state.target
diff --git a/acpi-power-state-daemon/host-s5-state.target b/acpi-power-state-daemon/host-s5-state.target
new file mode 100644
index 0000000..bb88178
--- /dev/null
+++ b/acpi-power-state-daemon/host-s5-state.target
@@ -0,0 +1,3 @@
+[Unit]
+Description=Host S5 state target
+Conflicts=host-s0-state.target
diff --git a/acpi-power-state-daemon/meson.build b/acpi-power-state-daemon/meson.build
new file mode 100644
index 0000000..acd34fd
--- /dev/null
+++ b/acpi-power-state-daemon/meson.build
@@ -0,0 +1,59 @@
+# Copyright 2021 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+project(
+  'acpi_power_stated',
+  'cpp',
+  version: '0.1',
+  default_options: [
+    'warning_level=3',
+    'werror=true',
+    'cpp_std=c++17',
+  ],
+)
+
+headers = include_directories('.')
+
+systemd = dependency('systemd')
+systemunitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
+
+deps = [
+  systemd,
+  dependency('sdbusplus', fallback: ['sdbusplus', 'sdbusplus_dep']),
+  dependency('phosphor-dbus-interfaces'),
+]
+
+bindir = get_option('prefix') / get_option('bindir')
+
+executable(
+  'acpi_power_stated',
+  'acpi_power_state.cpp',
+  include_directories: headers,
+  implicit_include_directories: false,
+  dependencies: deps,
+  install: true,
+  install_dir: bindir)
+
+configure_file(
+  configuration: {'BIN': bindir / 'acpi_power_stated'},
+  input: 'acpi-power-state.service.in',
+  output: 'acpi-power-state.service',
+  install_mode: 'rw-r--r--',
+  install_dir: systemunitdir)
+
+install_data(
+  'host-s0-state.target',
+  'host-s5-state.target',
+  install_mode: 'rw-r--r--',
+  install_dir: systemunitdir)
diff --git a/acpi-power-state-daemon/subprojects b/acpi-power-state-daemon/subprojects
new file mode 120000
index 0000000..d2458e9
--- /dev/null
+++ b/acpi-power-state-daemon/subprojects
@@ -0,0 +1 @@
+../subprojects/
\ No newline at end of file