xref: /openbmc/phosphor-gpio-monitor/gpioMon.cpp (revision 75ff16717de9a7b3beeda9f3cace9456cad98156)
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