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
