This adds applets for manipulating gpios under Linux via sysfs. It uses
the /sys/class/gpio API to set direction and value of gpios and to read
back the actual value. The applets work like the corresponding C functions
in the kernel:

gpio_set_value <gpio> <value>
gpio_get_value <gpio>
gpio_direction_output <gpio> <value>
gpio_direction_input <gpio>

<gpio> is the Linux gpio number and <value> is 0 for low and 1 for high.
gpio_get_value will report the value to stdout.

If not already exported the applets export the gpio via
/sys/class/gpio/export. After usage the gpio is unexported again,
but only if it wasn't exported before calling the applet.

Signed-off-by: Sascha Hauer <[email protected]>
---
 include/applets.src.h |   4 +
 miscutils/Config.src  |   8 ++
 miscutils/Kbuild.src  |   1 +
 miscutils/gpio.c      | 354 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 367 insertions(+)
 create mode 100644 miscutils/gpio.c

diff --git a/include/applets.src.h b/include/applets.src.h
index aedcf22..b4abb4f 100644
--- a/include/applets.src.h
+++ b/include/applets.src.h
@@ -167,6 +167,10 @@ IF_GETENFORCE(APPLET(getenforce, BB_DIR_USR_SBIN, 
BB_SUID_DROP))
 IF_GETOPT(APPLET(getopt, BB_DIR_BIN, BB_SUID_DROP))
 IF_GETSEBOOL(APPLET(getsebool, BB_DIR_USR_SBIN, BB_SUID_DROP))
 IF_GETTY(APPLET(getty, BB_DIR_SBIN, BB_SUID_DROP))
+IF_GPIO(APPLET(gpio_set_value, BB_DIR_USR_BIN, BB_SUID_DROP))
+IF_GPIO(APPLET(gpio_get_value, BB_DIR_USR_BIN, BB_SUID_DROP))
+IF_GPIO(APPLET(gpio_direction_output, BB_DIR_USR_BIN, BB_SUID_DROP))
+IF_GPIO(APPLET(gpio_direction_input, BB_DIR_USR_BIN, BB_SUID_DROP))
 IF_HD(APPLET_NOEXEC(hd, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hd))
 IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP))
 IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head))
diff --git a/miscutils/Config.src b/miscutils/Config.src
index 1da9800..6048c59 100644
--- a/miscutils/Config.src
+++ b/miscutils/Config.src
@@ -320,6 +320,14 @@ config FLASH_ERASEALL
          The flash_eraseall binary from mtd-utils as of git head c4c6a59eb.
          This utility is used to erase the whole MTD device.
 
+config GPIO
+       bool "gpio tools"
+       default n
+       help
+         This adds support for manipulating gpios via sysfs. It adds the
+         applets gpio_set_value, gpio_get_value, gpio_direction_output and
+         gpio_direction_input.
+
 config IONICE
        bool "ionice"
        default y
diff --git a/miscutils/Kbuild.src b/miscutils/Kbuild.src
index 9e164f1..e18a816 100644
--- a/miscutils/Kbuild.src
+++ b/miscutils/Kbuild.src
@@ -23,6 +23,7 @@ lib-$(CONFIG_FLASHCP)     += flashcp.o
 lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o
 lib-$(CONFIG_FLASH_LOCK)     += flash_lock_unlock.o
 lib-$(CONFIG_FLASH_UNLOCK)   += flash_lock_unlock.o
+lib-$(CONFIG_GPIO)        += gpio.o
 lib-$(CONFIG_IONICE)      += ionice.o
 lib-$(CONFIG_HDPARM)      += hdparm.o
 lib-$(CONFIG_INOTIFYD)    += inotifyd.o
