1 #include "gpio_controller.hpp"
2
3 #include <phosphor-logging/lg2.hpp>
4
5 #include <fstream>
6 #include <map>
7
8 PHOSPHOR_LOG2_USING;
9
GPIOGroup(std::vector<std::string> linesIn,std::vector<bool> polaritiesIn)10 GPIOGroup::GPIOGroup(std::vector<std::string> linesIn,
11 std::vector<bool> polaritiesIn) :
12 lines(std::move(linesIn)), polarities(std::move(polaritiesIn))
13 {}
14
~GPIOGroup()15 GPIOGroup::~GPIOGroup()
16 {
17 releaseAll();
18 }
19
GPIOGroup(GPIOGroup && other)20 GPIOGroup::GPIOGroup(GPIOGroup&& other) noexcept :
21 lines(std::move(other.lines)), polarities(std::move(other.polarities)),
22 activeBulks(std::move(other.activeBulks))
23 {}
24
operator =(GPIOGroup && other)25 GPIOGroup& GPIOGroup::operator=(GPIOGroup&& other) noexcept
26 {
27 if (this != &other)
28 {
29 releaseAll();
30 lines = std::move(other.lines);
31 polarities = std::move(other.polarities);
32 activeBulks = std::move(other.activeBulks);
33 }
34 return *this;
35 }
36
muxToBMC()37 bool GPIOGroup::muxToBMC()
38 {
39 return mux(false);
40 }
muxToDevice()41 bool GPIOGroup::muxToDevice()
42 {
43 return mux(true);
44 }
45
releaseAll()46 void GPIOGroup::releaseAll()
47 {
48 for (auto& b : activeBulks)
49 {
50 if (b)
51 {
52 b->release();
53 }
54 }
55 activeBulks.clear();
56 }
57
mux(bool inverted)58 bool GPIOGroup::mux(bool inverted)
59 {
60 if (lines.empty())
61 {
62 return true;
63 }
64
65 activeBulks = requestMuxGPIOs(lines, polarities, inverted);
66 if (activeBulks.empty())
67 {
68 error("Failed to mux GPIOs", "INVERTED", inverted);
69 return false;
70 }
71 return true;
72 }
73
ScopedBmcMux(GPIOGroup & g)74 ScopedBmcMux::ScopedBmcMux(GPIOGroup& g) : gpioGroup(g)
75 {
76 if (!gpioGroup.muxToBMC())
77 {
78 throw std::runtime_error("Failed to mux GPIOs to BMC");
79 }
80 }
~ScopedBmcMux()81 ScopedBmcMux::~ScopedBmcMux()
82 {
83 gpioGroup.releaseAll();
84 if (!gpioGroup.muxToDevice())
85 {
86 error("Failed to mux GPIOs back to device");
87 }
88 gpioGroup.releaseAll();
89 }
90
requestMuxGPIOs(const std::vector<std::string> & gpioLines,const std::vector<bool> & gpioPolarities,bool inverted)91 std::vector<std::unique_ptr<::gpiod::line_bulk>> requestMuxGPIOs(
92 const std::vector<std::string>& gpioLines,
93 const std::vector<bool>& gpioPolarities, bool inverted)
94 {
95 std::map<std::string, std::vector<std::string>> groupLineNames;
96 std::map<std::string, std::vector<int>> groupValues;
97
98 for (size_t i = 0; i < gpioLines.size(); ++i)
99 {
100 auto line = ::gpiod::find_line(gpioLines[i]);
101
102 if (!line)
103 {
104 error("Failed to find GPIO line: {LINE}", "LINE", gpioLines[i]);
105 return {};
106 }
107
108 if (line.is_used())
109 {
110 error("GPIO line {LINE} was still used", "LINE", gpioLines[i]);
111 return {};
112 }
113
114 std::string chipName = line.get_chip().name();
115 groupLineNames[chipName].push_back(gpioLines[i]);
116 groupValues[chipName].push_back(gpioPolarities[i] ^ inverted ? 1 : 0);
117 }
118
119 std::vector<std::unique_ptr<::gpiod::line_bulk>> lineBulks;
120 ::gpiod::line_request config{"", ::gpiod::line_request::DIRECTION_OUTPUT,
121 0};
122
123 for (auto& [chipName, lineNames] : groupLineNames)
124 {
125 ::gpiod::chip chip(chipName);
126 std::vector<::gpiod::line> lines;
127
128 for (size_t i = 0; i < lineNames.size(); ++i)
129 {
130 const auto& name = lineNames[i];
131 auto line = chip.find_line(name);
132
133 if (!line)
134 {
135 error("Failed to get {LINE} from chip {CHIP}", "LINE", name,
136 "CHIP", chipName);
137 return {};
138 }
139
140 lg2::info("Requesting chip {CHIP}, GPIO line {LINE} to {VALUE}",
141 "CHIP", chip.name(), "LINE", line.name(), "VALUE",
142 groupValues[chipName][i]);
143
144 lines.push_back(std::move(line));
145 }
146
147 auto lineBulk = std::make_unique<::gpiod::line_bulk>(lines);
148
149 if (!lineBulk)
150 {
151 error("Failed to create line bulk for chip={CHIP}", "CHIP",
152 chipName);
153 return {};
154 }
155
156 lineBulk->request(config, groupValues[chipName]);
157
158 lineBulks.push_back(std::move(lineBulk));
159 }
160
161 return lineBulks;
162 }
163