blob: 801cc9e3f3dd81ee74ffa85568c8150005eb6d8a [file] [log] [blame]
George Liud6a1bae2022-06-20 13:47:31 +08001#include "config.h"
Matt Spinlerfb35a322018-11-26 14:30:30 -06002
George Liud6a1bae2022-06-20 13:47:31 +08003#include "button_handler.hpp"
Matt Spinler69f93512018-11-26 14:55:58 -06004
Matt Spinler1a309f72023-04-04 13:12:19 -05005#include "power_button_profile_factory.hpp"
6
George Liu9fb15972022-06-20 14:54:38 +08007#include <phosphor-logging/lg2.hpp>
Matt Spinler963c65f2018-11-26 14:46:41 -06008#include <xyz/openbmc_project/State/Chassis/server.hpp>
9#include <xyz/openbmc_project/State/Host/server.hpp>
Matt Spinlerfb35a322018-11-26 14:30:30 -060010namespace phosphor
11{
12namespace button
13{
Matt Spinler963c65f2018-11-26 14:46:41 -060014
15namespace sdbusRule = sdbusplus::bus::match::rules;
16using namespace sdbusplus::xyz::openbmc_project::State::server;
Matt Spinler963c65f2018-11-26 14:46:41 -060017
Matt Spinler963c65f2018-11-26 14:46:41 -060018constexpr auto chassisIface = "xyz.openbmc_project.State.Chassis";
19constexpr auto hostIface = "xyz.openbmc_project.State.Host";
20constexpr auto powerButtonIface = "xyz.openbmc_project.Chassis.Buttons.Power";
Matt Spinler69f93512018-11-26 14:55:58 -060021constexpr auto idButtonIface = "xyz.openbmc_project.Chassis.Buttons.ID";
Matt Spinler06a5bdd2018-11-26 14:50:48 -060022constexpr auto resetButtonIface = "xyz.openbmc_project.Chassis.Buttons.Reset";
Matt Spinler69f93512018-11-26 14:55:58 -060023constexpr auto ledGroupIface = "xyz.openbmc_project.Led.Group";
Naveen Moses3bd1cfc2022-02-14 18:04:20 +053024constexpr auto ledGroupBasePath = "/xyz/openbmc_project/led/groups/";
25constexpr auto hostSelectorIface =
26 "xyz.openbmc_project.Chassis.Buttons.HostSelector";
27constexpr auto debugHostSelectorIface =
Naveen Mosesa6d4e652022-04-13 19:27:25 +053028 "xyz.openbmc_project.Chassis.Buttons.Button";
Naveen Moses3bd1cfc2022-02-14 18:04:20 +053029
30constexpr auto propertyIface = "org.freedesktop.DBus.Properties";
31constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
Matt Spinler963c65f2018-11-26 14:46:41 -060032
33constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
34constexpr auto mapperService = "xyz.openbmc_project.ObjectMapper";
Naveen Moses3bd1cfc2022-02-14 18:04:20 +053035constexpr auto BMC_POSITION = 0;
Matt Spinler963c65f2018-11-26 14:46:41 -060036
Patrick Williams9a529a62022-07-22 19:26:54 -050037Handler::Handler(sdbusplus::bus_t& bus) : bus(bus)
Matt Spinlerfb35a322018-11-26 14:30:30 -060038{
Matt Spinler963c65f2018-11-26 14:46:41 -060039 try
40 {
41 if (!getService(POWER_DBUS_OBJECT_NAME, powerButtonIface).empty())
42 {
George Liu9fb15972022-06-20 14:54:38 +080043 lg2::info("Starting power button handler");
Matt Spinler1a309f72023-04-04 13:12:19 -050044
45 // Check for a custom handler
46 powerButtonProfile =
47 PowerButtonProfileFactory::instance().createProfile(bus);
48
49 if (!powerButtonProfile)
50 {
51 powerButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
52 bus,
53 sdbusRule::type::signal() + sdbusRule::member("Released") +
54 sdbusRule::path(POWER_DBUS_OBJECT_NAME) +
55 sdbusRule::interface(powerButtonIface),
56 std::bind(std::mem_fn(&Handler::powerReleased), this,
57 std::placeholders::_1));
58 }
Matt Spinler963c65f2018-11-26 14:46:41 -060059 }
60 }
Patrick Williams9a529a62022-07-22 19:26:54 -050061 catch (const sdbusplus::exception_t& e)
Matt Spinler963c65f2018-11-26 14:46:41 -060062 {
63 // The button wasn't implemented
64 }
Matt Spinler06a5bdd2018-11-26 14:50:48 -060065
66 try
67 {
Matt Spinler69f93512018-11-26 14:55:58 -060068 if (!getService(ID_DBUS_OBJECT_NAME, idButtonIface).empty())
69 {
George Liu9fb15972022-06-20 14:54:38 +080070 lg2::info("Registering ID button handler");
Matt Spinler69f93512018-11-26 14:55:58 -060071 idButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
72 bus,
73 sdbusRule::type::signal() + sdbusRule::member("Released") +
74 sdbusRule::path(ID_DBUS_OBJECT_NAME) +
75 sdbusRule::interface(idButtonIface),
Naveen Mosesab8dac52022-07-15 19:32:27 +053076 std::bind(std::mem_fn(&Handler::idReleased), this,
Matt Spinler69f93512018-11-26 14:55:58 -060077 std::placeholders::_1));
78 }
79 }
Patrick Williams9a529a62022-07-22 19:26:54 -050080 catch (const sdbusplus::exception_t& e)
Matt Spinler69f93512018-11-26 14:55:58 -060081 {
82 // The button wasn't implemented
83 }
84
85 try
86 {
Matt Spinler06a5bdd2018-11-26 14:50:48 -060087 if (!getService(RESET_DBUS_OBJECT_NAME, resetButtonIface).empty())
88 {
George Liu9fb15972022-06-20 14:54:38 +080089 lg2::info("Registering reset button handler");
Matt Spinler06a5bdd2018-11-26 14:50:48 -060090 resetButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
91 bus,
92 sdbusRule::type::signal() + sdbusRule::member("Released") +
93 sdbusRule::path(RESET_DBUS_OBJECT_NAME) +
94 sdbusRule::interface(resetButtonIface),
Naveen Mosesab8dac52022-07-15 19:32:27 +053095 std::bind(std::mem_fn(&Handler::resetReleased), this,
Matt Spinler06a5bdd2018-11-26 14:50:48 -060096 std::placeholders::_1));
97 }
98 }
Patrick Williams9a529a62022-07-22 19:26:54 -050099 catch (const sdbusplus::exception_t& e)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600100 {
101 // The button wasn't implemented
102 }
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530103 try
104 {
105 if (!getService(DBG_HS_DBUS_OBJECT_NAME, debugHostSelectorIface)
106 .empty())
107 {
108 lg2::info("Registering debug host selector button handler");
109 debugHSButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
110 bus,
111 sdbusRule::type::signal() + sdbusRule::member("Released") +
112 sdbusRule::path(DBG_HS_DBUS_OBJECT_NAME) +
113 sdbusRule::interface(debugHostSelectorIface),
114 std::bind(std::mem_fn(&Handler::debugHostSelectorReleased),
115 this, std::placeholders::_1));
116 }
117 }
Patrick Williamse3b4e112022-11-26 09:41:58 -0600118 catch (const sdbusplus::exception_t& e)
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530119 {
120 // The button wasn't implemented
121 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600122}
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530123bool Handler::isMultiHost()
124{
125 // return true in case host selector object is available
126 return (!getService(HS_DBUS_OBJECT_NAME, hostSelectorIface).empty());
127}
Matt Spinler963c65f2018-11-26 14:46:41 -0600128std::string Handler::getService(const std::string& path,
129 const std::string& interface) const
130{
131 auto method = bus.new_method_call(mapperService, mapperObjPath, mapperIface,
132 "GetObject");
133 method.append(path, std::vector{interface});
Thang Q. Nguyen42507852022-08-12 09:11:35 +0700134 try
135 {
136 auto result = bus.call(method);
137 std::map<std::string, std::vector<std::string>> objectData;
138 result.read(objectData);
139 return objectData.begin()->first;
140 }
Patrick Williamse3b4e112022-11-26 09:41:58 -0600141 catch (const sdbusplus::exception_t& e)
Thang Q. Nguyen42507852022-08-12 09:11:35 +0700142 {
143 return std::string();
144 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600145}
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530146size_t Handler::getHostSelectorValue()
Matt Spinler963c65f2018-11-26 14:46:41 -0600147{
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530148 auto HSService = getService(HS_DBUS_OBJECT_NAME, hostSelectorIface);
149
150 if (HSService.empty())
151 {
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530152 lg2::info("Host selector dbus object not available");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530153 throw std::invalid_argument("Host selector dbus object not available");
154 }
155
156 try
157 {
158 auto method = bus.new_method_call(
159 HSService.c_str(), HS_DBUS_OBJECT_NAME, propertyIface, "Get");
160 method.append(hostSelectorIface, "Position");
161 auto result = bus.call(method);
162
163 std::variant<size_t> HSPositionVariant;
164 result.read(HSPositionVariant);
165
166 auto position = std::get<size_t>(HSPositionVariant);
167 return position;
168 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500169 catch (const sdbusplus::exception_t& e)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530170 {
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530171 lg2::error("Error reading host selector position: {ERROR}", "ERROR", e);
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530172 throw;
173 }
174}
175bool Handler::poweredOn(size_t hostNumber) const
176{
Potin Laic0fee462022-12-23 14:19:23 +0800177 auto hostObjectName = HOST_STATE_OBJECT_NAME + std::to_string(hostNumber);
178 auto service = getService(hostObjectName.c_str(), hostIface);
179 auto method = bus.new_method_call(service.c_str(), hostObjectName.c_str(),
180 propertyIface, "Get");
181 method.append(hostIface, "CurrentHostState");
Matt Spinler963c65f2018-11-26 14:46:41 -0600182 auto result = bus.call(method);
183
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500184 std::variant<std::string> state;
Matt Spinler963c65f2018-11-26 14:46:41 -0600185 result.read(state);
186
Potin Laic0fee462022-12-23 14:19:23 +0800187 return Host::HostState::Off !=
188 Host::convertHostStateFromString(std::get<std::string>(state));
Matt Spinler963c65f2018-11-26 14:46:41 -0600189}
190
DelphineCCChiu395c7642023-04-19 10:46:47 +0800191void Handler::handlePowerEvent(PowerEvent powerEventType,
192 std::chrono::microseconds duration)
Matt Spinler963c65f2018-11-26 14:46:41 -0600193{
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530194 std::string objPathName;
195 std::string dbusIfaceName;
196 std::string transitionName;
197 std::variant<Host::Transition, Chassis::Transition> transition;
DelphineCCChiu395c7642023-04-19 10:46:47 +0800198 uint64_t durationMs =
199 std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
Matt Spinler963c65f2018-11-26 14:46:41 -0600200
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530201 size_t hostNumber = 0;
202 auto isMultiHostSystem = isMultiHost();
203 if (isMultiHostSystem)
Matt Spinler963c65f2018-11-26 14:46:41 -0600204 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530205 hostNumber = getHostSelectorValue();
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530206 lg2::info("Multi-host system detected : {POSITION}", "POSITION",
George Liu9fb15972022-06-20 14:54:38 +0800207 hostNumber);
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530208 }
209
210 std::string hostNumStr = std::to_string(hostNumber);
211
212 // ignore power and reset button events if BMC is selected.
213 if (isMultiHostSystem && (hostNumber == BMC_POSITION) &&
DelphineCCChiu395c7642023-04-19 10:46:47 +0800214 (powerEventType != PowerEvent::powerReleased) &&
215 (durationMs <= LONG_PRESS_TIME_MS))
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530216 {
George Liu9fb15972022-06-20 14:54:38 +0800217 lg2::info(
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530218 "handlePowerEvent : BMC selected on multi-host system. ignoring power and reset button events...");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530219 return;
220 }
221
222 switch (powerEventType)
223 {
Naveen Mosesab8dac52022-07-15 19:32:27 +0530224 case PowerEvent::powerReleased:
George Liu5b98f4d2022-06-20 13:31:14 +0800225 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800226 if (durationMs <= LONG_PRESS_TIME_MS)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530227 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800228 objPathName = HOST_STATE_OBJECT_NAME + hostNumStr;
229 dbusIfaceName = hostIface;
230 transitionName = "RequestedHostTransition";
231
232 transition = Host::Transition::On;
233
234 if (poweredOn(hostNumber))
235 {
236 transition = Host::Transition::Off;
237 }
238 lg2::info("handlePowerEvent : Handle power button press ");
239
240 break;
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530241 }
DelphineCCChiu395c7642023-04-19 10:46:47 +0800242 else
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530243 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800244 dbusIfaceName = chassisIface;
245 transitionName = "RequestedPowerTransition";
246 objPathName = CHASSIS_STATE_OBJECT_NAME + hostNumStr;
247 transition = Chassis::Transition::Off;
248
249 /* multi host system :
250 hosts (1 to N) - host shutdown
251 bmc (0) - sled cycle
252 single host system :
253 host(0) - host shutdown
254 */
255 if (isMultiHostSystem && (hostNumber == BMC_POSITION))
256 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530257#if CHASSIS_SYSTEM_RESET_ENABLED
DelphineCCChiu395c7642023-04-19 10:46:47 +0800258 objPathName = CHASSISSYSTEM_STATE_OBJECT_NAME + hostNumStr;
259 transition = Chassis::Transition::PowerCycle;
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530260#else
DelphineCCChiu395c7642023-04-19 10:46:47 +0800261 return;
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530262#endif
DelphineCCChiu395c7642023-04-19 10:46:47 +0800263 }
264 else if (!poweredOn(hostNumber))
265 {
266 lg2::info(
267 "Power is off so ignoring long power button press");
268 return;
269 }
270 lg2::info("handlePowerEvent : handle long power button press");
271 break;
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530272 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600273 }
Naveen Mosesab8dac52022-07-15 19:32:27 +0530274 case PowerEvent::resetReleased:
George Liu5b98f4d2022-06-20 13:31:14 +0800275 {
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530276 objPathName = HOST_STATE_OBJECT_NAME + hostNumStr;
277 dbusIfaceName = hostIface;
278 transitionName = "RequestedHostTransition";
Matt Spinler963c65f2018-11-26 14:46:41 -0600279
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530280 if (!poweredOn(hostNumber))
281 {
George Liu9fb15972022-06-20 14:54:38 +0800282 lg2::info("Power is off so ignoring reset button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530283 return;
284 }
Matt Spinler963c65f2018-11-26 14:46:41 -0600285
George Liu9fb15972022-06-20 14:54:38 +0800286 lg2::info("Handling reset button press");
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530287 transition = Host::Transition::Reboot;
288 break;
289 }
George Liu5b98f4d2022-06-20 13:31:14 +0800290 default:
291 {
George Liu9fb15972022-06-20 14:54:38 +0800292 lg2::error("{EVENT} is invalid power event. skipping...", "EVENT",
293 static_cast<std::underlying_type_t<PowerEvent>>(
294 powerEventType));
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530295
296 return;
297 }
298 }
299 auto service = getService(objPathName.c_str(), dbusIfaceName);
300 auto method = bus.new_method_call(service.c_str(), objPathName.c_str(),
301 propertyIface, "Set");
302 method.append(dbusIfaceName, transitionName, transition);
303 bus.call(method);
304}
DelphineCCChiu395c7642023-04-19 10:46:47 +0800305void Handler::powerReleased(sdbusplus::message_t& msg)
Naveen Moses3bd1cfc2022-02-14 18:04:20 +0530306{
307 try
308 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800309 uint64_t time;
310 msg.read(time);
311
312 handlePowerEvent(PowerEvent::powerReleased,
313 std::chrono::microseconds(time));
Matt Spinler963c65f2018-11-26 14:46:41 -0600314 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500315 catch (const sdbusplus::exception_t& e)
Matt Spinler963c65f2018-11-26 14:46:41 -0600316 {
George Liu9fb15972022-06-20 14:54:38 +0800317 lg2::error("Failed power state change on a power button press: {ERROR}",
318 "ERROR", e);
Matt Spinler963c65f2018-11-26 14:46:41 -0600319 }
320}
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600321
Patrick Williams9a529a62022-07-22 19:26:54 -0500322void Handler::resetReleased(sdbusplus::message_t& /* msg */)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600323{
324 try
325 {
DelphineCCChiu395c7642023-04-19 10:46:47 +0800326 // No need to calculate duration, set to 0.
327 handlePowerEvent(PowerEvent::resetReleased,
328 std::chrono::microseconds(0));
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600329 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500330 catch (const sdbusplus::exception_t& e)
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600331 {
George Liu9fb15972022-06-20 14:54:38 +0800332 lg2::error("Failed power state change on a reset button press: {ERROR}",
333 "ERROR", e);
Matt Spinler06a5bdd2018-11-26 14:50:48 -0600334 }
335}
Matt Spinler69f93512018-11-26 14:55:58 -0600336
Patrick Williams9a529a62022-07-22 19:26:54 -0500337void Handler::idReleased(sdbusplus::message_t& /* msg */)
Matt Spinler69f93512018-11-26 14:55:58 -0600338{
339 std::string groupPath{ledGroupBasePath};
340 groupPath += ID_LED_GROUP;
341
342 auto service = getService(groupPath, ledGroupIface);
343
344 if (service.empty())
345 {
George Liu9fb15972022-06-20 14:54:38 +0800346 lg2::info("No found {GROUP} during ID button press:", "GROUP",
347 groupPath);
Matt Spinler69f93512018-11-26 14:55:58 -0600348 return;
349 }
350
351 try
352 {
353 auto method = bus.new_method_call(service.c_str(), groupPath.c_str(),
354 propertyIface, "Get");
355 method.append(ledGroupIface, "Asserted");
356 auto result = bus.call(method);
357
Patrick Williams5ed4cc02020-05-13 17:52:15 -0500358 std::variant<bool> state;
Matt Spinler69f93512018-11-26 14:55:58 -0600359 result.read(state);
360
Patrick Williams51f5e8b2020-05-13 11:33:44 -0500361 state = !std::get<bool>(state);
Matt Spinler69f93512018-11-26 14:55:58 -0600362
George Liu9fb15972022-06-20 14:54:38 +0800363 lg2::info(
364 "Changing ID LED group state on ID LED press, GROUP = {GROUP}, STATE = {STATE}",
365 "GROUP", groupPath, "STATE", std::get<bool>(state));
Matt Spinler69f93512018-11-26 14:55:58 -0600366
367 method = bus.new_method_call(service.c_str(), groupPath.c_str(),
368 propertyIface, "Set");
369
370 method.append(ledGroupIface, "Asserted", state);
371 result = bus.call(method);
372 }
Patrick Williams9a529a62022-07-22 19:26:54 -0500373 catch (const sdbusplus::exception_t& e)
Matt Spinler69f93512018-11-26 14:55:58 -0600374 {
George Liu9fb15972022-06-20 14:54:38 +0800375 lg2::error("Error toggling ID LED group on ID button press: {ERROR}",
376 "ERROR", e);
Matt Spinler69f93512018-11-26 14:55:58 -0600377 }
378}
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530379
380void Handler::increaseHostSelectorPosition()
381{
382 try
383 {
384 auto HSService = getService(HS_DBUS_OBJECT_NAME, hostSelectorIface);
385
386 if (HSService.empty())
387 {
388 lg2::error("Host selector service not available");
389 return;
390 }
391
392 auto method =
393 bus.new_method_call(HSService.c_str(), HS_DBUS_OBJECT_NAME,
394 phosphor::button::propertyIface, "GetAll");
395 method.append(phosphor::button::hostSelectorIface);
396 auto result = bus.call(method);
397 std::unordered_map<std::string, std::variant<size_t>> properties;
398 result.read(properties);
399
400 auto maxPosition = std::get<size_t>(properties.at("MaxPosition"));
401 auto position = std::get<size_t>(properties.at("Position"));
402
403 std::variant<size_t> HSPositionVariant =
404 (position < maxPosition) ? (position + 1) : 0;
405
406 method = bus.new_method_call(HSService.c_str(), HS_DBUS_OBJECT_NAME,
407 phosphor::button::propertyIface, "Set");
408 method.append(phosphor::button::hostSelectorIface, "Position");
409
410 method.append(HSPositionVariant);
411 result = bus.call(method);
412 }
Patrick Williamse3b4e112022-11-26 09:41:58 -0600413 catch (const sdbusplus::exception_t& e)
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530414 {
415 lg2::error("Error modifying host selector position : {ERROR}", "ERROR",
416 e);
417 }
418}
419
Patrick Williamse3b4e112022-11-26 09:41:58 -0600420void Handler::debugHostSelectorReleased(sdbusplus::message_t& /* msg */)
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530421{
422 try
423 {
424 increaseHostSelectorPosition();
425 }
Patrick Williamse3b4e112022-11-26 09:41:58 -0600426 catch (const sdbusplus::exception_t& e)
Naveen Mosesa6d4e652022-04-13 19:27:25 +0530427 {
428 lg2::error(
429 "Failed power process debug host selector button press : {ERROR}",
430 "ERROR", e);
431 }
432}
433
Matt Spinlerfb35a322018-11-26 14:30:30 -0600434} // namespace button
435} // namespace phosphor