1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 4 #pragma once 5 #include "evdev.hpp" 6 7 #include <systemd/sd-event.h> 8 9 #include <sdbusplus/bus.hpp> 10 11 #include <cstdlib> 12 #include <filesystem> 13 #include <string> 14 15 namespace phosphor 16 { 17 namespace gpio 18 { 19 namespace presence 20 { 21 22 static constexpr auto deviceField = 0; 23 static constexpr auto pathField = 1; 24 using Device = std::string; 25 using Path = std::filesystem::path; 26 using Driver = std::tuple<Device, Path>; 27 using Interface = std::string; 28 29 /** @class Presence 30 * @brief Responsible for determining and monitoring presence, 31 * by monitoring GPIO state changes, of inventory items and 32 * updating D-Bus accordingly. 33 */ 34 class Presence : public Evdev 35 { 36 using Property = std::string; 37 using Value = std::variant<bool, std::string>; 38 // Association between property and its value 39 using PropertyMap = std::map<Property, Value>; 40 using Interface = std::string; 41 // Association between interface and the D-Bus property 42 using InterfaceMap = std::map<Interface, PropertyMap>; 43 using Object = sdbusplus::message::object_path; 44 // Association between object and the interface 45 using ObjectMap = std::map<Object, InterfaceMap>; 46 47 public: 48 Presence() = delete; 49 ~Presence() = default; 50 Presence(const Presence&) = delete; 51 Presence& operator=(const Presence&) = delete; 52 Presence(Presence&&) = delete; 53 Presence& operator=(Presence&&) = delete; 54 55 /** @brief Constructs Presence object. 56 * 57 * @param[in] bus - D-Bus bus Object 58 * @param[in] inventory - Object path under inventory 59 to display this inventory item 60 * @param[in] path - Device path to read for GPIO pin state 61 to determine presence of inventory item 62 * @param[in] key - GPIO key to monitor 63 * @param[in] name - Pretty name of the inventory item 64 * @param[in] event - sd_event handler 65 * @param[in] drivers - list of device drivers to bind and unbind 66 * @param[in] ifaces - list of extra interfaces to associate with the 67 * inventory item 68 * @param[in] handler - IO callback handler. Defaults to one in this 69 * class 70 */ Presence(sdbusplus::bus_t & bus,const std::string & inventory,const std::string & path,const unsigned int key,const std::string & name,EventPtr & event,const std::vector<Driver> & drivers,const std::vector<Interface> & ifaces,sd_event_io_handler_t handler=Presence::processEvents)71 Presence(sdbusplus::bus_t& bus, const std::string& inventory, 72 const std::string& path, const unsigned int key, 73 const std::string& name, EventPtr& event, 74 const std::vector<Driver>& drivers, 75 const std::vector<Interface>& ifaces, 76 sd_event_io_handler_t handler = Presence::processEvents) : 77 Evdev(path, key, event, handler, true), bus(bus), inventory(inventory), 78 name(name), drivers(drivers), ifaces(ifaces) 79 { 80 // See if the environment (from configuration file?) has a 81 // DRIVER_BIND_DELAY_MS set. 82 if (char* envDelay = std::getenv("DRIVER_BIND_DELAY_MS")) 83 { 84 // DRIVER_BIND_DELAY_MS environment variable is set. 85 // Update the bind delay (in milliseconds) to the value from the 86 // environment. 87 delay = std::strtoull(envDelay, nullptr, 10); 88 } 89 determinePresence(); 90 } 91 92 /** @brief Callback handler when the FD has some activity on it 93 * 94 * @param[in] es - Populated event source 95 * @param[in] fd - Associated File descriptor 96 * @param[in] revents - Type of event 97 * @param[in] userData - User data that was passed during registration 98 * 99 * @return - 0 or positive number on success and negative 100 * errno otherwise 101 */ 102 static int processEvents(sd_event_source* es, int fd, uint32_t revents, 103 void* userData); 104 105 private: 106 /** 107 * @brief Update the present property for the inventory item. 108 * 109 * @param[in] present - What the present property should be set to. 110 */ 111 void updateInventory(bool present); 112 113 /** 114 * @brief Construct the inventory object map for the inventory item. 115 * 116 * @param[in] present - What the present property should be set to. 117 * 118 * @return The inventory object map to update inventory 119 */ 120 ObjectMap getObjectMap(bool present); 121 122 /** @brief Connection for sdbusplus bus */ 123 sdbusplus::bus_t& bus; 124 125 /** 126 * @brief Read the GPIO device to determine initial presence and set 127 * present property at D-Bus path. 128 */ 129 void determinePresence(); 130 131 /** @brief Object path under inventory to display this inventory item */ 132 const std::string inventory; 133 134 /** @brief Delay in milliseconds from present to bind device driver */ 135 unsigned int delay = 0; 136 137 /** @brief Pretty name of the inventory item*/ 138 const std::string name; 139 140 /** @brief Analyzes the GPIO event and update present property*/ 141 void analyzeEvent(); 142 143 /** @brief Vector of path and device tuples to bind/unbind*/ 144 const std::vector<Driver> drivers; 145 146 /** @brief Vector of extra inventory interfaces to associate with the 147 * inventory item 148 */ 149 const std::vector<Interface> ifaces; 150 151 /** 152 * @brief Binds or unbinds drivers 153 * 154 * Called when a presence change is detected to either 155 * bind the drivers for the new card or unbind them for 156 * the just removed card. Operates on the drivers vector. 157 * 158 * Writes <device> to <path>/bind (or unbind) 159 * 160 * @param present - when true, will bind the drivers 161 * when false, will unbind them 162 */ 163 void bindOrUnbindDrivers(bool present); 164 }; 165 166 /** 167 * @brief Get the service name from the mapper for the 168 * interface and path passed in. 169 * 170 * @param[in] path - The D-Bus path name 171 * @param[in] interface - The D-Bus interface name 172 * @param[in] bus - The D-Bus bus object 173 * 174 * @return The service name 175 */ 176 std::string getService(const std::string& path, const std::string& interface, 177 sdbusplus::bus_t& bus); 178 179 } // namespace presence 180 } // namespace gpio 181 } // namespace phosphor 182