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