xref: /openbsd-src/usr.sbin/gpioctl/gpioctl.c (revision 8978cb65a40c32b5e73841de6a54cf1e43704430)
1*8978cb65Smmcc /*	$OpenBSD: gpioctl.c,v 1.17 2015/12/26 20:52:03 mmcc Exp $	*/
248e05255Sgrange /*
3b4828597Smbalmer  * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
448e05255Sgrange  * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
548e05255Sgrange  *
648e05255Sgrange  * Permission to use, copy, modify, and distribute this software for any
748e05255Sgrange  * purpose with or without fee is hereby granted, provided that the above
848e05255Sgrange  * copyright notice and this permission notice appear in all copies.
948e05255Sgrange  *
1048e05255Sgrange  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1148e05255Sgrange  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1248e05255Sgrange  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1348e05255Sgrange  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1448e05255Sgrange  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1548e05255Sgrange  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1648e05255Sgrange  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1748e05255Sgrange  */
1848e05255Sgrange 
1948e05255Sgrange /*
2048e05255Sgrange  * Program to control GPIO devices.
2148e05255Sgrange  */
2248e05255Sgrange 
2348e05255Sgrange #include <sys/types.h>
2448e05255Sgrange #include <sys/gpio.h>
2548e05255Sgrange #include <sys/ioctl.h>
26edf9ea1aSderaadt #include <sys/limits.h>
2748e05255Sgrange 
2848e05255Sgrange #include <err.h>
29b9a1499cSmbalmer #include <errno.h>
3048e05255Sgrange #include <fcntl.h>
312e6ed72bSmbalmer #include <paths.h>
3248e05255Sgrange #include <stdio.h>
3348e05255Sgrange #include <stdlib.h>
3448e05255Sgrange #include <string.h>
3548e05255Sgrange #include <unistd.h>
3648e05255Sgrange 
3748e05255Sgrange 
382e6ed72bSmbalmer char *dev;
3948e05255Sgrange int devfd = -1;
4048e05255Sgrange int quiet = 0;
4148e05255Sgrange 
4248e05255Sgrange void	getinfo(void);
432e6ed72bSmbalmer void	pinread(int, char *);
442e6ed72bSmbalmer void	pinwrite(int, char *, int);
452e6ed72bSmbalmer void	pinset(int pin, char *name, int flags, char *alias);
462e6ed72bSmbalmer void	unset(int pin, char *name);
477d434456Smatthieu void	devattach(char *, int, u_int32_t, u_int32_t);
48b9a1499cSmbalmer void	devdetach(char *);
4948e05255Sgrange 
5048e05255Sgrange __dead void usage(void);
5148e05255Sgrange 
5248e05255Sgrange const struct bitstr {
5348e05255Sgrange 	unsigned int mask;
5448e05255Sgrange 	const char *string;
5548e05255Sgrange } pinflags[] = {
5648e05255Sgrange 	{ GPIO_PIN_INPUT, "in" },
5748e05255Sgrange 	{ GPIO_PIN_OUTPUT, "out" },
5848e05255Sgrange 	{ GPIO_PIN_INOUT, "inout" },
5948e05255Sgrange 	{ GPIO_PIN_OPENDRAIN, "od" },
6048e05255Sgrange 	{ GPIO_PIN_PUSHPULL, "pp" },
6148e05255Sgrange 	{ GPIO_PIN_TRISTATE, "tri" },
6248e05255Sgrange 	{ GPIO_PIN_PULLUP, "pu" },
63017db7a3Smbalmer 	{ GPIO_PIN_PULLDOWN, "pd" },
64c6dcffecSmbalmer 	{ GPIO_PIN_INVIN, "iin" },
65c6dcffecSmbalmer 	{ GPIO_PIN_INVOUT, "iout" },
6648e05255Sgrange 	{ 0, NULL },
6748e05255Sgrange };
6848e05255Sgrange 
6948e05255Sgrange int
main(int argc,char * argv[])7048e05255Sgrange main(int argc, char *argv[])
7148e05255Sgrange {
722e6ed72bSmbalmer 	const struct bitstr *bs;
73b9a1499cSmbalmer 	long lval;
747d434456Smatthieu 	u_int32_t ga_mask = 0, ga_flags = 0;
75b4828597Smbalmer 	int pin, ch, ga_offset = -1, n, fl = 0, value = 0;
76b4828597Smbalmer 	const char *errstr;
777d434456Smatthieu 	char *ep, *flags, *nam = NULL;
782e6ed72bSmbalmer 	char devn[32];
7948e05255Sgrange 
802e6ed72bSmbalmer 	while ((ch = getopt(argc, argv, "q")) != -1)
8148e05255Sgrange 		switch (ch) {
8248e05255Sgrange 		case 'q':
8348e05255Sgrange 			quiet = 1;
8448e05255Sgrange 			break;
8548e05255Sgrange 		default:
8648e05255Sgrange 			usage();
8748e05255Sgrange 			/* NOTREACHED */
8848e05255Sgrange 		}
8948e05255Sgrange 	argc -= optind;
9048e05255Sgrange 	argv += optind;
9148e05255Sgrange 
922e6ed72bSmbalmer 	if (argc < 1)
9348e05255Sgrange 		usage();
942e6ed72bSmbalmer 	dev = argv[0];
952e6ed72bSmbalmer 
962e6ed72bSmbalmer 	if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) {
9789a69f69Smbalmer 		(void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev);
982e6ed72bSmbalmer 		dev = devn;
992e6ed72bSmbalmer 	}
1002e6ed72bSmbalmer 
1012e6ed72bSmbalmer 	if ((devfd = open(dev, O_RDWR)) == -1)
1022e6ed72bSmbalmer 		err(1, "%s", dev);
1032e6ed72bSmbalmer 
1042e6ed72bSmbalmer 	if (argc == 1) {
1052e6ed72bSmbalmer 		getinfo();
1062e6ed72bSmbalmer 		return 0;
1072e6ed72bSmbalmer 	}
1082e6ed72bSmbalmer 
1092e6ed72bSmbalmer 	if (!strcmp(argv[1], "attach")) {
1102e6ed72bSmbalmer 		char *driver, *offset, *mask;
1112e6ed72bSmbalmer 
1127d434456Smatthieu 		if (argc != 5 && argc != 6)
1132e6ed72bSmbalmer 			usage();
1142e6ed72bSmbalmer 
1152e6ed72bSmbalmer 		driver = argv[2];
1162e6ed72bSmbalmer 		offset = argv[3];
1172e6ed72bSmbalmer 		mask = argv[4];
1187d434456Smatthieu 		flags = argc == 6 ? argv[5] : NULL;
1192e6ed72bSmbalmer 
1202e6ed72bSmbalmer 		ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
1212e6ed72bSmbalmer 		if (errstr)
1222e6ed72bSmbalmer 			errx(1, "offset is %s: %s", errstr, offset);
1232e6ed72bSmbalmer 
1242e6ed72bSmbalmer 		lval = strtol(mask, &ep, 0);
1252e6ed72bSmbalmer 		if (*mask == '\0' || *ep != '\0')
1262e6ed72bSmbalmer 			errx(1, "invalid mask (not a number)");
1272e6ed72bSmbalmer 		if ((errno == ERANGE && (lval == LONG_MAX
1282e6ed72bSmbalmer 		    || lval == LONG_MIN)) || lval > UINT_MAX)
1292e6ed72bSmbalmer 			errx(1, "mask out of range");
1302e6ed72bSmbalmer 		ga_mask = lval;
1317d434456Smatthieu 		if (flags != NULL) {
1327d434456Smatthieu 			lval = strtonum(flags, 0, UINT_MAX, &errstr);
1337d434456Smatthieu 			if (errstr)
1347d434456Smatthieu 				errx(1, "flags is %s: %s", errstr, flags);
1357d434456Smatthieu 			ga_flags = lval;
1367d434456Smatthieu 		}
1377d434456Smatthieu 		devattach(driver, ga_offset, ga_mask, ga_flags);
1382e6ed72bSmbalmer 		return 0;
1392e6ed72bSmbalmer 	} else if (!strcmp(argv[1], "detach")) {
1402e6ed72bSmbalmer 		if (argc != 3)
1412e6ed72bSmbalmer 			usage();
1422e6ed72bSmbalmer 		devdetach(argv[2]);
1432e6ed72bSmbalmer 	} else {
1442e6ed72bSmbalmer 		char *nm = NULL;
1452e6ed72bSmbalmer 
1462e6ed72bSmbalmer 		/* expecting a pin number or name */
1472e6ed72bSmbalmer 		pin = strtonum(argv[1], 0, INT_MAX, &errstr);
1482e6ed72bSmbalmer 		if (errstr)
1492e6ed72bSmbalmer 			nm = argv[1];	/* try named pin */
1502e6ed72bSmbalmer 		if (argc > 2) {
1512e6ed72bSmbalmer 			if (!strcmp(argv[2], "set")) {
1522e6ed72bSmbalmer 				for (n = 3; n < argc; n++) {
1532e6ed72bSmbalmer 					for (bs = pinflags; bs->string != NULL;
1542e6ed72bSmbalmer 					     bs++) {
1552e6ed72bSmbalmer 						if (!strcmp(argv[n],
1562e6ed72bSmbalmer 						    bs->string)) {
1572e6ed72bSmbalmer 							fl |= bs->mask;
1582e6ed72bSmbalmer 							break;
1592e6ed72bSmbalmer 						}
1602e6ed72bSmbalmer 					}
1612e6ed72bSmbalmer 					if (bs->string == NULL)
1622e6ed72bSmbalmer 						nam = argv[n];
1632e6ed72bSmbalmer 				}
1642e6ed72bSmbalmer 				pinset(pin, nm, fl, nam);
1652e6ed72bSmbalmer 			} else if (!strcmp(argv[2], "unset")) {
1662e6ed72bSmbalmer 				unset(pin, nm);
1672e6ed72bSmbalmer 			} else {
1682e6ed72bSmbalmer 				value = strtonum(argv[2], INT_MIN, INT_MAX,
1692e6ed72bSmbalmer 				   &errstr);
17029712188Smbalmer 				if (errstr) {
17129712188Smbalmer 					if (!strcmp(argv[2], "on"))
17229712188Smbalmer 						value = 1;
17329712188Smbalmer 					else if (!strcmp(argv[2], "off"))
17429712188Smbalmer 						value = 0;
17529712188Smbalmer 					else if (!strcmp(argv[2], "toggle"))
17629712188Smbalmer 						value = 2;
17729712188Smbalmer 					else
17829712188Smbalmer 						errx(1, "%s: invalid value",
17929712188Smbalmer 						    argv[2]);
18029712188Smbalmer 				}
1812e6ed72bSmbalmer 				pinwrite(pin, nm, value);
1822e6ed72bSmbalmer 			}
1832e6ed72bSmbalmer 		} else
1842e6ed72bSmbalmer 			pinread(pin, nm);
18548e05255Sgrange 	}
18648e05255Sgrange 
18748e05255Sgrange 	return (0);
18848e05255Sgrange }
18948e05255Sgrange 
19048e05255Sgrange void
getinfo(void)19148e05255Sgrange getinfo(void)
19248e05255Sgrange {
19348e05255Sgrange 	struct gpio_info info;
19448e05255Sgrange 
195*8978cb65Smmcc 	memset(&info, 0, sizeof(info));
19648e05255Sgrange 	if (ioctl(devfd, GPIOINFO, &info) == -1)
19748e05255Sgrange 		err(1, "GPIOINFO");
19848e05255Sgrange 
19948e05255Sgrange 	if (quiet)
20048e05255Sgrange 		return;
20148e05255Sgrange 
2022e6ed72bSmbalmer 	printf("%s: %d pins\n", dev, info.gpio_npins);
20348e05255Sgrange }
20448e05255Sgrange 
20548e05255Sgrange void
pinread(int pin,char * gp_name)2062e6ed72bSmbalmer pinread(int pin, char *gp_name)
20748e05255Sgrange {
20848e05255Sgrange 	struct gpio_pin_op op;
20948e05255Sgrange 
210*8978cb65Smmcc 	memset(&op, 0, sizeof(op));
2112e6ed72bSmbalmer 	if (gp_name != NULL)
2122e6ed72bSmbalmer 		strlcpy(op.gp_name, gp_name, sizeof(op.gp_name));
2132e6ed72bSmbalmer 	else
21448e05255Sgrange 		op.gp_pin = pin;
2152e6ed72bSmbalmer 
21648e05255Sgrange 	if (ioctl(devfd, GPIOPINREAD, &op) == -1)
21748e05255Sgrange 		err(1, "GPIOPINREAD");
21848e05255Sgrange 
21948e05255Sgrange 	if (quiet)
22048e05255Sgrange 		return;
22148e05255Sgrange 
2222e6ed72bSmbalmer 	if (gp_name)
2232e6ed72bSmbalmer 		printf("pin %s: state %d\n", gp_name, op.gp_value);
2242e6ed72bSmbalmer 	else
22548e05255Sgrange 		printf("pin %d: state %d\n", pin, op.gp_value);
22648e05255Sgrange }
22748e05255Sgrange 
22848e05255Sgrange void
pinwrite(int pin,char * gp_name,int value)2292e6ed72bSmbalmer pinwrite(int pin, char *gp_name, int value)
23048e05255Sgrange {
23148e05255Sgrange 	struct gpio_pin_op op;
23248e05255Sgrange 
23348e05255Sgrange 	if (value < 0 || value > 2)
23448e05255Sgrange 		errx(1, "%d: invalid value", value);
23548e05255Sgrange 
236*8978cb65Smmcc 	memset(&op, 0, sizeof(op));
2372e6ed72bSmbalmer 	if (gp_name != NULL)
2382e6ed72bSmbalmer 		strlcpy(op.gp_name, gp_name, sizeof(op.gp_name));
2392e6ed72bSmbalmer 	else
24048e05255Sgrange 		op.gp_pin = pin;
24148e05255Sgrange 	op.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH);
24248e05255Sgrange 	if (value < 2) {
24348e05255Sgrange 		if (ioctl(devfd, GPIOPINWRITE, &op) == -1)
24429712188Smbalmer 			err(1, "GPIOPINWRITE");
24548e05255Sgrange 	} else {
24648e05255Sgrange 		if (ioctl(devfd, GPIOPINTOGGLE, &op) == -1)
24748e05255Sgrange 			err(1, "GPIOPINTOGGLE");
24848e05255Sgrange 	}
24948e05255Sgrange 
25048e05255Sgrange 	if (quiet)
25148e05255Sgrange 		return;
25248e05255Sgrange 
2532e6ed72bSmbalmer 	if (gp_name)
2542e6ed72bSmbalmer 		printf("pin %s: state %d -> %d\n", gp_name, op.gp_value,
2552e6ed72bSmbalmer 		    (value < 2 ? value : 1 - op.gp_value));
2562e6ed72bSmbalmer 	else
25748e05255Sgrange 		printf("pin %d: state %d -> %d\n", pin, op.gp_value,
25848e05255Sgrange 		    (value < 2 ? value : 1 - op.gp_value));
25948e05255Sgrange }
26048e05255Sgrange 
26148e05255Sgrange void
pinset(int pin,char * name,int fl,char * alias)2622e6ed72bSmbalmer pinset(int pin, char *name, int fl, char *alias)
26348e05255Sgrange {
2642e6ed72bSmbalmer 	struct gpio_pin_set set;
26548e05255Sgrange 	const struct bitstr *bs;
26648e05255Sgrange 
267*8978cb65Smmcc 	memset(&set, 0, sizeof(set));
2682e6ed72bSmbalmer 	if (name != NULL)
2692e6ed72bSmbalmer 		strlcpy(set.gp_name, name, sizeof(set.gp_name));
2702e6ed72bSmbalmer 	else
2712e6ed72bSmbalmer 		set.gp_pin = pin;
2722e6ed72bSmbalmer 	set.gp_flags = fl;
2732e6ed72bSmbalmer 
2742e6ed72bSmbalmer 	if (alias != NULL)
2752e6ed72bSmbalmer 		strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
2762e6ed72bSmbalmer 
2772e6ed72bSmbalmer 	if (ioctl(devfd, GPIOPINSET, &set) == -1)
2782e6ed72bSmbalmer 		err(1, "GPIOPINSET");
27948e05255Sgrange 
28048e05255Sgrange 	if (quiet)
28148e05255Sgrange 		return;
28248e05255Sgrange 
2832e6ed72bSmbalmer 	if (name != NULL)
2842e6ed72bSmbalmer 		printf("pin %s: caps:", name);
2852e6ed72bSmbalmer 	else
28648e05255Sgrange 		printf("pin %d: caps:", pin);
28748e05255Sgrange 	for (bs = pinflags; bs->string != NULL; bs++)
2882e6ed72bSmbalmer 		if (set.gp_caps & bs->mask)
28948e05255Sgrange 			printf(" %s", bs->string);
29048e05255Sgrange 	printf(", flags:");
29148e05255Sgrange 	for (bs = pinflags; bs->string != NULL; bs++)
2922e6ed72bSmbalmer 		if (set.gp_flags & bs->mask)
29348e05255Sgrange 			printf(" %s", bs->string);
29448e05255Sgrange 	if (fl > 0) {
29548e05255Sgrange 		printf(" ->");
29648e05255Sgrange 		for (bs = pinflags; bs->string != NULL; bs++)
29748e05255Sgrange 			if (fl & bs->mask)
29848e05255Sgrange 				printf(" %s", bs->string);
29948e05255Sgrange 	}
30048e05255Sgrange 	printf("\n");
30148e05255Sgrange }
30248e05255Sgrange 
30348e05255Sgrange void
unset(int pin,char * name)3042e6ed72bSmbalmer unset(int pin, char *name)
3052e6ed72bSmbalmer {
3062e6ed72bSmbalmer 	struct gpio_pin_set set;
3072e6ed72bSmbalmer 
308*8978cb65Smmcc 	memset(&set, 0, sizeof(set));
3092e6ed72bSmbalmer 	if (name != NULL)
3102e6ed72bSmbalmer 		strlcpy(set.gp_name, name, sizeof(set.gp_name));
3112e6ed72bSmbalmer 	else
3122e6ed72bSmbalmer 		set.gp_pin = pin;
3132e6ed72bSmbalmer 
3142e6ed72bSmbalmer 	if (ioctl(devfd, GPIOPINUNSET, &set) == -1)
3152e6ed72bSmbalmer 		err(1, "GPIOPINUNSET");
3162e6ed72bSmbalmer }
3172e6ed72bSmbalmer 
3182e6ed72bSmbalmer void
devattach(char * dvname,int offset,u_int32_t mask,u_int32_t flags)3197d434456Smatthieu devattach(char *dvname, int offset, u_int32_t mask, u_int32_t flags)
320b9a1499cSmbalmer {
321b9a1499cSmbalmer 	struct gpio_attach attach;
322b9a1499cSmbalmer 
323*8978cb65Smmcc 	memset(&attach, 0, sizeof(attach));
324b9a1499cSmbalmer 	strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
325b9a1499cSmbalmer 	attach.ga_offset = offset;
326b9a1499cSmbalmer 	attach.ga_mask = mask;
3277d434456Smatthieu 	attach.ga_flags = flags;
328b9a1499cSmbalmer 	if (ioctl(devfd, GPIOATTACH, &attach) == -1)
329b9a1499cSmbalmer 		err(1, "GPIOATTACH");
330b9a1499cSmbalmer }
331b9a1499cSmbalmer 
332b9a1499cSmbalmer void
devdetach(char * dvname)333b9a1499cSmbalmer devdetach(char *dvname)
334b9a1499cSmbalmer {
335b9a1499cSmbalmer 	struct gpio_attach attach;
336b9a1499cSmbalmer 
337*8978cb65Smmcc 	memset(&attach, 0, sizeof(attach));
338b9a1499cSmbalmer 	strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
339b9a1499cSmbalmer 	if (ioctl(devfd, GPIODETACH, &attach) == -1)
340b9a1499cSmbalmer 		err(1, "GPIODETACH");
341b9a1499cSmbalmer }
342b9a1499cSmbalmer void
usage(void)34348e05255Sgrange usage(void)
34448e05255Sgrange {
34548e05255Sgrange 	extern char *__progname;
34648e05255Sgrange 
3473af2d23dSjmc 	fprintf(stderr, "usage: %s [-q] device pin [0 | 1 | 2 | "
34829712188Smbalmer 	    "on | off | toggle]\n", __progname);
3492e6ed72bSmbalmer 	fprintf(stderr, "       %s [-q] device pin set [flags] [name]\n",
35048e05255Sgrange 	    __progname);
3512e6ed72bSmbalmer 	fprintf(stderr, "       %s [-q] device pin unset\n", __progname);
3527d434456Smatthieu 	fprintf(stderr, "       %s [-q] device attach device offset mask "
3537d434456Smatthieu 	    "[flag]\n", __progname);
3542e6ed72bSmbalmer 	fprintf(stderr, "       %s [-q] device detach device\n", __progname);
35548e05255Sgrange 
35648e05255Sgrange 	exit(1);
35748e05255Sgrange }
358