blob: b009d3fdf29802d97409c9d50d3ae3efdd9f63f5 [file] [log] [blame]
Patrick Venturedace6802018-11-01 16:52:10 -07001#include "gpio_presence.hpp"
2
3#include "xyz/openbmc_project/Common/error.hpp"
4
Gunnar Mills5f101102017-06-29 13:07:39 -05005#include <fcntl.h>
Matt Spinler902d1c32017-09-01 11:03:02 -05006#include <libevdev/libevdev.h>
Patrick Venturedace6802018-11-01 16:52:10 -07007
Patrick Venturedace6802018-11-01 16:52:10 -07008#include <phosphor-logging/elog-errors.hpp>
Gunnar Mills5f101102017-06-29 13:07:39 -05009#include <phosphor-logging/elog.hpp>
George Liu2a8848c2023-08-01 13:49:28 +080010#include <phosphor-logging/lg2.hpp>
Gunnar Mills72639152017-06-22 15:06:21 -050011
Patrick Williams39084b42023-05-10 07:50:58 -050012#include <fstream>
13
Gunnar Mills72639152017-06-22 15:06:21 -050014namespace phosphor
15{
16namespace gpio
17{
18namespace presence
19{
20
Gunnar Mills5f101102017-06-29 13:07:39 -050021using namespace phosphor::logging;
22using namespace sdbusplus::xyz::openbmc_project::Common::Error;
23
Gunnar Mills80292bb2017-07-05 16:34:51 -050024constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
25constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
26
27constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
28constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
29constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
30
Patrick Venturedace6802018-11-01 16:52:10 -070031std::string getService(const std::string& path, const std::string& interface,
Patrick Williamsbc5b3752022-07-22 19:26:56 -050032 sdbusplus::bus_t& bus)
Gunnar Mills80292bb2017-07-05 16:34:51 -050033{
Patrick Venturedace6802018-11-01 16:52:10 -070034 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
35 MAPPER_INTERFACE, "GetObject");
Gunnar Mills80292bb2017-07-05 16:34:51 -050036
37 mapperCall.append(path);
38 mapperCall.append(std::vector<std::string>({interface}));
39
George Liu7abda622023-08-01 13:54:11 +080040 std::map<std::string, std::vector<std::string>> mapperResponse;
41 try
42 {
43 auto mapperResponseMsg = bus.call(mapperCall);
44 mapperResponseMsg.read(mapperResponse);
45 }
46 catch (const sdbusplus::exception_t& e)
Gunnar Mills80292bb2017-07-05 16:34:51 -050047 {
George Liu2a8848c2023-08-01 13:49:28 +080048 lg2::error(
49 "Error in mapper call to get service name, path: {PATH}, interface: {INTERFACE}, error: {ERROR}",
50 "PATH", path, "INTERFACE", interface, "ERROR", e);
Gunnar Mills80292bb2017-07-05 16:34:51 -050051 elog<InternalFailure>();
52 }
53
54 return mapperResponse.begin()->first;
55}
56
Gunnar Mills5f101102017-06-29 13:07:39 -050057void Presence::determinePresence()
58{
Gunnar Mills80292bb2017-07-05 16:34:51 -050059 auto present = false;
Gunnar Mills5f101102017-06-29 13:07:39 -050060 auto value = static_cast<int>(0);
Patrick Williams8377d592024-08-16 15:21:08 -040061 auto fetch_rc =
62 libevdev_fetch_event_value(devicePtr.get(), EV_KEY, key, &value);
Gunnar Mills5f101102017-06-29 13:07:39 -050063 if (0 == fetch_rc)
64 {
George Liu2a8848c2023-08-01 13:49:28 +080065 lg2::error("Device does not support event type, key: {KEYCODE}",
66 "KEYCODE", key);
Gunnar Mills5f101102017-06-29 13:07:39 -050067 elog<InternalFailure>();
68 return;
69 }
Gunnar Mills80292bb2017-07-05 16:34:51 -050070 if (value > 0)
71 {
72 present = true;
73 }
74
75 updateInventory(present);
Gunnar Mills5f101102017-06-29 13:07:39 -050076}
77
Gunnar Mills765725e2017-07-06 14:17:44 -050078// Callback handler when there is an activity on the FD
Brad Bishop86d16f02019-09-19 16:07:33 -040079int Presence::processEvents(sd_event_source*, int, uint32_t, void* userData)
Gunnar Mills765725e2017-07-06 14:17:44 -050080{
81 auto presence = static_cast<Presence*>(userData);
82
83 presence->analyzeEvent();
84 return 0;
85}
86
Gunnar Mills765725e2017-07-06 14:17:44 -050087// Analyzes the GPIO event
88void Presence::analyzeEvent()
89{
Gunnar Mills765725e2017-07-06 14:17:44 -050090 // Data returned
Patrick Williams1c888032024-12-18 11:21:41 -050091 struct input_event ev{};
Gunnar Mills765725e2017-07-06 14:17:44 -050092 int rc = 0;
93
94 // While testing, observed that not having a loop here was leading
95 // into events being missed.
96 while (rc >= 0)
97 {
98 // Wait until no more events are available on the device.
Patrick Venturedace6802018-11-01 16:52:10 -070099 rc = libevdev_next_event(devicePtr.get(), LIBEVDEV_READ_FLAG_NORMAL,
100 &ev);
Gunnar Mills765725e2017-07-06 14:17:44 -0500101 if (rc < 0)
102 {
103 // There was an error waiting for events, mostly that there are no
104 // events to be read.. So continue waiting...
105 return;
106 }
107
108 if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
109 {
110 if (ev.type == EV_SYN && ev.code == SYN_REPORT)
111 {
112 continue;
113 }
114 else if (ev.code == key)
115 {
116 auto present = false;
117 if (ev.value > 0)
118 {
119 present = true;
Brandon Wymanb08a0f62021-03-03 19:53:18 -0600120 std::this_thread::sleep_for(
121 std::chrono::milliseconds(delay));
122 bindOrUnbindDrivers(present);
123 updateInventory(present);
Gunnar Mills765725e2017-07-06 14:17:44 -0500124 }
Brandon Wymanb08a0f62021-03-03 19:53:18 -0600125 else
126 {
127 updateInventory(present);
128 bindOrUnbindDrivers(present);
129 }
Gunnar Mills765725e2017-07-06 14:17:44 -0500130 }
131 }
132 }
133
134 return;
135}
Gunnar Mills80292bb2017-07-05 16:34:51 -0500136
137Presence::ObjectMap Presence::getObjectMap(bool present)
138{
139 ObjectMap invObj;
140 InterfaceMap invIntf;
141 PropertyMap invProp;
142
143 invProp.emplace("Present", present);
144 invProp.emplace("PrettyName", name);
Patrick Venturedace6802018-11-01 16:52:10 -0700145 invIntf.emplace("xyz.openbmc_project.Inventory.Item", std::move(invProp));
Anthony Wilson206f0042019-05-02 00:02:23 -0500146 // Add any extra interfaces we want to associate with the inventory item
147 for (auto& iface : ifaces)
148 {
149 invIntf.emplace(iface, PropertyMap());
150 }
Gunnar Mills80292bb2017-07-05 16:34:51 -0500151 invObj.emplace(std::move(inventory), std::move(invIntf));
152
153 return invObj;
154}
155
156void Presence::updateInventory(bool present)
157{
158 ObjectMap invObj = getObjectMap(present);
159
George Liu2a8848c2023-08-01 13:49:28 +0800160 lg2::info(
161 "Updating inventory present property value to {PRESENT}, path: {PATH}",
162 "PRESENT", present, "PATH", inventory);
Gunnar Mills765725e2017-07-06 14:17:44 -0500163
Gunnar Mills80292bb2017-07-05 16:34:51 -0500164 auto invService = getService(INVENTORY_PATH, INVENTORY_INTF, bus);
165
166 // Update inventory
Patrick Venturedace6802018-11-01 16:52:10 -0700167 auto invMsg = bus.new_method_call(invService.c_str(), INVENTORY_PATH,
168 INVENTORY_INTF, "Notify");
Gunnar Mills80292bb2017-07-05 16:34:51 -0500169 invMsg.append(std::move(invObj));
George Liu7abda622023-08-01 13:54:11 +0800170 try
Gunnar Mills80292bb2017-07-05 16:34:51 -0500171 {
George Liu7abda622023-08-01 13:54:11 +0800172 auto invMgrResponseMsg = bus.call(invMsg);
173 }
174 catch (const sdbusplus::exception_t& e)
175 {
George Liu2a8848c2023-08-01 13:49:28 +0800176 lg2::error(
177 "Error in inventory manager call to update inventory: {ERROR}",
178 "ERROR", e);
Gunnar Mills80292bb2017-07-05 16:34:51 -0500179 elog<InternalFailure>();
180 }
Matt Spinler902d1c32017-09-01 11:03:02 -0500181}
182
183void Presence::bindOrUnbindDrivers(bool present)
184{
185 auto action = (present) ? "bind" : "unbind";
186
187 for (auto& driver : drivers)
188 {
189 auto path = std::get<pathField>(driver) / action;
190 auto device = std::get<deviceField>(driver);
191
192 if (present)
193 {
George Liu2a8848c2023-08-01 13:49:28 +0800194 lg2::info("Binding a {DEVICE} driver: {PATH}", "DEVICE", device,
195 "PATH", path);
Matt Spinler902d1c32017-09-01 11:03:02 -0500196 }
197 else
198 {
George Liu2a8848c2023-08-01 13:49:28 +0800199 lg2::info("Unbinding a {DEVICE} driver: {PATH}", "DEVICE", device,
200 "PATH", path);
Matt Spinler902d1c32017-09-01 11:03:02 -0500201 }
202
203 std::ofstream file;
204
Patrick Venturedace6802018-11-01 16:52:10 -0700205 file.exceptions(std::ofstream::failbit | std::ofstream::badbit |
206 std::ofstream::eofbit);
Matt Spinler902d1c32017-09-01 11:03:02 -0500207
208 try
209 {
210 file.open(path);
211 file << device;
212 file.close();
213 }
Patrick Williams67554142021-10-06 13:00:15 -0500214 catch (const std::exception& e)
Matt Spinler902d1c32017-09-01 11:03:02 -0500215 {
George Liu2a8848c2023-08-01 13:49:28 +0800216 lg2::error(
217 "Failed binding or unbinding a {DEVICE} after a card was removed or added, path: {PATH}, error: {ERROR}",
218 "DEVICE", device, "PATH", path, "ERROR", e);
Matt Spinler902d1c32017-09-01 11:03:02 -0500219 }
220 }
Gunnar Mills80292bb2017-07-05 16:34:51 -0500221}
222
Gunnar Mills72639152017-06-22 15:06:21 -0500223} // namespace presence
224} // namespace gpio
225} // namespace phosphor