summaryrefslogtreecommitdiffstats
path: root/usr.sbin/gpioctl
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2010-09-28 03:28:20 +0000
committergonzo <gonzo@FreeBSD.org>2010-09-28 03:28:20 +0000
commit6c4ac4482207f8afffda41cb953fe268933b701f (patch)
treef3c60535625b1bcce696f5d22357c3c2709a9ded /usr.sbin/gpioctl
parent0502deed69f7916c288032a87977fa5d7d5ecc35 (diff)
downloadFreeBSD-src-6c4ac4482207f8afffda41cb953fe268933b701f.zip
FreeBSD-src-6c4ac4482207f8afffda41cb953fe268933b701f.tar.gz
Add gpioctl(8). Utility for configuring/accessing GPIO pins
Diffstat (limited to 'usr.sbin/gpioctl')
-rw-r--r--usr.sbin/gpioctl/Makefile6
-rw-r--r--usr.sbin/gpioctl/gpioctl.8124
-rw-r--r--usr.sbin/gpioctl/gpioctl.c323
3 files changed, 453 insertions, 0 deletions
diff --git a/usr.sbin/gpioctl/Makefile b/usr.sbin/gpioctl/Makefile
new file mode 100644
index 0000000..997f0c7
--- /dev/null
+++ b/usr.sbin/gpioctl/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+PROG= gpioctl
+MAN= gpioctl.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/gpioctl/gpioctl.8 b/usr.sbin/gpioctl/gpioctl.8
new file mode 100644
index 0000000..6747f8e
--- /dev/null
+++ b/usr.sbin/gpioctl/gpioctl.8
@@ -0,0 +1,124 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. 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 University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 27, 2010
+.Dt GPIOCTL 1
+.Os
+.Sh NAME
+.Nm gpioctl
+.Nd GPIO control utility
+.Sh SYNOPSIS
+.Nm
+.Cm -l
+.Fl f Ar ctldev
+.Op Fl v
+.Nm
+.Cm -t
+.Fl f Ar ctldev
+.Ar pin
+.Nm
+.Cm -c
+.Fl f Ar ctldev
+.Ar pin
+.Ar flag
+.Op flag ...
+.Nm
+.Cm -f Ar ctldev
+.Ar pin
+.Ar [0|1]
+.Sh DESCRIPTION
+The
+.Nm
+utility could be used to manage GPIO pins from userland and list available pins.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl f Ar ctldev"
+.It Fl c Ar pin Ar flag Op flag ...
+Configure pin by setting provided flags. The following flags are currently defined:
+.Bl -tag -offset indent -width ".Cm PULSE"
+.It Cm IN
+Input pin
+.It Cm OUT
+Output pin
+.It Cm OD
+Open drain pin
+.It Cm PP
+Push pull pin
+.It Cm TS
+Tristate pin
+.It Cm PU
+Pull-up pin
+.It Cm PD
+Pull-down pin
+.It Cm II
+Inverted input pin
+.It Cm IO
+Inverted output pin
+.El
+.It Fl f Ar ctldev
+GPIO controller device to use
+.It Fl l
+list available pins
+.It Fl t Ar pin
+toggle value of provided pin number
+.It Fl v
+be verbose: for each listed pin print current configuration
+.El
+.Sh EXAMPLES
+.Pp
+.Bl -bullet
+.It
+List pins available on GPIO controller defined by device /dev/gpioctl0
+.Pp
+gpioctl -f /dev/gpioctl0 -l
+.It
+Set the value of pin 12 to 1
+.Pp
+gpioctl -f /dev/gpioctl0 12 1
+.It
+Configure pin 12 to be input pin
+.Pp
+gpioctl -f /dev/gpioctl0 -c 12 IN
+.El
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Fx 9.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility and this manual page were written by
+.An Oleksandr Tymoshenko
+.Aq gonzo@freebsd.org
diff --git a/usr.sbin/gpioctl/gpioctl.c b/usr.sbin/gpioctl/gpioctl.c
new file mode 100644
index 0000000..8956ef4
--- /dev/null
+++ b/usr.sbin/gpioctl/gpioctl.c
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+ * 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 unmodified, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/gpio.h>
+
+struct flag_desc {
+ const char *name;
+ uint32_t flag;
+};
+
+struct flag_desc gpio_flags[] = {
+ { "IN", GPIO_PIN_INPUT },
+ { "OUT", GPIO_PIN_OUTPUT },
+ { "OD", GPIO_PIN_OPENDRAIN },
+ { "PP", GPIO_PIN_PUSHPULL },
+ { "TS", GPIO_PIN_TRISTATE },
+ { "PU", GPIO_PIN_PULLUP },
+ { "PD", GPIO_PIN_PULLDOWN },
+ { "II", GPIO_PIN_INVIN },
+ { "IO", GPIO_PIN_INVOUT },
+ { "PULSE", GPIO_PIN_PULSATE },
+ { NULL, 0 },
+};
+
+int str2cap(const char *str);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\tgpioctl -f ctldev -l [-v]\n");
+ fprintf(stderr, "\tgpioctl -f ctldev -t pin\n");
+ fprintf(stderr, "\tgpioctl -f ctldev -c pin flag ...\n");
+ fprintf(stderr, "\tgpioctl -f ctldev pin [0|1]\n");
+ exit(1);
+}
+
+static const char *
+cap2str(uint32_t cap)
+{
+ struct flag_desc * pdesc = gpio_flags;
+ while (pdesc->name) {
+ if (pdesc->flag == cap)
+ return pdesc->name;
+ pdesc++;
+ }
+
+ return "UNKNOWN";
+}
+
+int
+str2cap(const char *str)
+{
+ struct flag_desc * pdesc = gpio_flags;
+ while (pdesc->name) {
+ if (strcasecmp(str, pdesc->name) == 0)
+ return pdesc->flag;
+ pdesc++;
+ }
+
+ return (-1);
+}
+
+/*
+ * Our handmade function for converting string to number
+ */
+static int
+str2int(const char *s, int *ok)
+{
+ char *endptr;
+ int res = strtod(s, &endptr);
+ if (endptr != s + strlen(s) )
+ *ok = 0;
+ else
+ *ok = 1;
+
+ return res;
+}
+
+static void
+print_caps(int caps)
+{
+ int i, need_coma;
+
+ need_coma = 0;
+ printf("<");
+ for (i = 0; i < 32; i++) {
+ if (caps & (1 << i)) {
+ if (need_coma)
+ printf(",");
+ printf("%s", cap2str(1 << i));
+ need_coma = 1;
+ }
+ }
+ printf(">");
+}
+
+static void
+dump_pins(int fd, int verbose)
+{
+ int i, maxpin;
+ struct gpio_pin pin;
+ struct gpio_req req;
+
+ if (ioctl(fd, GPIOMAXPIN, &maxpin) < 0) {
+ perror("ioctl(GPIOMAXPIN)");
+ exit(1);
+ }
+
+ for (i = 0; i <= maxpin; i++) {
+ pin.gp_pin = i;
+ if (ioctl(fd, GPIOGETCONFIG, &pin) < 0)
+ /* For some reason this pin is inaccessible */
+ continue;
+
+ req.gp_pin = i;
+ if (ioctl(fd, GPIOGET, &req) < 0) {
+ /* Now, that's wrong */
+ perror("ioctl(GPIOGET)");
+ exit(1);
+ }
+
+ printf("pin %02d:\t%d\t%s", pin.gp_pin, req.gp_value,
+ pin.gp_name);
+
+ print_caps(pin.gp_flags);
+
+ if (verbose) {
+ printf(", caps:");
+ print_caps(pin.gp_caps);
+ }
+ printf("\n");
+ }
+}
+
+static void
+fail(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ struct gpio_pin pin;
+ struct gpio_req req;
+ char *ctlfile = NULL;
+ int pinn, pinv, fd, ch;
+ int flags, flag, ok;
+ int config, toggle, verbose, list;
+
+ config = toggle = verbose = list = pinn = 0;
+
+ while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) {
+ switch (ch) {
+ case 'c':
+ config = 1;
+ pinn = str2int(optarg, &ok);
+ if (!ok)
+ fail("Invalid pin number: %s\n", optarg);
+ break;
+ case 'f':
+ ctlfile = optarg;
+ break;
+ case 'l':
+ list = 1;
+ break;
+ case 't':
+ toggle = 1;
+ pinn = str2int(optarg, &ok);
+ if (!ok)
+ fail("Invalid pin number: %s\n", optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+ argv += optind;
+ argc -= optind;
+ for (i = 0; i < argc; i++)
+ printf("%d/%s\n", i, argv[i]);
+
+ if (ctlfile == NULL)
+ fail("No gpioctl device provided\n");
+
+ fd = open(ctlfile, O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ if (list) {
+ dump_pins(fd, verbose);
+ close(fd);
+ exit(0);
+ }
+
+ if (toggle) {
+ /*
+ * -t pin assumes no additional arguments
+ */
+ if(argc > 0) {
+ usage();
+ exit(1);
+ }
+
+ req.gp_pin = pinn;
+ if (ioctl(fd, GPIOTOGGLE, &req) < 0) {
+ perror("ioctl(GPIOTOGGLE)");
+ exit(1);
+ }
+
+ close(fd);
+ exit (0);
+ }
+
+ if (config) {
+ flags = 0;
+ for (i = 0; i < argc; i++) {
+ flag = str2cap(argv[i]);
+ if (flag < 0)
+ fail("Invalid flag: %s\n", argv[i]);
+ flags |= flag;
+ }
+
+ pin.gp_pin = pinn;
+ pin.gp_flags = flags;
+ if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) {
+ perror("ioctl(GPIOSETCONFIG)");
+ exit(1);
+ }
+
+ exit(0);
+ }
+
+ /*
+ * Last two cases - set value or print value
+ */
+ if ((argc == 0) || (argc > 2)) {
+ usage();
+ exit(1);
+ }
+
+ pinn = str2int(argv[0], &ok);
+ if (!ok)
+ fail("Invalid pin number: %s\n", argv[0]);
+
+ /*
+ * Read pin value
+ */
+ if (argc == 1) {
+ req.gp_pin = pinn;
+ if (ioctl(fd, GPIOGET, &req) < 0) {
+ perror("ioctl(GPIOGET)");
+ exit(1);
+ }
+ printf("%d\n", req.gp_value);
+ exit (0);
+ }
+
+ /* Is it valid number (0 or 1) ? */
+ pinv = str2int(argv[1], &ok);
+ if (!ok || ((pinv != 0) && (pinv != 1)))
+ fail("Invalid pin value: %s\n", argv[1]);
+
+ /*
+ * Set pin value
+ */
+ req.gp_pin = pinn;
+ req.gp_value = pinv;
+ if (ioctl(fd, GPIOSET, &req) < 0) {
+ perror("ioctl(GPIOSET)");
+ exit(1);
+ }
+
+ close(fd);
+ exit(0);
+}
OpenPOWER on IntegriCloud