1 /** 2 * Copyright © 2019 Facebook 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "gpioMon.hpp" 18 19 #include <phosphor-logging/log.hpp> 20 #include <sdbusplus/bus.hpp> 21 22 namespace phosphor 23 { 24 namespace gpio 25 { 26 27 /* systemd service to kick start a target. */ 28 constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1"; 29 constexpr auto SYSTEMD_ROOT = "/org/freedesktop/systemd1"; 30 constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager"; 31 32 using namespace phosphor::logging; 33 34 void GpioMonitor::scheduleEventHandler() 35 { 36 37 gpioEventDescriptor.async_wait( 38 boost::asio::posix::stream_descriptor::wait_read, 39 [this](const boost::system::error_code& ec) { 40 if (ec) 41 { 42 std::string msg = gpioLineMsg + "event handler error" + 43 std::string(ec.message()); 44 log<level::ERR>(msg.c_str()); 45 return; 46 } 47 gpioEventHandler(); 48 }); 49 } 50 51 void GpioMonitor::gpioEventHandler() 52 { 53 gpiod_line_event gpioLineEvent; 54 55 if (gpiod_line_event_read_fd(gpioEventDescriptor.native_handle(), 56 &gpioLineEvent) < 0) 57 { 58 log<level::ERR>("Failed to read gpioLineEvent from fd", 59 entry("GPIO_LINE=%s", gpioLineMsg.c_str())); 60 return; 61 } 62 63 std::string logMessage = 64 gpioLineMsg + (gpioLineEvent.event_type == GPIOD_LINE_EVENT_RISING_EDGE 65 ? " Asserted" 66 : " Deasserted"); 67 68 log<level::INFO>(logMessage.c_str()); 69 70 /* Execute the target if it is defined. */ 71 if (!target.empty()) 72 { 73 auto bus = sdbusplus::bus::new_default(); 74 auto method = bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_ROOT, 75 SYSTEMD_INTERFACE, "StartUnit"); 76 method.append(target); 77 method.append("replace"); 78 79 bus.call_noreply(method); 80 } 81 82 /* if not required to continue monitoring then return */ 83 if (!continueAfterEvent) 84 { 85 return; 86 } 87 88 /* Schedule a wait event */ 89 scheduleEventHandler(); 90 } 91 92 int GpioMonitor::requestGPIOEvents() 93 { 94 95 /* Request an event to monitor for respected gpio line */ 96 if (gpiod_line_request(gpioLine, &gpioConfig, 0) < 0) 97 { 98 log<level::ERR>("Failed to request gpioLineEvent", 99 entry("GPIO_LINE=%s", gpioLineMsg.c_str())); 100 return -1; 101 } 102 103 int gpioLineFd = gpiod_line_event_get_fd(gpioLine); 104 if (gpioLineFd < 0) 105 { 106 log<level::ERR>("Failed to get fd for gpioLineEvent", 107 entry("GPIO_LINE=%s", gpioLineMsg.c_str())); 108 return -1; 109 } 110 111 std::string logMsg = gpioLineMsg + " monitoring started"; 112 log<level::INFO>(logMsg.c_str()); 113 114 /* Assign line fd to descriptor for monitoring */ 115 gpioEventDescriptor.assign(gpioLineFd); 116 117 /* Schedule a wait event */ 118 scheduleEventHandler(); 119 120 return 0; 121 } 122 } // namespace gpio 123 } // namespace phosphor 124