1 #include "button_handler.hpp" 2 3 #include "settings.hpp" 4 5 #include <phosphor-logging/log.hpp> 6 #include <xyz/openbmc_project/State/Chassis/server.hpp> 7 #include <xyz/openbmc_project/State/Host/server.hpp> 8 9 namespace phosphor 10 { 11 namespace button 12 { 13 14 namespace sdbusRule = sdbusplus::bus::match::rules; 15 using namespace sdbusplus::xyz::openbmc_project::State::server; 16 using namespace phosphor::logging; 17 18 constexpr auto propertyIface = "org.freedesktop.DBus.Properties"; 19 constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis"; 20 constexpr auto hostIface = "xyz.openbmc_project.State.Host"; 21 constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power"; 22 constexpr auto idButtonIface = "xyz.openbmc_project.Chassis.Buttons.ID"; 23 constexpr auto resetButtonIface = "xyz.openbmc_project.Chassis.Buttons.Reset"; 24 constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper"; 25 constexpr auto ledGroupIface = "xyz.openbmc_project.Led.Group"; 26 27 constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper"; 28 constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper"; 29 constexpr auto ledGroupBasePath = "/xyz/openbmc_project/led/groups/"; 30 31 Handler::Handler(sdbusplus::bus::bus& bus) : bus(bus) 32 { 33 try 34 { 35 if (!getService(POWER_DBUS_OBJECT_NAME, powerButtonIface).empty()) 36 { 37 log<level::INFO>("Starting power button handler"); 38 powerButtonReleased = std::make_unique<sdbusplus::bus::match_t>( 39 bus, 40 sdbusRule::type::signal() + sdbusRule::member("Released") + 41 sdbusRule::path(POWER_DBUS_OBJECT_NAME) + 42 sdbusRule::interface(powerButtonIface), 43 std::bind(std::mem_fn(&Handler::powerPressed), this, 44 std::placeholders::_1)); 45 46 powerButtonLongPressReleased = 47 std::make_unique<sdbusplus::bus::match_t>( 48 bus, 49 sdbusRule::type::signal() + 50 sdbusRule::member("PressedLong") + 51 sdbusRule::path(POWER_DBUS_OBJECT_NAME) + 52 sdbusRule::interface(powerButtonIface), 53 std::bind(std::mem_fn(&Handler::longPowerPressed), this, 54 std::placeholders::_1)); 55 } 56 } 57 catch (sdbusplus::exception::exception& e) 58 { 59 // The button wasn't implemented 60 } 61 62 try 63 { 64 if (!getService(ID_DBUS_OBJECT_NAME, idButtonIface).empty()) 65 { 66 log<level::INFO>("Registering ID button handler"); 67 idButtonReleased = std::make_unique<sdbusplus::bus::match_t>( 68 bus, 69 sdbusRule::type::signal() + sdbusRule::member("Released") + 70 sdbusRule::path(ID_DBUS_OBJECT_NAME) + 71 sdbusRule::interface(idButtonIface), 72 std::bind(std::mem_fn(&Handler::idPressed), this, 73 std::placeholders::_1)); 74 } 75 } 76 catch (sdbusplus::exception::exception& e) 77 { 78 // The button wasn't implemented 79 } 80 81 try 82 { 83 if (!getService(RESET_DBUS_OBJECT_NAME, resetButtonIface).empty()) 84 { 85 log<level::INFO>("Registering reset button handler"); 86 resetButtonReleased = std::make_unique<sdbusplus::bus::match_t>( 87 bus, 88 sdbusRule::type::signal() + sdbusRule::member("Released") + 89 sdbusRule::path(RESET_DBUS_OBJECT_NAME) + 90 sdbusRule::interface(resetButtonIface), 91 std::bind(std::mem_fn(&Handler::resetPressed), this, 92 std::placeholders::_1)); 93 } 94 } 95 catch (sdbusplus::exception::exception& e) 96 { 97 // The button wasn't implemented 98 } 99 } 100 101 std::string Handler::getService(const std::string& path, 102 const std::string& interface) const 103 { 104 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface, 105 "GetObject"); 106 method.append(path, std::vector{interface}); 107 auto result = bus.call(method); 108 109 std::map<std::string, std::vector<std::string>> objectData; 110 result.read(objectData); 111 112 return objectData.begin()->first; 113 } 114 115 bool Handler::poweredOn() const 116 { 117 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface); 118 auto method = bus.new_method_call( 119 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Get"); 120 method.append(chassisIface, "CurrentPowerState"); 121 auto result = bus.call(method); 122 123 std::variant<std::string> state; 124 result.read(state); 125 126 return Chassis::PowerState::On == 127 Chassis::convertPowerStateFromString(std::get<std::string>(state)); 128 } 129 130 void Handler::powerPressed(sdbusplus::message::message& msg) 131 { 132 auto transition = Host::Transition::On; 133 134 try 135 { 136 if (poweredOn()) 137 { 138 transition = Host::Transition::Off; 139 } 140 141 log<level::INFO>("Handling power button press"); 142 143 std::variant<std::string> state = convertForMessage(transition); 144 145 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface); 146 auto method = bus.new_method_call( 147 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set"); 148 method.append(hostIface, "RequestedHostTransition", state); 149 150 bus.call(method); 151 } 152 catch (sdbusplus::exception::exception& e) 153 { 154 log<level::ERR>("Failed power state change on a power button press", 155 entry("ERROR=%s", e.what())); 156 } 157 } 158 159 void Handler::longPowerPressed(sdbusplus::message::message& msg) 160 { 161 try 162 { 163 if (!poweredOn()) 164 { 165 log<level::INFO>( 166 "Power is off so ignoring long power button press"); 167 return; 168 } 169 170 log<level::INFO>("Handling long power button press"); 171 172 std::variant<std::string> state = 173 convertForMessage(Chassis::Transition::Off); 174 175 auto service = getService(CHASSIS_STATE_OBJECT_NAME, chassisIface); 176 auto method = bus.new_method_call( 177 service.c_str(), CHASSIS_STATE_OBJECT_NAME, propertyIface, "Set"); 178 method.append(chassisIface, "RequestedPowerTransition", state); 179 180 bus.call(method); 181 } 182 catch (sdbusplus::exception::exception& e) 183 { 184 log<level::ERR>("Failed powering off on long power button press", 185 entry("ERROR=%s", e.what())); 186 } 187 } 188 189 void Handler::resetPressed(sdbusplus::message::message& msg) 190 { 191 try 192 { 193 if (!poweredOn()) 194 { 195 log<level::INFO>("Power is off so ignoring reset button press"); 196 return; 197 } 198 199 log<level::INFO>("Handling reset button press"); 200 201 std::variant<std::string> state = 202 convertForMessage(Host::Transition::Reboot); 203 204 auto service = getService(HOST_STATE_OBJECT_NAME, hostIface); 205 auto method = bus.new_method_call( 206 service.c_str(), HOST_STATE_OBJECT_NAME, propertyIface, "Set"); 207 208 method.append(hostIface, "RequestedHostTransition", state); 209 210 bus.call(method); 211 } 212 catch (sdbusplus::exception::exception& e) 213 { 214 log<level::ERR>("Failed power state change on a reset button press", 215 entry("ERROR=%s", e.what())); 216 } 217 } 218 219 void Handler::idPressed(sdbusplus::message::message& msg) 220 { 221 std::string groupPath{ledGroupBasePath}; 222 groupPath += ID_LED_GROUP; 223 224 auto service = getService(groupPath, ledGroupIface); 225 226 if (service.empty()) 227 { 228 log<level::INFO>("No identify LED group found during ID button press", 229 entry("GROUP=%s", groupPath.c_str())); 230 return; 231 } 232 233 try 234 { 235 auto method = bus.new_method_call(service.c_str(), groupPath.c_str(), 236 propertyIface, "Get"); 237 method.append(ledGroupIface, "Asserted"); 238 auto result = bus.call(method); 239 240 std::variant<bool> state; 241 result.read(state); 242 243 state = !std::get<bool>(state); 244 245 log<level::INFO>("Changing ID LED group state on ID LED press", 246 entry("GROUP=%s", groupPath.c_str()), 247 entry("STATE=%d", std::get<bool>(state))); 248 249 method = bus.new_method_call(service.c_str(), groupPath.c_str(), 250 propertyIface, "Set"); 251 252 method.append(ledGroupIface, "Asserted", state); 253 result = bus.call(method); 254 } 255 catch (sdbusplus::exception::exception& e) 256 { 257 log<level::ERR>("Error toggling ID LED group on ID button press", 258 entry("ERROR=%s", e.what())); 259 } 260 } 261 } // namespace button 262 } // namespace phosphor 263