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