1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3
4 #include "gpio_presence.hpp"
5
6 #include <CLI/CLI.hpp>
7 #include <boost/asio/io_context.hpp>
8 #include <nlohmann/json.hpp>
9 #include <phosphor-logging/lg2.hpp>
10
11 #include <fstream>
12
13 namespace phosphor
14 {
15 namespace gpio
16 {
17
18 const std::map<std::string, int> biasMap = {
19 /**< Set bias as is. */
20 {"AS_IS", 0},
21 /**< Disable bias. */
22 {"DISABLE", GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE},
23 /**< Enable pull-up. */
24 {"PULL_UP", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP},
25 /**< Enable pull-down. */
26 {"PULL_DOWN", GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN}};
27 }
28 } // namespace phosphor
29
main(int argc,char ** argv)30 int main(int argc, char** argv)
31 {
32 boost::asio::io_context io;
33
34 CLI::App app{"Monitor gpio presence status"};
35
36 std::string gpioFileName;
37
38 /* Add an input option */
39 app.add_option("-c,--config", gpioFileName, "Name of config json file")
40 ->required()
41 ->check(CLI::ExistingFile);
42
43 /* Parse input parameter */
44 try
45 {
46 app.parse(argc, argv);
47 }
48 catch (const CLI::Error& e)
49 {
50 return app.exit(e);
51 }
52
53 /* Get list of gpio config details from json file */
54 std::ifstream file(gpioFileName);
55 if (!file)
56 {
57 lg2::error("Failed to open config file: {FILE}", "FILE", gpioFileName);
58 return -1;
59 }
60
61 nlohmann::json gpioMonObj;
62 file >> gpioMonObj;
63 file.close();
64
65 std::vector<phosphor::gpio::GpioPresence> gpios;
66
67 for (auto& obj : gpioMonObj)
68 {
69 /* GPIO Line message */
70 std::string lineMsg = "GPIO Line ";
71
72 /* GPIO line */
73 gpiod_line* line = nullptr;
74
75 /* GPIO line configuration, default to monitor both edge */
76 struct gpiod_line_request_config config{
77 "gpio_monitor", GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES, 0};
78
79 /* Pretty name of the inventory object */
80 std::string name;
81
82 /* Object path under inventory that will be created */
83 std::string inventory;
84
85 /* List of interfaces to associate to inventory item */
86 std::vector<std::string> extraInterfaces;
87
88 if (obj.find("LineName") == obj.end())
89 {
90 /* If there is no line Name defined then gpio num nd chip
91 * id must be defined. GpioNum is integer mapping to the
92 * GPIO key configured by the kernel
93 */
94 if (obj.find("GpioNum") == obj.end() ||
95 obj.find("ChipId") == obj.end())
96 {
97 lg2::error("Failed to find line name or gpio number: {FILE}",
98 "FILE", gpioFileName);
99 return -1;
100 }
101
102 std::string chipIdStr = obj["ChipId"].get<std::string>();
103 int gpioNum = obj["GpioNum"].get<int>();
104
105 lineMsg += chipIdStr + " " + std::to_string(gpioNum);
106
107 /* Get the GPIO line */
108 line = gpiod_line_get(chipIdStr.c_str(), gpioNum);
109 }
110 else
111 {
112 /* Find the GPIO line */
113 std::string lineName = obj["LineName"].get<std::string>();
114 lineMsg += lineName;
115 line = gpiod_line_find(lineName.c_str());
116 }
117
118 if (line == nullptr)
119 {
120 lg2::error("Failed to find the {GPIO}", "GPIO", lineMsg);
121 continue;
122 }
123
124 /* Parse out inventory argument. */
125 if (obj.find("Inventory") == obj.end())
126 {
127 lg2::error("{GPIO}: Inventory path not specified", "GPIO", lineMsg);
128 return -1;
129 }
130 else
131 {
132 inventory = obj["Inventory"].get<std::string>();
133 }
134
135 if (obj.find("Name") == obj.end())
136 {
137 lg2::error("{GPIO}: Name path not specified", "GPIO", lineMsg);
138 return -1;
139 }
140 else
141 {
142 name = obj["Name"].get<std::string>();
143 }
144
145 /* Parse optional bias */
146 if (obj.find("Bias") != obj.end())
147 {
148 std::string biasName = obj["Bias"].get<std::string>();
149 auto findBias = phosphor::gpio::biasMap.find(biasName);
150 if (findBias == phosphor::gpio::biasMap.end())
151 {
152 lg2::error("{GPIO}: Bias unknown: {BIAS}", "GPIO", lineMsg,
153 "BIAS", biasName);
154 return -1;
155 }
156
157 config.flags = findBias->second;
158 }
159
160 /* Parse optional active level */
161 if (obj.find("ActiveLow") != obj.end() && obj["ActiveLow"].get<bool>())
162 {
163 config.flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
164 }
165
166 /* Parse optional extra interfaces */
167 if (obj.find("ExtraInterfaces") != obj.end())
168 {
169 obj.at("ExtraInterfaces").get_to(extraInterfaces);
170 }
171
172 /* Create a monitor object and let it do all the rest */
173 gpios.push_back(phosphor::gpio::GpioPresence(
174 line, config, io, inventory, extraInterfaces, name, lineMsg));
175 }
176 io.run();
177
178 return 0;
179 }
180