blob: b6ea47af2b0dcda4a44d271190d35096995c8e5a [file] [log] [blame]
#pragma once
#include "evdev.hpp"
#include <systemd/sd-event.h>
#include <sdbusplus/bus.hpp>
#include <cstdlib>
#include <filesystem>
#include <string>
namespace phosphor
{
namespace gpio
{
namespace presence
{
static constexpr auto deviceField = 0;
static constexpr auto pathField = 1;
using Device = std::string;
using Path = std::filesystem::path;
using Driver = std::tuple<Device, Path>;
using Interface = std::string;
/** @class Presence
* @brief Responsible for determining and monitoring presence,
* by monitoring GPIO state changes, of inventory items and
* updating D-Bus accordingly.
*/
class Presence : public 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:
Presence() = delete;
~Presence() = default;
Presence(const Presence&) = delete;
Presence& operator=(const Presence&) = delete;
Presence(Presence&&) = delete;
Presence& operator=(Presence&&) = delete;
/** @brief Constructs Presence object.
*
* @param[in] bus - D-Bus bus Object
* @param[in] inventory - Object path under inventory
to display this inventory item
* @param[in] path - Device path to read for GPIO pin state
to determine presence of inventory item
* @param[in] key - GPIO key to monitor
* @param[in] name - Pretty name of the inventory item
* @param[in] event - sd_event handler
* @param[in] drivers - list of device drivers to bind and unbind
* @param[in] ifaces - list of extra interfaces to associate with the
* inventory item
* @param[in] handler - IO callback handler. Defaults to one in this
* class
*/
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) :
Evdev(path, key, event, handler, true),
bus(bus), inventory(inventory), name(name), drivers(drivers),
ifaces(ifaces)
{
// See if the environment (from configuration file?) has a
// DRIVER_BIND_DELAY_MS set.
if (char* envDelay = std::getenv("DRIVER_BIND_DELAY_MS"))
{
// DRIVER_BIND_DELAY_MS environment variable is set.
// Update the bind delay (in milliseconds) to the value from the
// environment.
delay = std::strtoull(envDelay, NULL, 10);
}
determinePresence();
}
/** @brief Callback handler when the FD has some activity on it
*
* @param[in] es - Populated event source
* @param[in] fd - Associated File descriptor
* @param[in] revents - Type of event
* @param[in] userData - User data that was passed during registration
*
* @return - 0 or positive number on success and negative
* errno otherwise
*/
static int processEvents(sd_event_source* es, int fd, uint32_t revents,
void* userData);
private:
/**
* @brief Update the present property for the inventory item.
*
* @param[in] present - What the present property should be set to.
*/
void updateInventory(bool present);
/**
* @brief Construct the inventory object map for the inventory item.
*
* @param[in] present - What the present property should be set to.
*
* @return The inventory object map to update inventory
*/
ObjectMap getObjectMap(bool present);
/** @brief Connection for sdbusplus bus */
sdbusplus::bus_t& bus;
/**
* @brief Read the GPIO device to determine initial presence and set
* present property at D-Bus path.
*/
void determinePresence();
/** @brief Object path under inventory to display this inventory item */
const std::string inventory;
/** @brief Delay in milliseconds from present to bind device driver */
unsigned int delay = 0;
/** @brief Pretty name of the inventory item*/
const std::string name;
/** @brief Analyzes the GPIO event and update present property*/
void analyzeEvent();
/** @brief Vector of path and device tuples to bind/unbind*/
const std::vector<Driver> drivers;
/** @brief Vector of extra inventory interfaces to associate with the
* inventory item
*/
const std::vector<Interface> ifaces;
/**
* @brief Binds or unbinds drivers
*
* Called when a presence change is detected to either
* bind the drivers for the new card or unbind them for
* the just removed card. Operates on the drivers vector.
*
* Writes <device> to <path>/bind (or unbind)
*
* @param present - when true, will bind the drivers
* when false, will unbind them
*/
void bindOrUnbindDrivers(bool present);
};
/**
* @brief Get the service name from the mapper for the
* interface and path passed in.
*
* @param[in] path - The D-Bus path name
* @param[in] interface - The D-Bus interface name
* @param[in] bus - The D-Bus bus object
*
* @return The service name
*/
std::string getService(const std::string& path, const std::string& interface,
sdbusplus::bus_t& bus);
} // namespace presence
} // namespace gpio
} // namespace phosphor