svn commit: r213238 - in head/usr.sbin: . gpioctl

Oleksandr Tymoshenko gonzo at FreeBSD.org
Tue Sep 28 03:28:21 UTC 2010


Author: gonzo
Date: Tue Sep 28 03:28:20 2010
New Revision: 213238
URL: http://svn.freebsd.org/changeset/base/213238

Log:
  Add gpioctl(8). Utility for configuring/accessing GPIO pins

Added:
  head/usr.sbin/gpioctl/
  head/usr.sbin/gpioctl/Makefile   (contents, props changed)
  head/usr.sbin/gpioctl/gpioctl.8   (contents, props changed)
  head/usr.sbin/gpioctl/gpioctl.c   (contents, props changed)
Modified:
  head/usr.sbin/Makefile

Modified: head/usr.sbin/Makefile
==============================================================================
--- head/usr.sbin/Makefile	Tue Sep 28 03:24:53 2010	(r213237)
+++ head/usr.sbin/Makefile	Tue Sep 28 03:28:20 2010	(r213238)
@@ -27,6 +27,7 @@ SUBDIR= adduser \
 	fwcontrol \
 	getfmac \
 	getpmac \
+	gpioctl \
 	gstat \
 	i2c \
 	ifmcstat \

Added: head/usr.sbin/gpioctl/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/gpioctl/Makefile	Tue Sep 28 03:28:20 2010	(r213238)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+PROG=	gpioctl
+MAN=	gpioctl.8
+
+.include <bsd.prog.mk>

Added: head/usr.sbin/gpioctl/gpioctl.8
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/gpioctl/gpioctl.8	Tue Sep 28 03:28:20 2010	(r213238)
@@ -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 at freebsd.org

Added: head/usr.sbin/gpioctl/gpioctl.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/gpioctl/gpioctl.c	Tue Sep 28 03:28:20 2010	(r213238)
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo at 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);
+}


More information about the svn-src-head mailing list