blob: ba897d04188b4bec00b46b5049b9a6eb4f2c3091 [file] [log] [blame]
#include <libevdev/libevdev.h>
#include <fcntl.h>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog-errors.hpp>
#include "xyz/openbmc_project/Common/error.hpp"
#include "gpio_presence.hpp"
namespace phosphor
{
namespace gpio
{
namespace presence
{
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
std::string getService(const std::string& path,
const std::string& interface,
sdbusplus::bus::bus& bus)
{
auto mapperCall = bus.new_method_call(MAPPER_BUSNAME,
MAPPER_PATH,
MAPPER_INTERFACE,
"GetObject");
mapperCall.append(path);
mapperCall.append(std::vector<std::string>({interface}));
auto mapperResponseMsg = bus.call(mapperCall);
if (mapperResponseMsg.is_method_error())
{
log<level::ERR>("Error in mapper call to get service name",
entry("PATH=%s", path.c_str()),
entry("INTERFACE=%s", interface.c_str()));
elog<InternalFailure>();
}
std::map<std::string, std::vector<std::string>> mapperResponse;
mapperResponseMsg.read(mapperResponse);
if (mapperResponse.empty())
{
log<level::ERR>(
"Error in mapper response for getting service name",
entry("PATH=%s", path.c_str()),
entry("INTERFACE=%s", interface.c_str()));
elog<InternalFailure>();
}
return mapperResponse.begin()->first;
}
// Populate the file descriptor for passed in device
int Presence::openDevice()
{
using namespace phosphor::logging;
auto fd = open(path.c_str(), O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
log<level::ERR>("Failed to open device path",
entry("DEVICEPATH=%s", path.c_str()),
entry("ERRNO=%d", errno));
elog<InternalFailure>();
}
return fd;
}
// Initializes the event device with the fd
void Presence::initEvDev()
{
if (devicePtr)
{
// Init can be done only once per device
return;
}
struct libevdev* evdev = nullptr;
auto rc = libevdev_new_from_fd((fd)(), &evdev);
if (rc < 0)
{
log<level::ERR>("Failed to initialize evdev");
elog<InternalFailure>();
return;
}
// Packing in the unique_ptr
devicePtr.reset(evdev);
}
void Presence::determinePresence()
{
auto present = false;
auto value = static_cast<int>(0);
auto fetch_rc = libevdev_fetch_event_value(devicePtr.get(), EV_KEY,
key, &value);
if (0 == fetch_rc)
{
log<level::ERR>("Device does not support event type",
entry("KEYCODE=%d", key));
elog<InternalFailure>();
return;
}
if (value > 0)
{
present = true;
}
updateInventory(present);
}
Presence::ObjectMap Presence::getObjectMap(bool present)
{
ObjectMap invObj;
InterfaceMap invIntf;
PropertyMap invProp;
invProp.emplace("Present", present);
invProp.emplace("PrettyName", name);
invIntf.emplace("xyz.openbmc_project.Inventory.Item",
std::move(invProp));
invObj.emplace(std::move(inventory), std::move(invIntf));
return invObj;
}
void Presence::updateInventory(bool present)
{
ObjectMap invObj = getObjectMap(present);
auto invService = getService(INVENTORY_PATH, INVENTORY_INTF, bus);
// Update inventory
auto invMsg = bus.new_method_call(invService.c_str(),
INVENTORY_PATH,
INVENTORY_INTF,
"Notify");
invMsg.append(std::move(invObj));
auto invMgrResponseMsg = bus.call(invMsg);
if (invMgrResponseMsg.is_method_error())
{
log<level::ERR>(
"Error in inventory manager call to update inventory");
elog<InternalFailure>();
}
}
} // namespace presence
} // namespace gpio
} // namespace phosphor