1 #include "gpio_presence.hpp"
2
3 #include <systemd/sd-event.h>
4
5 #include <CLI/CLI.hpp>
6 #include <phosphor-logging/lg2.hpp>
7
8 #include <iostream>
9
10 using namespace phosphor::gpio;
11 using namespace phosphor::gpio::presence;
12
13 /**
14 * Pulls out the path,device pairs from the string
15 * passed in
16 *
17 * @param[in] driverString - space separated path,device pairs
18 * @param[out] drivers - vector of device,path tuples filled in
19 * from driverString
20 *
21 * @return int - 0 if successful, < 0 else
22 */
getDrivers(const std::string & driverString,std::vector<Driver> & drivers)23 static int getDrivers(const std::string& driverString,
24 std::vector<Driver>& drivers)
25 {
26 std::istringstream stream{driverString};
27
28 while (true)
29 {
30 std::string entry;
31
32 // Extract each path,device pair
33 stream >> entry;
34
35 if (entry.empty())
36 {
37 break;
38 }
39
40 // Extract the path and device and save them
41 auto pos = entry.rfind(',');
42 if (pos != std::string::npos)
43 {
44 auto path = entry.substr(0, pos);
45 auto device = entry.substr(pos + 1);
46
47 drivers.emplace_back(std::move(device), std::move(path));
48 }
49 else
50 {
51 lg2::error("Invalid path,device combination: {ENTRY}", "ENTRY",
52 entry);
53 return -1;
54 }
55 }
56
57 return 0;
58 }
59
main(int argc,char ** argv)60 int main(int argc, char** argv)
61 {
62 CLI::App app{"Monitor gpio presence status"};
63
64 std::string path{};
65 std::string key{};
66 std::string name{};
67 std::string inventory{};
68 std::string drivers{};
69 std::string ifaces{};
70
71 /* Add an input option */
72 app.add_option(
73 "-p,--path", path,
74 " Path of device to read for GPIO pin state to determine presence of inventory item")
75 ->required();
76 app.add_option("-k,--key", key, "Input GPIO key number")->required();
77 app.add_option("-n,--name", name, "Pretty name of the inventory item")
78 ->required();
79 app.add_option("-i,--inventory", inventory,
80 "Object path under inventory that will be created")
81 ->required();
82 app.add_option(
83 "-d,--drivers", drivers,
84 "List of drivers to bind when card is added and unbind when card is removed\n"
85 "Format is a space separated list of path,device pairs.\n"
86 "For example: /sys/bus/i2c/drivers/some-driver,3-0068")
87 ->expected(0, 1);
88 app.add_option(
89 "-e,--extra-ifaces", ifaces,
90 "List of interfaces to associate to inventory item\n"
91 "Format is a comma separated list of interfaces.\n"
92 "For example: /xyz/openbmc_project/.../1,/xyz/openbmc_project/.../2")
93 ->expected(0, 1);
94
95 /* Parse input parameter */
96 try
97 {
98 app.parse(argc, argv);
99 }
100 catch (const CLI::Error& e)
101 {
102 return app.exit(e);
103 }
104
105 std::vector<Driver> driverList;
106
107 // Driver list is optional
108 if (!drivers.empty())
109 {
110 if (getDrivers(drivers, driverList) < 0)
111 {
112 lg2::error("Failed to parser drivers: {DRIVERS}", "DRIVERS",
113 drivers);
114 return -1;
115 }
116 }
117
118 std::vector<Interface> ifaceList;
119
120 // Extra interfaces list is optional
121 if (!ifaces.empty())
122 {
123 std::stringstream ss(ifaces);
124 Interface iface;
125 while (std::getline(ss, iface, ','))
126 {
127 ifaceList.push_back(iface);
128 }
129 }
130
131 auto bus = sdbusplus::bus::new_default();
132 auto rc = 0;
133 sd_event* event = nullptr;
134 rc = sd_event_default(&event);
135 if (rc < 0)
136 {
137 lg2::error("Error creating a default sd_event handler");
138 return rc;
139 }
140 EventPtr eventP{event};
141 event = nullptr;
142
143 Presence presence(bus, inventory, path, std::stoul(key), name, eventP,
144 driverList, ifaceList);
145
146 while (true)
147 {
148 // -1 denotes wait forever
149 rc = sd_event_run(eventP.get(), (uint64_t)-1);
150 if (rc < 0)
151 {
152 lg2::error("Failure in processing request: {RC}", "RC", rc);
153 break;
154 }
155 }
156 return rc;
157 }
158