#pragma once #include "file.hpp" #include <libevdev/libevdev.h> #include <systemd/sd-event.h> #include <sdbusplus/message.hpp> #include <map> #include <memory> #include <string> namespace phosphor { namespace gpio { /* Need a custom deleter for freeing up sd_event */ struct EventDeleter { void operator()(sd_event* event) const { sd_event_unref(event); } }; using EventPtr = std::unique_ptr<sd_event, EventDeleter>; /* Need a custom deleter for freeing up sd_event_source */ struct EventSourceDeleter { void operator()(sd_event_source* eventSource) const { sd_event_source_unref(eventSource); } }; using EventSourcePtr = std::unique_ptr<sd_event_source, EventSourceDeleter>; /* Need a custom deleter for freeing up evdev struct */ struct FreeEvDev { void operator()(struct libevdev* device) const { libevdev_free(device); } }; using EvdevPtr = std::unique_ptr<struct libevdev, FreeEvDev>; /** @class Evdev * @brief Responsible for catching GPIO state changes conditions and taking * actions */ class Evdev { using Property = std::string; using Value = std::variant<bool, std::string>; // Association between property and its value using PropertyMap = std::map<Property, Value>; using Interface = std::string; // Association between interface and the D-Bus property using InterfaceMap = std::map<Interface, PropertyMap>; using Object = sdbusplus::message::object_path; // Association between object and the interface using ObjectMap = std::map<Object, InterfaceMap>; public: Evdev() = delete; ~Evdev() = default; Evdev(const Evdev&) = delete; Evdev& operator=(const Evdev&) = delete; Evdev(Evdev&&) = delete; Evdev& operator=(Evdev&&) = delete; /** @brief Constructs Evdev object. * * @param[in] path - Device path to read for GPIO pin state * @param[in] key - GPIO key to monitor * @param[in] event - sd_event handler * @param[in] handler - IO callback handler. * @param[in] useEvDev - Whether to use EvDev to retrieve events */ Evdev(const std::string& path, const unsigned int key, EventPtr& event, sd_event_io_handler_t handler, bool useEvDev = true) : path(path), key(key), event(event), callbackHandler(handler), fd(openDevice()) { if (useEvDev) { // If we are asked to use EvDev, do that initialization. initEvDev(); } // Register callback handler when FD has some data registerCallback(); } protected: /** @brief Device path to read for GPIO pin state */ const std::string path; /** @brief GPIO key to monitor */ const unsigned int key; /** @brief Event structure */ EvdevPtr devicePtr; /** @brief Monitor to sd_event */ EventPtr& event; /** @brief Callback handler when the FD has some data */ sd_event_io_handler_t callbackHandler; /** @brief event source */ EventSourcePtr eventSource; /** @brief Opens the device and populates the descriptor */ int openDevice(); /** @brief attaches FD to events and sets up callback handler */ void registerCallback(); /** @brief File descriptor manager */ FileDescriptor fd; /** @brief Initializes evdev handle with the fd */ void initEvDev(); }; } // namespace gpio } // namespace phosphor