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