1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3
4 #include "gpioMon.hpp"
5
6 #include <phosphor-logging/lg2.hpp>
7 #include <sdbusplus/bus.hpp>
8
9 namespace phosphor
10 {
11 namespace gpio
12 {
13
14 /* systemd service to kick start a target. */
15 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
16 constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1";
17 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
18
19 constexpr auto falling = "FALLING";
20 constexpr auto rising = "RISING";
21 constexpr auto init_high = "INIT_HIGH";
22 constexpr auto init_low = "INIT_LOW";
23
scheduleEventHandler()24 void GpioMonitor::scheduleEventHandler()
25 {
26 gpioEventDescriptor.async_wait(
27 boost::asio::posix::stream_descriptor::wait_read,
28 [this](const boost::system::error_code& ec) {
29 if (ec)
30 {
31 lg2::error("{GPIO} event handler error: {ERROR}", "GPIO",
32 gpioLineMsg, "ERROR", ec.message());
33 return;
34 }
35 gpioEventHandler();
36 });
37 }
38
gpioEventHandler()39 void GpioMonitor::gpioEventHandler()
40 {
41 gpiod_line_event gpioLineEvent;
42
43 if (gpiod_line_event_read_fd(gpioEventDescriptor.native_handle(),
44 &gpioLineEvent) < 0)
45 {
46 lg2::error("Failed to read {GPIO} from fd", "GPIO", gpioLineMsg);
47 return;
48 }
49
50 if (gpioLineEvent.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
51 {
52 lg2::info("{GPIO} Asserted", "GPIO", gpioLineMsg);
53 }
54 else
55 {
56 lg2::info("{GPIO} Deasserted", "GPIO", gpioLineMsg);
57 }
58
59 /* Execute the target if it is defined. */
60 if (!target.empty())
61 {
62 auto bus = sdbusplus::bus::new_default();
63 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
64 SYSTEMD_INTERFACE, "StartUnit");
65 method.append(target);
66 method.append("replace");
67
68 bus.call_noreply(method);
69 }
70
71 std::vector<std::string> targetsToStart;
72 if (gpioLineEvent.event_type == GPIOD_LINE_EVENT_RISING_EDGE)
73 {
74 auto risingFind = targets.find(rising);
75 if (risingFind != targets.end())
76 {
77 targetsToStart = risingFind->second;
78 }
79 }
80 else
81 {
82 auto fallingFind = targets.find(falling);
83 if (fallingFind != targets.end())
84 {
85 targetsToStart = fallingFind->second;
86 }
87 }
88
89 /* Execute the multi targets if it is defined. */
90 if (!targetsToStart.empty())
91 {
92 auto bus = sdbusplus::bus::new_default();
93 for (auto& tar : targetsToStart)
94 {
95 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
96 SYSTEMD_INTERFACE, "StartUnit");
97 method.append(tar, "replace");
98 bus.call_noreply(method);
99 }
100 }
101
102 /* if not required to continue monitoring then return */
103 if (!continueAfterEvent)
104 {
105 return;
106 }
107
108 /* Schedule a wait event */
109 scheduleEventHandler();
110 }
111
gpioHandleInitialState(bool value)112 void GpioMonitor::gpioHandleInitialState(bool value)
113 {
114 if (auto itr = targets.find(value ? init_high : init_low);
115 itr != targets.end())
116 {
117 auto bus = sdbusplus::bus::new_default();
118 for (const auto& tar : itr->second)
119 {
120 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT,
121 SYSTEMD_INTERFACE, "StartUnit");
122 method.append(tar, "replace");
123 bus.call_noreply(method);
124 }
125 }
126 }
127
requestGPIOEvents()128 int GpioMonitor::requestGPIOEvents()
129 {
130 /* Request an event to monitor for respected gpio line */
131 if (gpiod_line_request(gpioLine, &gpioConfig, 0) < 0)
132 {
133 lg2::error("Failed to request {GPIO}", "GPIO", gpioLineMsg);
134 return -1;
135 }
136
137 int gpioLineFd = gpiod_line_event_get_fd(gpioLine);
138 if (gpioLineFd < 0)
139 {
140 lg2::error("Failed to get fd for {GPIO}", "GPIO", gpioLineMsg);
141 return -1;
142 }
143
144 int value = gpiod_line_get_value(gpioLine);
145 if (value < 0)
146 {
147 lg2::error("Failed to get value for {GPIO} Error: {ERROR}", "GPIO",
148 gpioLineMsg, "ERROR", strerror(errno));
149 }
150 else
151 {
152 gpioHandleInitialState(value != 0);
153 }
154
155 lg2::info("{GPIO} monitoring started", "GPIO", gpioLineMsg);
156
157 /* Assign line fd to descriptor for monitoring */
158 gpioEventDescriptor.assign(gpioLineFd);
159
160 /* Schedule a wait event */
161 scheduleEventHandler();
162
163 return 0;
164 }
165 } // namespace gpio
166 } // namespace phosphor
167