1 #pragma once
2 
3 #include "button_config.hpp"
4 #include "common.hpp"
5 #include "xyz/openbmc_project/Chassis/Common/error.hpp"
6 
7 #include <phosphor-logging/elog-errors.hpp>
8 // This is the base class for all the button interface types
9 //
10 class ButtonIface
11 {
12   public:
ButtonIface(sdbusplus::bus_t & bus,EventPtr & event,ButtonConfig & buttonCfg,sd_event_io_handler_t handler=ButtonIface::EventHandler)13     ButtonIface(sdbusplus::bus_t& bus, EventPtr& event, ButtonConfig& buttonCfg,
14                 sd_event_io_handler_t handler = ButtonIface::EventHandler) :
15         bus(bus), event(event), config(buttonCfg), callbackHandler(handler)
16     {
17         int ret = -1;
18         std::string configType;
19 
20         // config group gpio or cpld based on the defs read from the json file
21         if (buttonCfg.type == ConfigType::gpio)
22         {
23             configType = "GPIO";
24             ret = configGroupGpio(config);
25         }
26         else if (buttonCfg.type == ConfigType::cpld)
27         {
28             configType = "CPLD";
29             ret = configCpld(config);
30         }
31 
32         if (ret < 0)
33         {
34             phosphor::logging::log<phosphor::logging::level::ERR>(
35                 (getFormFactorType() + " : failed to config " + configType)
36                     .c_str());
37             throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
38                 IOError();
39         }
40     }
~ButtonIface()41     virtual ~ButtonIface() {}
42 
43     /**
44      * @brief This method is called from sd-event provided callback function
45      * callbackHandler if platform specific event handling is needed then a
46      * derived class instance with its specific evend handling logic along with
47      * init() function can be created to override the default event handling.
48      */
49 
50     virtual void handleEvent(sd_event_source* es, int fd, uint32_t revents) = 0;
EventHandler(sd_event_source * es,int fd,uint32_t revents,void * userdata)51     static int EventHandler(sd_event_source* es, int fd, uint32_t revents,
52                             void* userdata)
53     {
54         if (userdata)
55         {
56             ButtonIface* buttonIface = static_cast<ButtonIface*>(userdata);
57             buttonIface->handleEvent(es, fd, revents);
58         }
59 
60         return 0;
61     }
62 
getFormFactorType() const63     std::string getFormFactorType() const
64     {
65         return config.formFactorName;
66     }
67 
68   protected:
69     /**
70      * @brief oem specific initialization can be done under init function.
71      * if platform specific initialization is needed then
72      * a derived class instance with its own init function to override the
73      * default init() method can be added.
74      */
75 
init()76     virtual void init()
77     {
78         // initialize the button io fd from the ButtonConfig
79         // which has fd stored when configGroupGpio or configCpld is called
80         for (auto fd : config.fds)
81         {
82             char buf;
83 
84             int ret = ::read(fd, &buf, sizeof(buf));
85             if (ret < 0)
86             {
87                 phosphor::logging::log<phosphor::logging::level::ERR>(
88                     (getFormFactorType() + " : read error!").c_str());
89             }
90 
91             ret = sd_event_add_io(event.get(), nullptr, fd, EPOLLPRI,
92                                   callbackHandler, this);
93             if (ret < 0)
94             {
95                 phosphor::logging::log<phosphor::logging::level::ERR>(
96                     (getFormFactorType() + " : failed to add to event loop")
97                         .c_str());
98                 if (fd > 0)
99                 {
100                     ::close(fd);
101                 }
102                 throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
103                     IOError();
104             }
105         }
106     }
107     /**
108      * @brief similar to init() oem specific deinitialization can be done under
109      * deInit function. if platform specific deinitialization is needed then a
110      * derived class instance with its own init function to override the default
111      * deinit() method can be added.
112      */
deInit()113     virtual void deInit()
114     {
115         for (auto fd : config.fds)
116         {
117             if (fd > 0)
118             {
119                 ::close(fd);
120             }
121         }
122     }
123 
124     sdbusplus::bus_t& bus;
125     EventPtr& event;
126     ButtonConfig config;
127     sd_event_io_handler_t callbackHandler;
128 };
129