diff --git a/miscutils/gpio.c b/miscutils/gpio.c
new file mode 100644
index 0000000..b9848e7
--- /dev/null
+++ b/miscutils/gpio.c
@@ -0,0 +1,354 @@
+/*
+ * busybox gpio applets
+ *
+ * Copyright (c) 2014, Sascha Hauer, <[email protected]>, Pengutronix
+ *
+ * based on code:
+ *
+ * Copyright (c) 2011, RidgeRun
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by the RidgeRun.
+ * 4. Neither the name of the RidgeRun nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RIDGERUN ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL RIDGERUN BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//usage:#define gpio_set_value_trivial_usage
+//usage:       "<gpio> <value>"
+//usage:#define gpio_set_value_full_usage "\n\n"
+//usage:       "set gpio <gpio> to value <value>"
+
+//usage:#define gpio_get_value_trivial_usage
+//usage:       "<gpio>"
+//usage:#define gpio_get_value_full_usage "\n\n"
+//usage:       "get value of gpio <gpio>"
+
+//usage:#define gpio_direction_output_trivial_usage
+//usage:       "<gpio> <value>"
+//usage:#define gpio_direction_output_full_usage "\n\n"
+//usage:       "configure gpio <gpio> as output with initial value <value>"
+
+//usage:#define gpio_direction_input_trivial_usage
+//usage:       "<gpio>"
+//usage:#define gpio_direction_input_full_usage "\n\n"
+//usage:       "configure gpio <gpio> as input"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "libbb.h"
+
+#define SYSFS_GPIO_DIR "/sys/class/gpio"
+#define MAX_BUF 64
+
+static int gpio_is_exported(unsigned int gpio)
+{
+       char path[MAX_BUF];
+       int ret;
+       struct stat s;
+
+       sprintf(path, "%s/gpio%d", SYSFS_GPIO_DIR, gpio);
+
+       ret = stat(path, &s);
+       if (ret)
+               return 0;
+       return 1;
+}
+
+static int gpio_export(unsigned int gpio)
+{
+       int fd, len, ret;
+       char buf[MAX_BUF];
+       const char *export_path = SYSFS_GPIO_DIR "/unexport";
+
+       fd = open(export_path, O_WRONLY);
+       if (fd < 0) {
+               fprintf(stderr, "open %s: %s\n", export_path, strerror(errno));
+               return -errno;
+       }
+
+       len = snprintf(buf, sizeof(buf), "%d", gpio);
+       ret = write(fd, buf, len);
+       if (ret < 0)
+               fprintf(stderr, "export gpio %d: %s\n", gpio, strerror(errno));
+       else
+               ret = 0;
+
+       close(fd);
+
+       if (!gpio_is_exported(gpio))
+               return -ENOSYS;
+
+       return ret;
+}
+
+static int gpio_unexport(unsigned int gpio)
+{
+       int fd, len, ret;
+       char buf[MAX_BUF];
+       const char *unexport_path = SYSFS_GPIO_DIR "/unexport";
+
+       fd = open(unexport_path, O_WRONLY);
+       if (fd < 0) {
+               fprintf(stderr, "open %s: %s\n", unexport_path, 
strerror(errno));
+               return -errno;
+       }
+
+       len = snprintf(buf, sizeof(buf), "%d", gpio);
+       ret = write(fd, buf, len);
+       if (ret < 0)
+               fprintf(stderr, "unexport gpio %d: %s\n", gpio, 
strerror(errno));
+       else
+               ret = 0;
+
+       close(fd);
+
+       return ret;
+}
+
+enum gpio_direction {
+       GPIO_IN,
+       GPIO_OUT_LOW,
+       GPIO_OUT_HIGH,
+};
+
+static int gpio_set_direction(unsigned int gpio, enum gpio_direction dir)
+{
+       int fd, ret;
+       char buf[MAX_BUF];
+       const char *str;
+
+       snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR  "/gpio%d/direction", gpio);
+
+       fd = open(buf, O_WRONLY);
+       if (fd < 0) {
+               fprintf(stderr, "open %s: %s\n", buf, strerror(-errno));
+               return -errno;
+       }
+
+       switch (dir) {
+       case GPIO_IN:
+               str = "in";
+               break;
+       case GPIO_OUT_LOW:
+               str = "low";
+               break;
+       case GPIO_OUT_HIGH:
+               str = "high";
+               break;
+       default:
+               close(fd);
+               return -EINVAL;
+       };
+
+       ret = write(fd, str, strlen(str) + 1);
+       if (ret < 0)
+               fprintf(stderr, "write direction gpio %d: %s\n", gpio, 
strerror(-errno));
+       else
+               ret = 0;
+
+       close(fd);
+
+       return ret;
+}
+
+static int gpio_set_value(unsigned int gpio, unsigned int value)
+{
+       int fd, ret;
+       char buf[MAX_BUF];
+
+       snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+
+       fd = open(buf, O_WRONLY);
+       if (fd < 0) {
+               fprintf(stderr, "open %s: %s\n", buf, strerror(-errno));
+               return -errno;
+       }
+
+       if (value)
+               ret = write(fd, "1", 2);
+       else
+               ret = write(fd, "0", 2);
+
+       if (ret < 0)
+               fprintf(stderr, "write value gpio %d: %s\n", gpio, 
strerror(-errno));
+       else
+               ret = 0;
+
+       close(fd);
+
+       return ret;
+}
+
+static int gpio_direction_output(unsigned int gpio, int value)
+{
+       return gpio_set_direction(gpio, value ? GPIO_OUT_HIGH : GPIO_OUT_LOW);
+}
+
+static int gpio_direction_input(unsigned int gpio)
+{
+       return gpio_set_direction(gpio, GPIO_IN);
+}
+
+static int gpio_get_value(unsigned int gpio, unsigned int *value)
+{
+       int fd, ret;
+       char buf[MAX_BUF];
+       char ch;
+
+       snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
+
+       fd = open(buf, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "open %s: %s\n", buf, strerror(-errno));
+               return fd;
+       }
+
+       ret = read(fd, &ch, 1);
+       if (ret < 0)
+               fprintf(stderr, "read value gpio %d: %s\n", gpio, 
strerror(-errno));
+       else
+               ret = 0;
+
+       if (ch != '0') {
+               *value = 1;
+       } else {
+               *value = 0;
+       }
+
+       close(fd);
+
+       return ret;
+}
+
+static int gpio_open_export(const char *gpiostr, int *gpio_was_exported)
+{
+       int gpio, ret;
+
+       gpio = atoi(gpiostr);
+
+       *gpio_was_exported = gpio_is_exported(gpio);
+
+       if (!*gpio_was_exported) {
+               ret = gpio_export(gpio);
+               if (ret)
+                       return ret;
+       }
+
+       return gpio;
+}
+
+int gpio_direction_output_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+
+int gpio_direction_output_main(int argc, char **argv)
+{
+       int gpio, ret, gpio_was_exported;
+
+       if (argc != 3)
+               bb_show_usage();
+
+       gpio = gpio_open_export(argv[1], &gpio_was_exported);
+       if (gpio < 0)
+               return gpio;
+
+       ret = gpio_direction_output(gpio, atoi(argv[2]));
+
+       if (!gpio_was_exported)
+               gpio_unexport(gpio);
+
+       return ret;
+}
+
+int gpio_direction_input_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+
+int gpio_direction_input_main(int argc, char **argv)
+{
+       int gpio, ret, gpio_was_exported;
+
+       if (argc != 2)
+               bb_show_usage();
+
+       gpio = gpio_open_export(argv[1], &gpio_was_exported);
+       if (gpio < 0)
+               return gpio;
+
+       ret = gpio_direction_input(gpio);
+
+       if (!gpio_was_exported)
+               gpio_unexport(gpio);
+
+       return ret;
+}
+
+int gpio_set_value_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+
+int gpio_set_value_main(int argc, char **argv)
+{
+       int gpio, ret, gpio_was_exported;
+
+       if (argc != 3)
+               bb_show_usage();
+
+       gpio = gpio_open_export(argv[1], &gpio_was_exported);
+       if (gpio < 0)
+               return gpio;
+
+       ret = gpio_set_value(gpio, atoi(argv[2]));
+
+       if (!gpio_was_exported)
+               gpio_unexport(gpio);
+
+       return ret;
+}
+
+int gpio_get_value_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+
+int gpio_get_value_main(int argc, char **argv)
+{
+       int gpio, ret, gpio_was_exported;
+       unsigned int val = 0;
+
+       if (argc != 2)
+               bb_show_usage();
+
+       gpio = gpio_open_export(argv[1], &gpio_was_exported);
+       if (gpio < 0)
+               return gpio;
+
+       ret = gpio_get_value(gpio, &val);
+
+       printf("%d\n", val);
+
+       if (!gpio_was_exported)
+               gpio_unexport(gpio);
+
+       return ret;
+}
-- 
1.9.1

_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to