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 */ 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 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