1dace680fSPatrick Venture #include "gpio_presence.hpp"
2dace680fSPatrick Venture
3dace680fSPatrick Venture #include "xyz/openbmc_project/Common/error.hpp"
4dace680fSPatrick Venture
55f101103SGunnar Mills #include <fcntl.h>
6902d1c37SMatt Spinler #include <libevdev/libevdev.h>
7dace680fSPatrick Venture
8dace680fSPatrick Venture #include <phosphor-logging/elog-errors.hpp>
95f101103SGunnar Mills #include <phosphor-logging/elog.hpp>
102a8848c6SGeorge Liu #include <phosphor-logging/lg2.hpp>
117263915aSGunnar Mills
1239084b4aSPatrick Williams #include <fstream>
1339084b4aSPatrick Williams
147263915aSGunnar Mills namespace phosphor
157263915aSGunnar Mills {
167263915aSGunnar Mills namespace gpio
177263915aSGunnar Mills {
187263915aSGunnar Mills namespace presence
197263915aSGunnar Mills {
207263915aSGunnar Mills
215f101103SGunnar Mills using namespace phosphor::logging;
225f101103SGunnar Mills using namespace sdbusplus::xyz::openbmc_project::Common::Error;
235f101103SGunnar Mills
2480292bbeSGunnar Mills constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
2580292bbeSGunnar Mills constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
2680292bbeSGunnar Mills
2780292bbeSGunnar Mills constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
2880292bbeSGunnar Mills constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
2980292bbeSGunnar Mills constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
3080292bbeSGunnar Mills
getService(const std::string & path,const std::string & interface,sdbusplus::bus_t & bus)31dace680fSPatrick Venture std::string getService(const std::string& path, const std::string& interface,
32bc5b3751SPatrick Williams sdbusplus::bus_t& bus)
3380292bbeSGunnar Mills {
34dace680fSPatrick Venture auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
35dace680fSPatrick Venture MAPPER_INTERFACE, "GetObject");
3680292bbeSGunnar Mills
3780292bbeSGunnar Mills mapperCall.append(path);
3880292bbeSGunnar Mills mapperCall.append(std::vector<std::string>({interface}));
3980292bbeSGunnar Mills
407abda62cSGeorge Liu std::map<std::string, std::vector<std::string>> mapperResponse;
417abda62cSGeorge Liu try
427abda62cSGeorge Liu {
4380292bbeSGunnar Mills auto mapperResponseMsg = bus.call(mapperCall);
447abda62cSGeorge Liu mapperResponseMsg.read(mapperResponse);
457abda62cSGeorge Liu }
467abda62cSGeorge Liu catch (const sdbusplus::exception_t& e)
4780292bbeSGunnar Mills {
482a8848c6SGeorge Liu lg2::error(
492a8848c6SGeorge Liu "Error in mapper call to get service name, path: {PATH}, interface: {INTERFACE}, error: {ERROR}",
502a8848c6SGeorge Liu "PATH", path, "INTERFACE", interface, "ERROR", e);
5180292bbeSGunnar Mills elog<InternalFailure>();
5280292bbeSGunnar Mills }
5380292bbeSGunnar Mills
5480292bbeSGunnar Mills return mapperResponse.begin()->first;
5580292bbeSGunnar Mills }
5680292bbeSGunnar Mills
determinePresence()575f101103SGunnar Mills void Presence::determinePresence()
585f101103SGunnar Mills {
5980292bbeSGunnar Mills auto present = false;
605f101103SGunnar Mills auto value = static_cast<int>(0);
618377d59cSPatrick Williams auto fetch_rc =
628377d59cSPatrick Williams libevdev_fetch_event_value(devicePtr.get(), EV_KEY, key, &value);
635f101103SGunnar Mills if (0 == fetch_rc)
645f101103SGunnar Mills {
652a8848c6SGeorge Liu lg2::error("Device does not support event type, key: {KEYCODE}",
662a8848c6SGeorge Liu "KEYCODE", key);
675f101103SGunnar Mills elog<InternalFailure>();
685f101103SGunnar Mills return;
695f101103SGunnar Mills }
7080292bbeSGunnar Mills if (value > 0)
7180292bbeSGunnar Mills {
7280292bbeSGunnar Mills present = true;
735f101103SGunnar Mills }
745f101103SGunnar Mills
7580292bbeSGunnar Mills updateInventory(present);
7680292bbeSGunnar Mills }
7780292bbeSGunnar Mills
78765725e0SGunnar Mills // Callback handler when there is an activity on the FD
processEvents(sd_event_source *,int,uint32_t,void * userData)7986d16f03SBrad Bishop int Presence::processEvents(sd_event_source*, int, uint32_t, void* userData)
80765725e0SGunnar Mills {
81765725e0SGunnar Mills auto presence = static_cast<Presence*>(userData);
82765725e0SGunnar Mills
83765725e0SGunnar Mills presence->analyzeEvent();
84765725e0SGunnar Mills return 0;
85765725e0SGunnar Mills }
86765725e0SGunnar Mills
87765725e0SGunnar Mills // Analyzes the GPIO event
analyzeEvent()88765725e0SGunnar Mills void Presence::analyzeEvent()
89765725e0SGunnar Mills {
90765725e0SGunnar Mills // Data returned
91*1c88803fSPatrick Williams struct input_event ev{};
92765725e0SGunnar Mills int rc = 0;
93765725e0SGunnar Mills
94765725e0SGunnar Mills // While testing, observed that not having a loop here was leading
95765725e0SGunnar Mills // into events being missed.
96765725e0SGunnar Mills while (rc >= 0)
97765725e0SGunnar Mills {
98765725e0SGunnar Mills // Wait until no more events are available on the device.
99dace680fSPatrick Venture rc = libevdev_next_event(devicePtr.get(), LIBEVDEV_READ_FLAG_NORMAL,
100dace680fSPatrick Venture &ev);
101765725e0SGunnar Mills if (rc < 0)
102765725e0SGunnar Mills {
103765725e0SGunnar Mills // There was an error waiting for events, mostly that there are no
104765725e0SGunnar Mills // events to be read.. So continue waiting...
105765725e0SGunnar Mills return;
106765725e0SGunnar Mills }
107765725e0SGunnar Mills
108765725e0SGunnar Mills if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
109765725e0SGunnar Mills {
110765725e0SGunnar Mills if (ev.type == EV_SYN && ev.code == SYN_REPORT)
111765725e0SGunnar Mills {
112765725e0SGunnar Mills continue;
113765725e0SGunnar Mills }
114765725e0SGunnar Mills else if (ev.code == key)
115765725e0SGunnar Mills {
116765725e0SGunnar Mills auto present = false;
117765725e0SGunnar Mills if (ev.value > 0)
118765725e0SGunnar Mills {
119765725e0SGunnar Mills present = true;
120b08a0f69SBrandon Wyman std::this_thread::sleep_for(
121b08a0f69SBrandon Wyman std::chrono::milliseconds(delay));
122b08a0f69SBrandon Wyman bindOrUnbindDrivers(present);
123b08a0f69SBrandon Wyman updateInventory(present);
124765725e0SGunnar Mills }
125b08a0f69SBrandon Wyman else
126b08a0f69SBrandon Wyman {
127765725e0SGunnar Mills updateInventory(present);
128902d1c37SMatt Spinler bindOrUnbindDrivers(present);
129765725e0SGunnar Mills }
130765725e0SGunnar Mills }
131765725e0SGunnar Mills }
132b08a0f69SBrandon Wyman }
133765725e0SGunnar Mills
134765725e0SGunnar Mills return;
135765725e0SGunnar Mills }
13680292bbeSGunnar Mills
getObjectMap(bool present)13780292bbeSGunnar Mills Presence::ObjectMap Presence::getObjectMap(bool present)
13880292bbeSGunnar Mills {
13980292bbeSGunnar Mills ObjectMap invObj;
14080292bbeSGunnar Mills InterfaceMap invIntf;
14180292bbeSGunnar Mills PropertyMap invProp;
14280292bbeSGunnar Mills
14380292bbeSGunnar Mills invProp.emplace("Present", present);
14480292bbeSGunnar Mills invProp.emplace("PrettyName", name);
145dace680fSPatrick Venture invIntf.emplace("xyz.openbmc_project.Inventory.Item", std::move(invProp));
146206f0040SAnthony Wilson // Add any extra interfaces we want to associate with the inventory item
147206f0040SAnthony Wilson for (auto& iface : ifaces)
148206f0040SAnthony Wilson {
149206f0040SAnthony Wilson invIntf.emplace(iface, PropertyMap());
150206f0040SAnthony Wilson }
15180292bbeSGunnar Mills invObj.emplace(std::move(inventory), std::move(invIntf));
15280292bbeSGunnar Mills
15380292bbeSGunnar Mills return invObj;
15480292bbeSGunnar Mills }
15580292bbeSGunnar Mills
updateInventory(bool present)15680292bbeSGunnar Mills void Presence::updateInventory(bool present)
15780292bbeSGunnar Mills {
15880292bbeSGunnar Mills ObjectMap invObj = getObjectMap(present);
15980292bbeSGunnar Mills
1602a8848c6SGeorge Liu lg2::info(
1612a8848c6SGeorge Liu "Updating inventory present property value to {PRESENT}, path: {PATH}",
1622a8848c6SGeorge Liu "PRESENT", present, "PATH", inventory);
163765725e0SGunnar Mills
16480292bbeSGunnar Mills auto invService = getService(INVENTORY_PATH, INVENTORY_INTF, bus);
16580292bbeSGunnar Mills
16680292bbeSGunnar Mills // Update inventory
167dace680fSPatrick Venture auto invMsg = bus.new_method_call(invService.c_str(), INVENTORY_PATH,
168dace680fSPatrick Venture INVENTORY_INTF, "Notify");
16980292bbeSGunnar Mills invMsg.append(std::move(invObj));
1707abda62cSGeorge Liu try
17180292bbeSGunnar Mills {
1727abda62cSGeorge Liu auto invMgrResponseMsg = bus.call(invMsg);
1737abda62cSGeorge Liu }
1747abda62cSGeorge Liu catch (const sdbusplus::exception_t& e)
1757abda62cSGeorge Liu {
1762a8848c6SGeorge Liu lg2::error(
1772a8848c6SGeorge Liu "Error in inventory manager call to update inventory: {ERROR}",
1782a8848c6SGeorge Liu "ERROR", e);
17980292bbeSGunnar Mills elog<InternalFailure>();
18080292bbeSGunnar Mills }
181902d1c37SMatt Spinler }
182902d1c37SMatt Spinler
bindOrUnbindDrivers(bool present)183902d1c37SMatt Spinler void Presence::bindOrUnbindDrivers(bool present)
184902d1c37SMatt Spinler {
185902d1c37SMatt Spinler auto action = (present) ? "bind" : "unbind";
186902d1c37SMatt Spinler
187902d1c37SMatt Spinler for (auto& driver : drivers)
188902d1c37SMatt Spinler {
189902d1c37SMatt Spinler auto path = std::get<pathField>(driver) / action;
190902d1c37SMatt Spinler auto device = std::get<deviceField>(driver);
191902d1c37SMatt Spinler
192902d1c37SMatt Spinler if (present)
193902d1c37SMatt Spinler {
1942a8848c6SGeorge Liu lg2::info("Binding a {DEVICE} driver: {PATH}", "DEVICE", device,
1952a8848c6SGeorge Liu "PATH", path);
196902d1c37SMatt Spinler }
197902d1c37SMatt Spinler else
198902d1c37SMatt Spinler {
1992a8848c6SGeorge Liu lg2::info("Unbinding a {DEVICE} driver: {PATH}", "DEVICE", device,
2002a8848c6SGeorge Liu "PATH", path);
201902d1c37SMatt Spinler }
202902d1c37SMatt Spinler
203902d1c37SMatt Spinler std::ofstream file;
204902d1c37SMatt Spinler
205dace680fSPatrick Venture file.exceptions(std::ofstream::failbit | std::ofstream::badbit |
206902d1c37SMatt Spinler std::ofstream::eofbit);
207902d1c37SMatt Spinler
208902d1c37SMatt Spinler try
209902d1c37SMatt Spinler {
210902d1c37SMatt Spinler file.open(path);
211902d1c37SMatt Spinler file << device;
212902d1c37SMatt Spinler file.close();
213902d1c37SMatt Spinler }
21467554144SPatrick Williams catch (const std::exception& e)
215902d1c37SMatt Spinler {
2162a8848c6SGeorge Liu lg2::error(
2172a8848c6SGeorge Liu "Failed binding or unbinding a {DEVICE} after a card was removed or added, path: {PATH}, error: {ERROR}",
2182a8848c6SGeorge Liu "DEVICE", device, "PATH", path, "ERROR", e);
219902d1c37SMatt Spinler }
220902d1c37SMatt Spinler }
22180292bbeSGunnar Mills }
22280292bbeSGunnar Mills
2237263915aSGunnar Mills } // namespace presence
2247263915aSGunnar Mills } // namespace gpio
2257263915aSGunnar Mills } // namespace phosphor
226