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