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