On Tuesday 29 April 2014 16:31:33 Sascha Hauer wrote: > 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))
Hi, why must it be 4 different applets couldn't the same applet get/set the value as they share a lot of code? Eventually you could use the app name to check if the action to perform is to get or to set: (applet_name[6] == 's') Also you maybe could use some libbb functions to reduce the code size. I've listed the most obvious of them in the code but there could be more. I suspect that the RidgeRun license could a problem for the inclusion of this code in busybox and I wonder if it wouldn't be a cleaner solution to rewrite the app as it is rather simple stuff. Of course the busybox maintainer will decide on this issue. Hope it helps. Ciao, Tito > +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); > + xstat ? > + 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"; > + xopen ? open_or_warn > + 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) bb_perror_msg > + 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"; xopen ? open_or_warn > + 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) bb_perror_msg > + 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); xopen ? open_or_warn > + 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); bb_perror_msg > + 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); xopen ? open_or_warn > + 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) bb_perror_msg > + 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); xopen ? open_or_warn > + 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) bb_perror_msg > + 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; > +} > _______________________________________________ busybox mailing list [email protected] http://lists.busybox.net/mailman/listinfo/busybox
