| // 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_t& 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_t& Bus; |
| |
| ACPIPowerState(sdbusplus::bus_t& 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; |
| } |