blob: cce388f7ac31363750caf673757fd4d9f583482a [file] [log] [blame]
Christopher Meis75ff1672025-09-23 11:40:06 +02001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright OpenBMC Authors
3
Patrick Venturedace6802018-11-01 16:52:10 -07004#include "gpio_presence.hpp"
5
6#include "xyz/openbmc_project/Common/error.hpp"
7
Gunnar Mills5f101102017-06-29 13:07:39 -05008#include <fcntl.h>
Matt Spinler902d1c32017-09-01 11:03:02 -05009#include <libevdev/libevdev.h>
Patrick Venturedace6802018-11-01 16:52:10 -070010
Patrick Venturedace6802018-11-01 16:52:10 -070011#include <phosphor-logging/elog-errors.hpp>
Gunnar Mills5f101102017-06-29 13:07:39 -050012#include <phosphor-logging/elog.hpp>
George Liu2a8848c2023-08-01 13:49:28 +080013#include <phosphor-logging/lg2.hpp>
Gunnar Mills72639152017-06-22 15:06:21 -050014
Patrick Williams39084b42023-05-10 07:50:58 -050015#include <fstream>
16
Gunnar Mills72639152017-06-22 15:06:21 -050017namespace phosphor
18{
19namespace gpio
20{
21namespace presence
22{
23
Gunnar Mills5f101102017-06-29 13:07:39 -050024using namespace phosphor::logging;
25using namespace sdbusplus::xyz::openbmc_project::Common::Error;
26
Gunnar Mills80292bb2017-07-05 16:34:51 -050027constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
28constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
29
30constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
31constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
32constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
33
Patrick Venturedace6802018-11-01 16:52:10 -070034std::string getService(const std::string& path, const std::string& interface,
Patrick Williamsbc5b3752022-07-22 19:26:56 -050035 sdbusplus::bus_t& bus)
Gunnar Mills80292bb2017-07-05 16:34:51 -050036{
Patrick Venturedace6802018-11-01 16:52:10 -070037 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
38 MAPPER_INTERFACE, "GetObject");
Gunnar Mills80292bb2017-07-05 16:34:51 -050039
40 mapperCall.append(path);
41 mapperCall.append(std::vector<std::string>({interface}));
42
George Liu7abda622023-08-01 13:54:11 +080043 std::map<std::string, std::vector<std::string>> mapperResponse;
44 try
45 {
46 auto mapperResponseMsg = bus.call(mapperCall);
47 mapperResponseMsg.read(mapperResponse);
48 }
49 catch (const sdbusplus::exception_t& e)
Gunnar Mills80292bb2017-07-05 16:34:51 -050050 {
George Liu2a8848c2023-08-01 13:49:28 +080051 lg2::error(
52 "Error in mapper call to get service name, path: {PATH}, interface: {INTERFACE}, error: {ERROR}",
53 "PATH", path, "INTERFACE", interface, "ERROR", e);
Gunnar Mills80292bb2017-07-05 16:34:51 -050054 elog<InternalFailure>();
55 }
56
57 return mapperResponse.begin()->first;
58}
59
Gunnar Mills5f101102017-06-29 13:07:39 -050060void Presence::determinePresence()
61{
Gunnar Mills80292bb2017-07-05 16:34:51 -050062 auto present = false;
Gunnar Mills5f101102017-06-29 13:07:39 -050063 auto value = static_cast<int>(0);
Patrick Williams8377d592024-08-16 15:21:08 -040064 auto fetch_rc =
65 libevdev_fetch_event_value(devicePtr.get(), EV_KEY, key, &value);
Gunnar Mills5f101102017-06-29 13:07:39 -050066 if (0 == fetch_rc)
67 {
George Liu2a8848c2023-08-01 13:49:28 +080068 lg2::error("Device does not support event type, key: {KEYCODE}",
69 "KEYCODE", key);
Gunnar Mills5f101102017-06-29 13:07:39 -050070 elog<InternalFailure>();
71 return;
72 }
Gunnar Mills80292bb2017-07-05 16:34:51 -050073 if (value > 0)
74 {
75 present = true;
76 }
77
78 updateInventory(present);
Gunnar Mills5f101102017-06-29 13:07:39 -050079}
80
Gunnar Mills765725e2017-07-06 14:17:44 -050081// Callback handler when there is an activity on the FD
Brad Bishop86d16f02019-09-19 16:07:33 -040082int Presence::processEvents(sd_event_source*, int, uint32_t, void* userData)
Gunnar Mills765725e2017-07-06 14:17:44 -050083{
84 auto presence = static_cast<Presence*>(userData);
85
86 presence->analyzeEvent();
87 return 0;
88}
89
Gunnar Mills765725e2017-07-06 14:17:44 -050090// Analyzes the GPIO event
91void Presence::analyzeEvent()
92{
Gunnar Mills765725e2017-07-06 14:17:44 -050093 // Data returned
Patrick Williams1c888032024-12-18 11:21:41 -050094 struct input_event ev{};
Gunnar Mills765725e2017-07-06 14:17:44 -050095 int rc = 0;
96
97 // While testing, observed that not having a loop here was leading
98 // into events being missed.
99 while (rc >= 0)
100 {
101 // Wait until no more events are available on the device.
Patrick Venturedace6802018-11-01 16:52:10 -0700102 rc = libevdev_next_event(devicePtr.get(), LIBEVDEV_READ_FLAG_NORMAL,
103 &ev);
Gunnar Mills765725e2017-07-06 14:17:44 -0500104 if (rc < 0)
105 {
106 // There was an error waiting for events, mostly that there are no
107 // events to be read.. So continue waiting...
108 return;
109 }
110
111 if (rc == LIBEVDEV_READ_STATUS_SUCCESS)
112 {
113 if (ev.type == EV_SYN && ev.code == SYN_REPORT)
114 {
115 continue;
116 }
117 else if (ev.code == key)
118 {
119 auto present = false;
120 if (ev.value > 0)
121 {
122 present = true;
Brandon Wymanb08a0f62021-03-03 19:53:18 -0600123 std::this_thread::sleep_for(
124 std::chrono::milliseconds(delay));
125 bindOrUnbindDrivers(present);
126 updateInventory(present);
Gunnar Mills765725e2017-07-06 14:17:44 -0500127 }
Brandon Wymanb08a0f62021-03-03 19:53:18 -0600128 else
129 {
130 updateInventory(present);
131 bindOrUnbindDrivers(present);
132 }
Gunnar Mills765725e2017-07-06 14:17:44 -0500133 }
134 }
135 }
136
137 return;
138}
Gunnar Mills80292bb2017-07-05 16:34:51 -0500139
140Presence::ObjectMap Presence::getObjectMap(bool present)
141{
142 ObjectMap invObj;
143 InterfaceMap invIntf;
144 PropertyMap invProp;
145
146 invProp.emplace("Present", present);
147 invProp.emplace("PrettyName", name);
Patrick Venturedace6802018-11-01 16:52:10 -0700148 invIntf.emplace("xyz.openbmc_project.Inventory.Item", std::move(invProp));
Anthony Wilson206f0042019-05-02 00:02:23 -0500149 // Add any extra interfaces we want to associate with the inventory item
150 for (auto& iface : ifaces)
151 {
152 invIntf.emplace(iface, PropertyMap());
153 }
Gunnar Mills80292bb2017-07-05 16:34:51 -0500154 invObj.emplace(std::move(inventory), std::move(invIntf));
155
156 return invObj;
157}
158
159void Presence::updateInventory(bool present)
160{
161 ObjectMap invObj = getObjectMap(present);
162
George Liu2a8848c2023-08-01 13:49:28 +0800163 lg2::info(
164 "Updating inventory present property value to {PRESENT}, path: {PATH}",
165 "PRESENT", present, "PATH", inventory);
Gunnar Mills765725e2017-07-06 14:17:44 -0500166
Gunnar Mills80292bb2017-07-05 16:34:51 -0500167 auto invService = getService(INVENTORY_PATH, INVENTORY_INTF, bus);
168
169 // Update inventory
Patrick Venturedace6802018-11-01 16:52:10 -0700170 auto invMsg = bus.new_method_call(invService.c_str(), INVENTORY_PATH,
171 INVENTORY_INTF, "Notify");
Gunnar Mills80292bb2017-07-05 16:34:51 -0500172 invMsg.append(std::move(invObj));
George Liu7abda622023-08-01 13:54:11 +0800173 try
Gunnar Mills80292bb2017-07-05 16:34:51 -0500174 {
George Liu7abda622023-08-01 13:54:11 +0800175 auto invMgrResponseMsg = bus.call(invMsg);
176 }
177 catch (const sdbusplus::exception_t& e)
178 {
George Liu2a8848c2023-08-01 13:49:28 +0800179 lg2::error(
180 "Error in inventory manager call to update inventory: {ERROR}",
181 "ERROR", e);
Gunnar Mills80292bb2017-07-05 16:34:51 -0500182 elog<InternalFailure>();
183 }
Matt Spinler902d1c32017-09-01 11:03:02 -0500184}
185
186void Presence::bindOrUnbindDrivers(bool present)
187{
188 auto action = (present) ? "bind" : "unbind";
189
190 for (auto& driver : drivers)
191 {
192 auto path = std::get<pathField>(driver) / action;
193 auto device = std::get<deviceField>(driver);
194
195 if (present)
196 {
George Liu2a8848c2023-08-01 13:49:28 +0800197 lg2::info("Binding a {DEVICE} driver: {PATH}", "DEVICE", device,
198 "PATH", path);
Matt Spinler902d1c32017-09-01 11:03:02 -0500199 }
200 else
201 {
George Liu2a8848c2023-08-01 13:49:28 +0800202 lg2::info("Unbinding a {DEVICE} driver: {PATH}", "DEVICE", device,
203 "PATH", path);
Matt Spinler902d1c32017-09-01 11:03:02 -0500204 }
205
206 std::ofstream file;
207
Patrick Venturedace6802018-11-01 16:52:10 -0700208 file.exceptions(std::ofstream::failbit | std::ofstream::badbit |
209 std::ofstream::eofbit);
Matt Spinler902d1c32017-09-01 11:03:02 -0500210
211 try
212 {
213 file.open(path);
214 file << device;
215 file.close();
216 }
Patrick Williams67554142021-10-06 13:00:15 -0500217 catch (const std::exception& e)
Matt Spinler902d1c32017-09-01 11:03:02 -0500218 {
George Liu2a8848c2023-08-01 13:49:28 +0800219 lg2::error(
220 "Failed binding or unbinding a {DEVICE} after a card was removed or added, path: {PATH}, error: {ERROR}",
221 "DEVICE", device, "PATH", path, "ERROR", e);
Matt Spinler902d1c32017-09-01 11:03:02 -0500222 }
223 }
Gunnar Mills80292bb2017-07-05 16:34:51 -0500224}
225
Gunnar Mills72639152017-06-22 15:06:21 -0500226} // namespace presence
227} // namespace gpio
228} // namespace phosphor