1 #pragma once
2 #include "file.hpp"
3 
4 #include <libevdev/libevdev.h>
5 #include <systemd/sd-event.h>
6 
7 #include <map>
8 #include <memory>
9 #include <sdbusplus/message.hpp>
10 #include <string>
11 
12 namespace phosphor
13 {
14 namespace gpio
15 {
16 
17 /* Need a custom deleter for freeing up sd_event */
18 struct EventDeleter
19 {
20     void operator()(sd_event* event) const
21     {
22         event = sd_event_unref(event);
23     }
24 };
25 using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
26 
27 /* Need a custom deleter for freeing up sd_event_source */
28 struct EventSourceDeleter
29 {
30     void operator()(sd_event_source* eventSource) const
31     {
32         eventSource = sd_event_source_unref(eventSource);
33     }
34 };
35 using EventSourcePtr = std::unique_ptr<sd_event_source, EventSourceDeleter>;
36 
37 /* Need a custom deleter for freeing up evdev struct */
38 struct FreeEvDev
39 {
40     void operator()(struct libevdev* device) const
41     {
42         libevdev_free(device);
43     }
44 };
45 using EvdevPtr = std::unique_ptr<struct libevdev, FreeEvDev>;
46 
47 /** @class Evdev
48  *  @brief Responsible for catching GPIO state changes conditions and taking
49  *  actions
50  */
51 class Evdev
52 {
53 
54     using Property = std::string;
55     using Value = sdbusplus::message::variant<bool, std::string>;
56     // Association between property and its value
57     using PropertyMap = std::map<Property, Value>;
58     using Interface = std::string;
59     // Association between interface and the D-Bus property
60     using InterfaceMap = std::map<Interface, PropertyMap>;
61     using Object = sdbusplus::message::object_path;
62     // Association between object and the interface
63     using ObjectMap = std::map<Object, InterfaceMap>;
64 
65   public:
66     Evdev() = delete;
67     ~Evdev() = default;
68     Evdev(const Evdev&) = delete;
69     Evdev& operator=(const Evdev&) = delete;
70     Evdev(Evdev&&) = delete;
71     Evdev& operator=(Evdev&&) = delete;
72 
73     /** @brief Constructs Evdev object.
74      *
75      *  @param[in] path      - Device path to read for GPIO pin state
76      *  @param[in] key       - GPIO key to monitor
77      *  @param[in] event     - sd_event handler
78      *  @param[in] handler   - IO callback handler.
79      *  @param[in] useEvDev  - Whether to use EvDev to retrieve events
80      */
81     Evdev(const std::string& path, const unsigned int key, EventPtr& event,
82           sd_event_io_handler_t handler, bool useEvDev = true) :
83         path(path),
84         key(key), event(event), callbackHandler(handler), fd(openDevice())
85 
86     {
87         if (useEvDev)
88         {
89             // If we are asked to use EvDev, do that initialization.
90             initEvDev();
91         }
92 
93         // Register callback handler when FD has some data
94         registerCallback();
95     }
96 
97   protected:
98     /** @brief Device path to read for GPIO pin state */
99     const std::string path;
100 
101     /** @brief GPIO key to monitor */
102     const unsigned int key;
103 
104     /** @brief Event structure */
105     EvdevPtr devicePtr;
106 
107     /** @brief Monitor to sd_event */
108     EventPtr& event;
109 
110     /** @brief Callback handler when the FD has some data */
111     sd_event_io_handler_t callbackHandler;
112 
113     /** @brief event source */
114     EventSourcePtr eventSource;
115 
116     /** @brief Opens the device and populates the descriptor */
117     int openDevice();
118 
119     /** @brief attaches FD to events and sets up callback handler */
120     void registerCallback();
121 
122     /** @brief File descriptor manager */
123     FileDescriptor fd;
124 
125     /** @brief Initializes evdev handle with the fd */
126     void initEvDev();
127 };
128 
129 } // namespace gpio
130 } // namespace phosphor
131