1 #pragma once
2 
3 #include <unistd.h>
4 #include <string>
5 #include <linux/input.h>
6 #include <libevdev/libevdev.h>
7 #include <systemd/sd-event.h>
8 #include <sdbusplus/bus.hpp>
9 #include "file.hpp"
10 namespace phosphor
11 {
12 namespace gpio
13 {
14 
15 /* Need a custom deleter for freeing up sd_event */
16 struct EventDeleter
17 {
18     void operator()(sd_event* event) const
19     {
20         event = sd_event_unref(event);
21     }
22 };
23 using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
24 
25 /* Need a custom deleter for freeing up sd_event_source */
26 struct EventSourceDeleter
27 {
28     void operator()(sd_event_source* eventSource) const
29     {
30         eventSource = sd_event_source_unref(eventSource);
31     }
32 };
33 using EventSourcePtr = std::unique_ptr<sd_event_source, EventSourceDeleter>;
34 
35 /* Need a custom deleter for freeing up evdev struct */
36 struct EvdevDeleter
37 {
38     void operator()(struct libevdev* device) const
39     {
40         libevdev_free(device);
41     }
42 };
43 using EvdevPtr = std::unique_ptr<struct libevdev, EvdevDeleter>;
44 
45 /** @class Monitor
46  *  @brief Responsible for catching GPIO state change
47  *  condition and taking actions
48  */
49 class Monitor
50 {
51     public:
52         Monitor() = delete;
53         ~Monitor() = default;
54         Monitor(const Monitor&) = delete;
55         Monitor& operator=(const Monitor&) = delete;
56         Monitor(Monitor&&) = delete;
57         Monitor& operator=(Monitor&&) = delete;
58 
59         /** @brief Constructs Monitor object.
60          *
61          *  @param[in] path     - Path to gpio input device
62          *  @param[in] key      - GPIO key to monitor
63          *  @param[in] polarity - GPIO assertion polarity to look for
64          *  @param[in] target   - systemd unit to be started on GPIO
65          *                        value change
66          *  @param[in] event    - sd_event handler
67          *  @param[in] handler  - IO callback handler. Defaults to one in this
68          *                        class
69          */
70         Monitor(const std::string& path,
71                 decltype(input_event::code) key,
72                 decltype(input_event::value) polarity,
73                 const std::string& target,
74                 EventPtr& event,
75                 sd_event_io_handler_t handler = Monitor::processEvents)
76             : path(path),
77               key(key),
78               polarity(polarity),
79               target(target),
80               event(event),
81               callbackHandler(handler),
82               fd(openDevice())
83         {
84             // And register callback handler when FD has some data
85             registerCallback();
86         }
87 
88         /** @brief Callback handler when the FD has some activity on it
89          *
90          *  @param[in] es       - Populated event source
91          *  @param[in] fd       - Associated File descriptor
92          *  @param[in] revents  - Type of event
93          *  @param[in] userData - User data that was passed during registration
94          *
95          *  @return             - 0 or positive number on success and negative
96          *                        errno otherwise
97          */
98         static int processEvents(sd_event_source* es, int fd,
99                                  uint32_t revents, void* userData);
100 
101         /** @brief Returns the completion state of this handler */
102         inline auto completed() const
103         {
104             return complete;
105         }
106 
107     private:
108         /** @brief Absolute path of GPIO input device */
109         const std::string& path;
110 
111         /** @brief GPIO key code that is of interest */
112         decltype(input_event::code) key;
113 
114         /** @brief GPIO key value that is of interest */
115         decltype(input_event::value) polarity;
116 
117         /** @brief Systemd unit to be started when the condition is met */
118         const std::string& target;
119 
120         /** @brief Monitor to sd_event */
121         EventPtr& event;
122 
123         /** @brief event source */
124         EventSourcePtr eventSource;
125 
126         /** @brief Callback handler when the FD has some data */
127         sd_event_io_handler_t callbackHandler;
128 
129         /** @brief File descriptor manager */
130         FileDescriptor fd;
131 
132         /** event structure */
133         EvdevPtr device;
134 
135         /** @brief Completion indicator */
136         bool complete = false;
137 
138         /** @brief Opens the device and populates the descriptor */
139         int openDevice();
140 
141         /** @brief attaches FD to events and sets up callback handler */
142         void registerCallback();
143 
144         /** @brief Analyzes the GPIO event and starts configured target */
145         void analyzeEvent();
146 
147         /** @brief Initializes evdev handle with the fd */
148         void initEvDev();
149 };
150 
151 } // namespace gpio
152 } // namespace phosphor
153