| /* |
| // Copyright (c) 2018 Intel Corporation |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| */ |
| |
| #include "gpio.hpp" |
| |
| #include <fcntl.h> |
| #include <unistd.h> |
| |
| #include <experimental/filesystem> |
| #include <fstream> |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <xyz/openbmc_project/Common/error.hpp> |
| |
| const static constexpr char* SYSMGR_SERVICE = "org.openbmc.managers.System"; |
| const static constexpr char* SYSMGR_OBJ_PATH = "/org/openbmc/managers/System"; |
| const static constexpr char* SYSMGR_INTERFACE = "org.openbmc.managers.System"; |
| |
| int closeGpio(int fd) |
| { |
| if (fd > 0) |
| { |
| ::close(fd); |
| } |
| return 0; |
| } |
| |
| int configGpio(const char* gpioName, int* fd, sdbusplus::bus::bus& bus) |
| { |
| sdbusplus::message::message method = bus.new_method_call( |
| SYSMGR_SERVICE, SYSMGR_OBJ_PATH, SYSMGR_INTERFACE, "gpioInit"); |
| |
| method.append(gpioName); |
| |
| sdbusplus::message::message result = bus.call(method); |
| |
| if (result.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "configGPIO: bus call error!"); |
| return -1; |
| } |
| |
| int32_t gpioNum = -1; |
| std::string gpioDev; |
| std::string gpioDirection; |
| |
| result.read(gpioDev, gpioNum, gpioDirection); |
| |
| if (gpioDev.empty()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "configGPIO: gpioDev error!"); |
| return -1; |
| } |
| |
| if (gpioDirection.empty()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "configGPIO: gpioDirection error!"); |
| return -1; |
| } |
| |
| std::fstream stream; |
| |
| stream.exceptions(std::ifstream::failbit | std::ifstream::badbit); |
| |
| std::string devPath = |
| gpioDev + "/gpio" + std::to_string(gpioNum) + "/value"; |
| |
| std::experimental::filesystem::path fullPath(devPath); |
| |
| if (std::experimental::filesystem::exists(fullPath)) |
| { |
| phosphor::logging::log<phosphor::logging::level::INFO>( |
| "GPIO exported", |
| phosphor::logging::entry("PATH=%s", devPath.c_str())); |
| } |
| else |
| { |
| devPath = gpioDev + "/export"; |
| |
| stream.open(devPath, std::fstream::out); |
| |
| if (!stream.good()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error in opening for write!", |
| phosphor::logging::entry("PATH=%s", devPath.c_str()), |
| phosphor::logging::entry("NUM=%d", gpioNum)); |
| return -1; |
| } |
| |
| stream << gpioNum; |
| stream.close(); |
| } |
| |
| if (gpioDirection == "out") |
| { |
| devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value"; |
| |
| uint32_t currentValue = 0; |
| |
| stream.open(devPath, std::fstream::in); |
| |
| if (!stream.good()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error in opening for read!", |
| phosphor::logging::entry("PATH=%s", devPath.c_str())); |
| return -1; |
| } |
| |
| stream >> currentValue; |
| stream.close(); |
| |
| const char* direction = currentValue ? "high" : "low"; |
| |
| devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction"; |
| |
| stream.open(devPath, std::fstream::out); |
| |
| if (!stream.good()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error in opening for write!"); |
| return -1; |
| } |
| |
| stream << direction; |
| stream.close(); |
| } |
| else if (gpioDirection == "in") |
| { |
| devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/direction"; |
| |
| stream.open(devPath, std::fstream::out); |
| |
| if (!stream.good()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error in opening for write!"); |
| return -1; |
| } |
| |
| stream << gpioDirection; |
| stream.close(); |
| } |
| else if (gpioDirection == "both") |
| { |
| |
| // For gpio configured as ‘both’, it is an interrupt pin and trigged on |
| // both rising and falling signals |
| devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/edge"; |
| |
| stream.open(devPath, std::fstream::out); |
| |
| if (!stream.good()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error in opening for write!"); |
| return -1; |
| } |
| |
| stream << gpioDirection; |
| stream.close(); |
| } |
| |
| devPath = gpioDev + "/gpio" + std::to_string(gpioNum) + "/value"; |
| |
| *fd = ::open(devPath.c_str(), O_RDWR | O_NONBLOCK); |
| |
| if (*fd < 0) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>("open error!"); |
| return -1; |
| } |
| |
| return 0; |
| } |