Add GPIO class

This class will be used for accessing GPIOs off of the
UCD90160 to check for PGOOD faults, and also later for
isolating GPU overtemps and PGOOD faults down to the specific
GPU that failed.

The FileDescriptor class is used by the GPIO class to manage
the lifetime of the GPIO file handles.

The class only supports reading a GPIO value.  At this point
there is no requirement for doing writes.

This class was copied from phosphor-gpio-monitor/gpio-util.

Change-Id: Iee276aed67e1cba549c3070c08238ab5f621c320
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/configure.ac b/configure.ac
index ed31491..28719bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,6 +17,13 @@
 AX_CXX_COMPILE_STDCXX_14([noext])
 AX_APPEND_COMPILE_FLAGS([-Wall -Werror], [CXXFLAGS])
 
+# 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`])
+)
+
 PKG_CHECK_MODULES([SDBUSPLUS], [sdbusplus],,
     AC_MSG_ERROR(["Requires sdbusplus package."]))
 PKG_CHECK_MODULES([PHOSPHOR_LOGGING], [phosphor-logging],,\
diff --git a/file.hpp b/file.hpp
new file mode 100644
index 0000000..5be4c4b
--- /dev/null
+++ b/file.hpp
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <unistd.h>
+namespace witherspoon
+{
+namespace power
+{
+namespace util
+{
+
+/**
+ * @class FileDescriptor
+ *
+ * Closes the file descriptor on destruction
+ */
+class FileDescriptor
+{
+    public:
+
+        FileDescriptor() = default;
+        FileDescriptor(const FileDescriptor&) = delete;
+        FileDescriptor& operator=(const FileDescriptor&) = delete;
+        FileDescriptor(FileDescriptor&&) = delete;
+        FileDescriptor& operator=(FileDescriptor&&) = delete;
+
+        /**
+         * Constructor
+         *
+         * @param[in] fd - File descriptor
+         */
+        FileDescriptor(int fd) : fd(fd)
+        {
+        }
+
+        ~FileDescriptor()
+        {
+            if (fd >= 0)
+            {
+                close(fd);
+            }
+        }
+
+        int operator()()
+        {
+            return fd;
+        }
+
+        operator bool() const
+        {
+            return fd != -1;
+        }
+
+        void set(int descriptor)
+        {
+            if (fd >= 0)
+            {
+                close(fd);
+            }
+
+            fd = descriptor;
+        }
+
+    private:
+
+        /**
+         * File descriptor
+         */
+        int fd = -1;
+};
+
+}
+}
+}
diff --git a/power-sequencer/Makefile.am b/power-sequencer/Makefile.am
index 9309999..485ae3e 100644
--- a/power-sequencer/Makefile.am
+++ b/power-sequencer/Makefile.am
@@ -6,6 +6,7 @@
 
 witherspoon_pseq_monitor_SOURCES = \
 	argument.cpp \
+	gpio.cpp \
 	main.cpp \
 	pgood_monitor.cpp \
 	ucd90160.cpp \
diff --git a/power-sequencer/gpio.cpp b/power-sequencer/gpio.cpp
new file mode 100644
index 0000000..32f4358
--- /dev/null
+++ b/power-sequencer/gpio.cpp
@@ -0,0 +1,103 @@
+/**
+ * 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/elog.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sys/ioctl.h>
+#include <xyz/openbmc_project/Common/error.hpp>
+#include "gpio.hpp"
+
+namespace witherspoon
+{
+namespace gpio
+{
+
+using namespace phosphor::logging;
+
+using InternalFailure = sdbusplus::xyz::openbmc_project::Common::
+                        Error::InternalFailure;
+
+Value GPIO::read()
+{
+    assert(direction == Direction::input);
+
+    requestLine();
+
+    gpiohandle_data data{};
+
+    auto rc = ioctl(lineFD(),
+                    GPIOHANDLE_GET_LINE_VALUES_IOCTL,
+                    &data);
+
+    if (rc < 0)
+    {
+        auto e = errno;
+        log<level::ERR>("Failed GET_LINE_VALUES ioctl",
+                        entry("ERRNO=%d", e));
+        elog<InternalFailure>();
+    }
+
+    return (data.values[0] == 0) ? Value::low : Value::high;
+}
+
+
+void GPIO::requestLine()
+{
+    //Only need to do this once
+    if (lineFD)
+    {
+        return;
+    }
+
+    power::util::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));
+        elog<InternalFailure>();
+    }
+
+    //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,
+            "witherspoon-pfault-analysis",
+            sizeof(request.consumer_label));
+
+    request.flags = (direction == Direction::input) ?
+                    GPIOHANDLE_REQUEST_INPUT : GPIOHANDLE_REQUEST_OUTPUT;
+
+    request.lineoffsets[0] = gpio;
+    request.lines = 1;
+
+    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));
+        elog<InternalFailure>();
+    }
+
+    lineFD.set(request.fd);
+}
+
+}
+}
diff --git a/power-sequencer/gpio.hpp b/power-sequencer/gpio.hpp
new file mode 100644
index 0000000..2d3c6dd
--- /dev/null
+++ b/power-sequencer/gpio.hpp
@@ -0,0 +1,107 @@
+#pragma once
+
+#include <linux/gpio.h>
+#include "file.hpp"
+
+namespace witherspoon
+{
+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;
+
+/**
+ * If the GPIO is an input or output
+ */
+enum class Direction
+{
+    input,
+    output
+};
+
+/**
+ * The possible values - low or high
+ */
+enum class Value
+{
+    low,
+    high
+};
+
+/**
+ * Represents a GPIO.
+ *
+ * Currently supports reading a GPIO.
+ *
+ * Write support may be added in the future.
+ */
+class GPIO
+{
+    public:
+
+        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)
+        {
+        }
+
+        /**
+         * Reads the GPIO value
+         *
+         * Requests the GPIO line if it hasn't been done already.
+         *
+         * @return Value - the GPIO value
+         */
+        Value read();
+
+    private:
+
+        /**
+         * Requests a GPIO line from the GPIO device
+         */
+        void requestLine();
+
+        /**
+         * 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
+         */
+        power::util::FileDescriptor lineFD;
+};
+
+}
+}