summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac7
-rw-r--r--file.hpp12
-rw-r--r--gpio-util/Makefile.am7
-rw-r--r--gpio-util/gpio.cpp98
-rw-r--r--gpio-util/gpio.hpp108
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)
diff --git a/file.hpp b/file.hpp
index 9ba4cbb..ee8fd4b 100644
--- a/file.hpp
+++ b/file.hpp
@@ -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;
+};
+
+}
+}
OpenPOWER on IntegriCloud