blob: 098adf81c7e786479289f1e918f7fc03fa73a0e8 [file] [log] [blame] [edit]
#include "gpio_controller.hpp"
#include <phosphor-logging/lg2.hpp>
#include <fstream>
#include <map>
PHOSPHOR_LOG2_USING;
GPIOGroup::GPIOGroup(std::vector<std::string> linesIn,
std::vector<bool> polaritiesIn) :
lines(std::move(linesIn)), polarities(std::move(polaritiesIn))
{}
GPIOGroup::~GPIOGroup()
{
releaseAll();
}
GPIOGroup::GPIOGroup(GPIOGroup&& other) noexcept :
lines(std::move(other.lines)), polarities(std::move(other.polarities)),
activeBulks(std::move(other.activeBulks))
{}
GPIOGroup& GPIOGroup::operator=(GPIOGroup&& other) noexcept
{
if (this != &other)
{
releaseAll();
lines = std::move(other.lines);
polarities = std::move(other.polarities);
activeBulks = std::move(other.activeBulks);
}
return *this;
}
bool GPIOGroup::muxToBMC()
{
return mux(false);
}
bool GPIOGroup::muxToDevice()
{
return mux(true);
}
void GPIOGroup::releaseAll()
{
for (auto& b : activeBulks)
{
if (b)
{
b->release();
}
}
activeBulks.clear();
}
bool GPIOGroup::mux(bool inverted)
{
if (lines.empty())
{
return true;
}
activeBulks = requestMuxGPIOs(lines, polarities, inverted);
if (activeBulks.empty())
{
error("Failed to mux GPIOs", "INVERTED", inverted);
return false;
}
return true;
}
ScopedBmcMux::ScopedBmcMux(GPIOGroup& g) : gpioGroup(g)
{
if (!gpioGroup.muxToBMC())
{
throw std::runtime_error("Failed to mux GPIOs to BMC");
}
}
ScopedBmcMux::~ScopedBmcMux()
{
gpioGroup.releaseAll();
if (!gpioGroup.muxToDevice())
{
error("Failed to mux GPIOs back to device");
}
gpioGroup.releaseAll();
}
std::vector<std::unique_ptr<::gpiod::line_bulk>> requestMuxGPIOs(
const std::vector<std::string>& gpioLines,
const std::vector<bool>& gpioPolarities, bool inverted)
{
std::map<std::string, std::vector<std::string>> groupLineNames;
std::map<std::string, std::vector<int>> groupValues;
for (size_t i = 0; i < gpioLines.size(); ++i)
{
auto line = ::gpiod::find_line(gpioLines[i]);
if (!line)
{
error("Failed to find GPIO line: {LINE}", "LINE", gpioLines[i]);
return {};
}
if (line.is_used())
{
error("GPIO line {LINE} was still used", "LINE", gpioLines[i]);
return {};
}
std::string chipName = line.get_chip().name();
groupLineNames[chipName].push_back(gpioLines[i]);
groupValues[chipName].push_back(gpioPolarities[i] ^ inverted ? 1 : 0);
}
std::vector<std::unique_ptr<::gpiod::line_bulk>> lineBulks;
::gpiod::line_request config{"", ::gpiod::line_request::DIRECTION_OUTPUT,
0};
for (auto& [chipName, lineNames] : groupLineNames)
{
::gpiod::chip chip(chipName);
std::vector<::gpiod::line> lines;
for (size_t i = 0; i < lineNames.size(); ++i)
{
const auto& name = lineNames[i];
auto line = chip.find_line(name);
if (!line)
{
error("Failed to get {LINE} from chip {CHIP}", "LINE", name,
"CHIP", chipName);
return {};
}
lg2::info("Requesting chip {CHIP}, GPIO line {LINE} to {VALUE}",
"CHIP", chip.name(), "LINE", line.name(), "VALUE",
groupValues[chipName][i]);
lines.push_back(std::move(line));
}
auto lineBulk = std::make_unique<::gpiod::line_bulk>(lines);
if (!lineBulk)
{
error("Failed to create line bulk for chip={CHIP}", "CHIP",
chipName);
return {};
}
lineBulk->request(config, groupValues[chipName]);
lineBulks.push_back(std::move(lineBulk));
}
return lineBulks;
}