blob: 338248f3223bcae5c23819b1a14e8e53c713634e [file] [log] [blame]
Patrick Rudolph46a9a5b2023-08-10 18:32:05 +02001/**
2 * Copyright © 2019 Facebook
3 * Copyright © 2023 9elements GmbH
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "gpio_presence.hpp"
19
20#include "xyz/openbmc_project/Common/error.hpp"
21
22#include <phosphor-logging/elog-errors.hpp>
23#include <phosphor-logging/elog.hpp>
24#include <phosphor-logging/lg2.hpp>
25#include <sdbusplus/bus.hpp>
26
27namespace phosphor
28{
29namespace gpio
30{
31
32using namespace phosphor::logging;
33using namespace sdbusplus::xyz::openbmc_project::Common::Error;
34
35constexpr auto INVENTORY_PATH = "/xyz/openbmc_project/inventory";
36constexpr auto INVENTORY_INTF = "xyz.openbmc_project.Inventory.Manager";
37
38constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
39constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
40constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
41
42std::string getService(const std::string& path, const std::string& interface,
43 sdbusplus::bus_t& bus)
44{
45 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
46 MAPPER_INTERFACE, "GetObject");
47
48 mapperCall.append(path);
49 mapperCall.append(std::vector<std::string>({interface}));
50
51 std::map<std::string, std::vector<std::string>> mapperResponse;
52 try
53 {
54 auto mapperResponseMsg = bus.call(mapperCall);
55 mapperResponseMsg.read(mapperResponse);
56 }
57 catch (const sdbusplus::exception_t& e)
58 {
59 lg2::error(
60 "Error in mapper call to get service name, path: {PATH}, interface: {INTERFACE}, error: {ERROR}",
61 "PATH", path, "INTERFACE", interface, "ERROR", e);
62 elog<InternalFailure>();
63 }
64
65 return mapperResponse.begin()->first;
66}
67
68GpioPresence::ObjectMap GpioPresence::getObjectMap(bool present)
69{
70 ObjectMap invObj;
71 InterfaceMap invIntf;
72 PropertyMap invProp;
73
74 invProp.emplace("Present", present);
75 invProp.emplace("PrettyName", name);
76 invIntf.emplace("xyz.openbmc_project.Inventory.Item", std::move(invProp));
77 // Add any extra interfaces we want to associate with the inventory item
78 for (auto& iface : interfaces)
79 {
80 invIntf.emplace(iface, PropertyMap());
81 }
82 invObj.emplace(std::move(inventory), std::move(invIntf));
83
84 return invObj;
85}
86
87void GpioPresence::updateInventory(bool present)
88{
89 ObjectMap invObj = getObjectMap(present);
90
91 lg2::info(
92 "Updating inventory present property value to {PRESENT}, path: {PATH}",
93 "PRESENT", present, "PATH", inventory);
94
95 auto bus = sdbusplus::bus::new_default();
96 auto invService = getService(INVENTORY_PATH, INVENTORY_INTF, bus);
97
98 // Update inventory
99 auto invMsg = bus.new_method_call(invService.c_str(), INVENTORY_PATH,
100 INVENTORY_INTF, "Notify");
101 invMsg.append(std::move(invObj));
102 try
103 {
104 auto invMgrResponseMsg = bus.call(invMsg);
105 }
106 catch (const sdbusplus::exception_t& e)
107 {
108 lg2::error(
109 "Error in inventory manager call to update inventory: {ERROR}",
110 "ERROR", e);
111 elog<InternalFailure>();
112 }
113}
114
115void GpioPresence::scheduleEventHandler()
116{
117 std::string gpio = std::string(gpioLineMsg);
118
119 gpioEventDescriptor.async_wait(
120 boost::asio::posix::stream_descriptor::wait_read,
121 [this, gpio](const boost::system::error_code& ec) {
122 if (ec == boost::asio::error::operation_aborted)
123 {
124 // we were cancelled
125 return;
126 }
127 if (ec)
128 {
129 lg2::error("{GPIO} event handler error: {ERROR}", "GPIO", gpio,
130 "ERROR", ec.message());
131 return;
132 }
133 gpioEventHandler();
134 });
135}
136
137void GpioPresence::cancelEventHandler()
138{
139 gpioEventDescriptor.cancel();
140}
141
142void GpioPresence::gpioEventHandler()
143{
144 gpiod_line_event gpioLineEvent;
145
146 if (gpiod_line_event_read_fd(gpioEventDescriptor.native_handle(),
147 &gpioLineEvent) < 0)
148 {
149 lg2::error("Failed to read {GPIO} from fd", "GPIO", gpioLineMsg);
150 return;
151 }
152
153 if (gpioLineEvent.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
154 {
155 lg2::info("{GPIO} Asserted", "GPIO", gpioLineMsg);
156 }
157 else
158 {
159 lg2::info("{GPIO} Deasserted", "GPIO", gpioLineMsg);
160 }
161 updateInventory(gpioLineEvent.event_type == GPIOD_LINE_EVENT_RISING_EDGE);
162
163 /* Schedule a wait event */
164 scheduleEventHandler();
165}
166
167int GpioPresence::requestGPIOEvents()
168{
169 std::string flags;
170
171 /* Request an event to monitor for respected gpio line */
172 if (gpiod_line_request(gpioLine, &gpioConfig, 0) < 0)
173 {
174 lg2::error("Failed to request {GPIO}: {ERRNO}", "GPIO", gpioLineMsg,
175 "ERRNO", errno);
176 return -1;
177 }
178
179 int gpioLineFd = gpiod_line_event_get_fd(gpioLine);
180 if (gpioLineFd < 0)
181 {
182 lg2::error("Failed to get fd for {GPIO}", "GPIO", gpioLineMsg);
183 return -1;
184 }
185
186 if (gpioConfig.flags & GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE)
187 {
188 flags += " Bias DISABLE";
189 }
190 else if (gpioConfig.flags & GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP)
191 {
192 flags += " Bias PULL_UP";
193 }
194 else if (gpioConfig.flags & GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN)
195 {
196 flags += " Bias PULL_DOWN";
197 }
198
199 if (gpioConfig.flags & GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW)
200 {
201 flags += " ActiveLow";
202 }
203
204 if (!flags.empty())
205 {
206 flags = "[" + flags + "]";
207 }
208
209 lg2::info("{GPIO} {FLAGS} monitoring started", "GPIO", gpioLineMsg, "FLAGS",
210 flags);
211
212 /* Assign line fd to descriptor for monitoring */
213 gpioEventDescriptor.assign(gpioLineFd);
214
215 updateInventory(gpiod_line_get_value(gpioLine));
216
217 /* Schedule a wait event */
218 scheduleEventHandler();
219
220 return 0;
221}
222} // namespace gpio
223} // namespace phosphor