1 #include "button_handler.hpp" 2 3 #include <phosphor-logging/log.hpp> 4 #include <xyz/openbmc_project/State/Chassis/server.hpp> 5 #include <xyz/openbmc_project/State/Host/server.hpp> 6 7 namespace phosphor 8 { 9 namespace button 10 { 11 12 namespace sdbusRule = sdbusplus::bus::match::rules; 13 using namespace sdbusplus::xyz::openbmc_project::State::server; 14 using namespace phosphor::logging; 15 using sdbusplus::exception::SdBusError; 16 17 constexpr auto propertyIface = "org.freedesktop.DBus.Properties"; 18 constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis"; 19 constexpr auto hostIface = "xyz.openbmc_project.State.Host"; 20 constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power"; 21 constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper"; 22 23 constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper"; 24 constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper"; 25 26 Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus) 27 { 28 try 29 { 30 if (!getService(POWER_DBUS_OBJECT_NAME, powerButtonIface).empty()) 31 { 32 log<level::INFO>("Starting power button handler"); 33 powerButtonReleased = std::make_unique<sdbusplus::bus::match_t>( 34 bus, 35 sdbusRule::type::signal() + sdbusRule::member("Released") + 36 sdbusRule::path(POWER_DBUS_OBJECT_NAME) + 37 sdbusRule::interface(powerButtonIface), 38 std::bind(std::mem_fn(&Handler::powerPressed), this, 39 std::placeholders::_1)); 40 41 powerButtonLongPressReleased = 42 std::make_unique<sdbusplus::bus::match_t>( 43 bus, 44 sdbusRule::type::signal() + 45 sdbusRule::member("PressedLong") + 46 sdbusRule::path(POWER_DBUS_OBJECT_NAME) + 47 sdbusRule::interface(powerButtonIface), 48 std::bind(std::mem_fn(&Handler::longPowerPressed), this, 49 std::placeholders::_1)); 50 } 51 } 52 catch (SdBusError& e) 53 { 54 // The button wasn't implemented 55 } 56 } 57 58 std::string Handler::getService(const std::string& path, 59 const std::string& interface) const 60 { 61 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface, 62 "GetObject"); 63 method.append(path, std::vector{interface}); 64 auto result = bus.call(method); 65 66 std::map<std::string, std::vector<std::string>> objectData; 67 result.read(objectData); 68 69 return objectData.begin()->first; 70 } 71 72 bool Handler::poweredOn() const 73 { 74 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface); 75 auto method = bus.new_method_call( 76 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Get"); 77 method.append(chassisIface, "CurrentPowerState"); 78 auto result = bus.call(method); 79 80 sdbusplus::message::variant<std::string> state; 81 result.read(state); 82 83 return Chassis::PowerState::On == 84 Chassis::convertPowerStateFromString( 85 sdbusplus::message::variant_ns::get<std::string>(state)); 86 } 87 88 void Handler::powerPressed(sdbusplus::message::message& msg) 89 { 90 auto transition = Host::Transition::On; 91 92 try 93 { 94 if (poweredOn()) 95 { 96 transition = Host::Transition::Off; 97 } 98 99 log<level::INFO>("Handling power button press"); 100 101 sdbusplus::message::variant<std::string> state = 102 convertForMessage(transition); 103 104 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface); 105 auto method = bus.new_method_call( 106 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set"); 107 method.append(hostIface, "RequestedHostTransition", state); 108 109 bus.call(method); 110 } 111 catch (SdBusError& e) 112 { 113 log<level::ERR>("Failed power state change on a power button press", 114 entry("ERROR=%s", e.what())); 115 } 116 } 117 118 void Handler::longPowerPressed(sdbusplus::message::message& msg) 119 { 120 try 121 { 122 if (!poweredOn()) 123 { 124 log<level::INFO>( 125 "Power is off so ignoring long power button press"); 126 return; 127 } 128 129 log<level::INFO>("Handling long power button press"); 130 131 sdbusplus::message::variant<std::string> state = 132 convertForMessage(Chassis::Transition::Off); 133 134 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface); 135 auto method = bus.new_method_call( 136 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Set"); 137 method.append(chassisIface, "RequestedPowerTransition", state); 138 139 bus.call(method); 140 } 141 catch (SdBusError& e) 142 { 143 log<level::ERR>("Failed powering off on long power button press", 144 entry("ERROR=%s", e.what())); 145 } 146 } 147 } // namespace button 148 } // namespace phosphor 149