diff options
-rw-r--r-- | configure.ac | 7 | ||||
-rw-r--r-- | file.hpp | 12 | ||||
-rw-r--r-- | gpio-util/Makefile.am | 7 | ||||
-rw-r--r-- | gpio-util/gpio.cpp | 98 | ||||
-rw-r--r-- | gpio-util/gpio.hpp | 108 |
5 files changed, 231 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index ae95205..1a2bb98 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,13 @@ PKG_CHECK_MODULES([SDBUSPLUS], [sdbusplus],, [AC_MSG_ERROR([Could not find sdbus PKG_CHECK_MODULES([PHOSPHOR_DBUS_INTERFACES], [phosphor-dbus-interfaces],, [AC_MSG_ERROR([Could not find phosphor-dbus-interfaces...openbmc/phosphor-dbus-interfaces package required])]) PKG_CHECK_MODULES([LIBEVDEV], [libevdev],, [AC_MSG_ERROR([Could not find libevdev...libevdev package required])]) +# Download gpio.h from github if necessary. +AC_CHECK_HEADER(linux/gpio.h,[HAVE_LINUX_GPIO_H=""],[HAVE_LINUX_GPIO_H="-I linux/gpio.h"]) +AS_IF([test "$HAVE_LINUX_GPIO_H" != ""], + AC_MSG_WARN([Could not find linux/gpio.h: Attempting to download locally for building from https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/gpio.h]) + AC_SUBST([BT_BMC_DL],[`mkdir -p linux;wget https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/gpio.h -O linux/gpio.h`]) +) + # Check/set gtest specific functions. AX_PTHREAD([GTEST_CPPFLAGS="-DGTEST_HAS_PTHREAD=1"],[GTEST_CPPFLAGS="-DGTEST_HAS_PTHREAD=0"]) AC_SUBST(GTEST_CPPFLAGS) @@ -15,7 +15,7 @@ class FileDescriptor int fd = -1; public: - FileDescriptor() = delete; + FileDescriptor() = default; FileDescriptor(const FileDescriptor&) = delete; FileDescriptor& operator=(const FileDescriptor&) = delete; FileDescriptor(FileDescriptor&&) = delete; @@ -42,6 +42,16 @@ class FileDescriptor { return fd; } + + operator bool() const + { + return fd != -1; + } + + void set(int descriptor) + { + fd = descriptor; + } }; } // namespace gpio diff --git a/gpio-util/Makefile.am b/gpio-util/Makefile.am index ea8c763..9bdc42d 100644 --- a/gpio-util/Makefile.am +++ b/gpio-util/Makefile.am @@ -5,4 +5,11 @@ sbin_PROGRAMS = \ phosphor-gpio-util phosphor_gpio_util_SOURCES = \ + gpio.cpp \ main.cpp + +phosphor_gpio_util_LDADD = \ + $(PHOSPHOR_LOGGING_LIBS) + +phosphor_gpio_util_CXXFLAGS = \ + $(PHOSPHOR_LOGGING_CFLAGS) diff --git a/gpio-util/gpio.cpp b/gpio-util/gpio.cpp new file mode 100644 index 0000000..d5c2ce4 --- /dev/null +++ b/gpio-util/gpio.cpp @@ -0,0 +1,98 @@ +/** + * Copyright © 2017 IBM 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 <fcntl.h> +#include <phosphor-logging/log.hpp> +#include <sys/ioctl.h> +#include "gpio.hpp" + +namespace phosphor +{ +namespace gpio +{ + +using namespace phosphor::logging; + +void GPIO::set(Value value) +{ + assert(direction == Direction::output); + + requestLine(value); + + gpiohandle_data data{}; + data.values[0] = static_cast<gpioValue_t>(value); + + auto rc = ioctl(lineFD(), GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); + if (rc == -1) + { + auto e = errno; + log<level::ERR>("Failed SET_LINE_VALUES ioctl", + entry("ERRNO=%d", e)); + throw std::runtime_error("Failed SET_LINE_VALUES ioctl"); + } +} + + +void GPIO::requestLine(Value defaultValue) +{ + //Only need to do this once + if (lineFD) + { + return; + } + + FileDescriptor fd{open(device.c_str(), 0)}; + if (fd() == -1) + { + auto e = errno; + log<level::ERR>("Failed opening GPIO device", + entry("DEVICE=%s", device), + entry("ERRNO=%d", e)); + throw std::runtime_error("Failed opening GPIO device"); + } + + //Make an ioctl call to request the GPIO line, which will + //return the descriptor to use to access it. + gpiohandle_request request{}; + strncpy(request.consumer_label, + "phosphor-gpio-util", + sizeof(request.consumer_label)); + + request.flags = (direction == Direction::output) ? + GPIOHANDLE_REQUEST_OUTPUT : GPIOHANDLE_REQUEST_INPUT; + + request.lineoffsets[0] = gpio; + request.lines = 1; + + if (direction == Direction::output) + { + request.default_values[0] = static_cast<gpioValue_t>(defaultValue); + } + + auto rc = ioctl(fd(), GPIO_GET_LINEHANDLE_IOCTL, &request); + if (rc == -1) + { + auto e = errno; + log<level::ERR>("Failed GET_LINEHANDLE ioctl", + entry("GPIO=%d", gpio), + entry("ERRNO=%d", e)); + throw std::runtime_error("Failed GET_LINEHANDLE ioctl"); + } + + lineFD.set(request.fd); +} + +} +} diff --git a/gpio-util/gpio.hpp b/gpio-util/gpio.hpp new file mode 100644 index 0000000..ba8cce3 --- /dev/null +++ b/gpio-util/gpio.hpp @@ -0,0 +1,108 @@ +#pragma once + +#include <linux/gpio.h> +#include "file.hpp" + +namespace phosphor +{ +namespace gpio +{ + + typedef std::remove_reference<decltype( + gpiohandle_request::lineoffsets[0])>::type gpioNum_t; + + typedef std::remove_reference<decltype( + gpiohandle_data::values[0])>::type gpioValue_t; + +/** + * Represents a GPIO. + * + * Operations are setting low or high. + * + * Read support may be added in the future. + */ +class GPIO +{ + public: + + /** + * If the GPIO is an input or output + */ + enum class Direction + { + input, + output + }; + + /** + * The possible values - low or high + */ + enum class Value + { + low, + high + }; + + GPIO() = delete; + GPIO(const GPIO&) = delete; + GPIO(GPIO&&) = default; + GPIO& operator=(const GPIO&) = delete; + GPIO& operator=(GPIO&&) = default; + ~GPIO() = default; + + /** + * Constructor + * + * @param[in] device - the GPIO device file + * @param[in] gpio - the GPIO number + * @param[in] direction - the GPIO direction + */ + GPIO(const std::string& device, + gpioNum_t gpio, + Direction direction) : + device(device), + gpio(gpio), + direction(direction) + { + } + + /** + * Sets the GPIO value + * + * Requests the GPIO line if it hasn't been done already. + */ + void set(Value value); + + private: + + /** + * Requests a GPIO line from the GPIO device + * + * @param[in] defaultValue - The default value, required for + * output GPIOs only. + */ + void requestLine(Value defaultValue = Value::high); + + /** + * The GPIO device name, like /dev/gpiochip0 + */ + const std::string device; + + /** + * The GPIO number + */ + const gpioNum_t gpio; + + /** + * The GPIO direction + */ + const Direction direction; + + /** + * File descriptor for the GPIO line + */ + FileDescriptor lineFD; +}; + +} +} |