Home | History | Annotate | Line # | Download | only in gpioctl
gpioctl.c revision 1.13
      1 /* $NetBSD: gpioctl.c,v 1.13 2011/09/15 11:46:32 mbalmer Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2008, 2010, 2011 Marc Balmer <mbalmer (at) NetBSD.org>
      5  * Copyright (c) 2004 Alexander Yurchenko <grange (at) openbsd.org>
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 /*
     21  * Program to control GPIO devices.
     22  */
     23 
     24 #include <sys/types.h>
     25 #include <sys/gpio.h>
     26 #include <sys/ioctl.h>
     27 
     28 #include <err.h>
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #include <limits.h>
     32 #include <paths.h>
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <time.h>
     36 #include <string.h>
     37 #include <unistd.h>
     38 
     39 static char *dev;
     40 static int devfd = -1;
     41 static int quiet = 0;
     42 
     43 static void getinfo(void);
     44 static void gpioread(int, char *);
     45 static void gpiowrite(int, char *, int);
     46 static void gpiopulse(int, char *, double, double);
     47 static void gpioset(int pin, char *name, int flags, char *alias);
     48 static void gpiounset(int pin, char *name);
     49 static void devattach(char *, int, uint32_t);
     50 static void devdetach(char *);
     51 __dead static void usage(void);
     52 
     53 extern long long strtonum(const char *numstr, long long minval,
     54     long long maxval, const char **errstrp);
     55 
     56 static const struct bitstr {
     57 	unsigned int mask;
     58 	const char *string;
     59 } pinflags[] = {
     60 	{ GPIO_PIN_INPUT, "in" },
     61 	{ GPIO_PIN_OUTPUT, "out" },
     62 	{ GPIO_PIN_INOUT, "inout" },
     63 	{ GPIO_PIN_OPENDRAIN, "od" },
     64 	{ GPIO_PIN_PUSHPULL, "pp" },
     65 	{ GPIO_PIN_TRISTATE, "tri" },
     66 	{ GPIO_PIN_PULLUP, "pu" },
     67 	{ GPIO_PIN_PULLDOWN, "pd" },
     68 	{ GPIO_PIN_INVIN, "iin" },
     69 	{ GPIO_PIN_INVOUT, "iout" },
     70 	{ GPIO_PIN_PULSATE, "pulsate" },
     71 	{ 0, NULL },
     72 };
     73 
     74 int
     75 main(int argc, char *argv[])
     76 {
     77 	const struct bitstr *bs;
     78 	double freq, dc;
     79 	int pin, ch, n, fl = 0, value = 0;
     80 	const char *errstr;
     81 	char *ep;
     82 	int ga_offset = -1;
     83 	uint32_t ga_mask = 0;
     84 	long lval;
     85 	char *nam = NULL;
     86 	char devn[32];
     87 
     88 	while ((ch = getopt(argc, argv, "q")) != -1)
     89 		switch (ch) {
     90 		case 'q':
     91 			quiet = 1;
     92 			break;
     93 		default:
     94 			usage();
     95 			/* NOTREACHED */
     96 		}
     97 	argc -= optind;
     98 	argv += optind;
     99 
    100 	if (argc < 1)
    101 		usage();
    102 	dev = argv[0];
    103 
    104 	freq = dc = 0.0;
    105 
    106 	if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) {
    107 		(void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev);
    108 		dev = devn;
    109 	}
    110 
    111 	if ((devfd = open(dev, O_RDWR)) == -1)
    112 		err(EXIT_FAILURE, "%s", dev);
    113 
    114 	if (argc == 1) {
    115 		getinfo();
    116 		return EXIT_SUCCESS;
    117 	}
    118 
    119 	if (!strcmp(argv[1], "attach")) {
    120 		char *driver, *offset, *mask;
    121 
    122 		if (argc != 5)
    123 			usage();
    124 
    125 		driver = argv[2];
    126 		offset = argv[3];
    127 		mask = argv[4];
    128 
    129 		ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
    130 		if (errstr)
    131 			errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset);
    132 		lval = strtol(mask, &ep, 0);
    133 		if (*mask == '\0' || *ep != '\0')
    134 			errx(EXIT_FAILURE, "invalid mask (not a number)");
    135 		if ((errno == ERANGE && (lval == LONG_MAX
    136 		    || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX)
    137 			errx(EXIT_FAILURE, "mask out of range");
    138 		ga_mask = lval;
    139 		devattach(driver, ga_offset, ga_mask);
    140 		return EXIT_SUCCESS;
    141 	} else if (!strcmp(argv[1], "detach")) {
    142 		if (argc != 3)
    143 			usage();
    144 		devdetach(argv[2]);
    145 	} else {
    146 		char *nm = NULL;
    147 
    148 		/* expecting a pin number or name */
    149 		pin = strtonum(argv[1], 0, INT_MAX, &errstr);
    150 		if (errstr)
    151 			nm = argv[1];	/* try named pin */
    152 		if (argc > 2) {
    153 			if (!strcmp(argv[2], "set")) {
    154 				for (n = 3; n < argc; n++) {
    155 					for (bs = pinflags; bs->string != NULL;
    156 					     bs++) {
    157 						if (!strcmp(argv[n],
    158 						    bs->string)) {
    159 							fl |= bs->mask;
    160 							break;
    161 						}
    162 					}
    163 					if (bs->string == NULL)
    164 						nam = argv[n];
    165 				}
    166 				gpioset(pin, nm, fl, nam);
    167 			} else if (!strcmp(argv[2], "unset")) {
    168 				gpiounset(pin, nm);
    169 			} else if (!strcmp(argv[2], "pulse")) {
    170 				if (argc == 4) {
    171 					freq = atof(argv[3]);
    172 					dc = 50.0;
    173 				} else if (argc == 5) {
    174 					freq = atof(argv[3]);
    175 					dc = atof(argv[4]);
    176 				} else
    177 					freq = dc = 0.0;
    178 				gpiopulse(pin, nm, freq, dc);
    179 			} else {
    180 				value = strtonum(argv[2], INT_MIN, INT_MAX,
    181 				   &errstr);
    182 				if (errstr) {
    183 					if (!strcmp(argv[2], "on"))
    184 						value = GPIO_PIN_HIGH;
    185 					else if (!strcmp(argv[2], "off"))
    186 						value = GPIO_PIN_LOW;
    187 					else if (!strcmp(argv[2], "toggle"))
    188 						value = 2;
    189 					else
    190 						errx(EXIT_FAILURE,
    191 						    "%s: invalid value",
    192 						    argv[2]);
    193 				}
    194 				gpiowrite(pin, nm, value);
    195 			}
    196 		} else
    197 			gpioread(pin, nm);
    198 	}
    199 
    200 	return EXIT_SUCCESS;
    201 }
    202 
    203 static void
    204 getinfo(void)
    205 {
    206 	struct gpio_info info;
    207 
    208 	if (ioctl(devfd, GPIOINFO, &info) == -1)
    209 		err(EXIT_FAILURE, "GPIOINFO");
    210 
    211 	if (quiet)
    212 		return;
    213 
    214 	printf("%s: %d pins\n", dev, info.gpio_npins);
    215 }
    216 
    217 static void
    218 gpioread(int pin, char *gp_name)
    219 {
    220 	struct gpio_req req;
    221 
    222 	memset(&req, 0, sizeof(req));
    223 	if (gp_name != NULL)
    224 		strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
    225 	else
    226 		req.gp_pin = pin;
    227 
    228 	if (ioctl(devfd, GPIOREAD, &req) == -1)
    229 		err(EXIT_FAILURE, "GPIOREAD");
    230 
    231 	if (quiet)
    232 		return;
    233 
    234 	if (gp_name)
    235 		printf("pin %s: state %d\n", gp_name, req.gp_value);
    236 	else
    237 		printf("pin %d: state %d\n", pin, req.gp_value);
    238 }
    239 
    240 static void
    241 gpiowrite(int pin, char *gp_name, int value)
    242 {
    243 	struct gpio_req req;
    244 
    245 	if (value < 0 || value > 2)
    246 		errx(EXIT_FAILURE, "%d: invalid value", value);
    247 
    248 	memset(&req, 0, sizeof(req));
    249 	if (gp_name != NULL)
    250 		strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
    251 	else
    252 		req.gp_pin = pin;
    253 
    254 	if (value == GPIO_PIN_HIGH || value == GPIO_PIN_LOW) {
    255 		req.gp_value = value;
    256 		if (ioctl(devfd, GPIOWRITE, &req) == -1)
    257 			err(EXIT_FAILURE, "GPIOWRITE");
    258 	} else {
    259 		if (ioctl(devfd, GPIOTOGGLE, &req) == -1)
    260 			err(EXIT_FAILURE, "GPIOTOGGLE");
    261 	}
    262 
    263 	if (quiet)
    264 		return;
    265 
    266 	if (gp_name)
    267 		printf("pin %s: state %d -> %d\n", gp_name, req.gp_value,
    268 		    (value < 2 ? value : 1 - req.gp_value));
    269 	else
    270 		printf("pin %d: state %d -> %d\n", pin, req.gp_value,
    271 		    (value < 2 ? value : 1 - req.gp_value));
    272 }
    273 
    274 static void
    275 gpiopulse(int pin, char *gp_name, double freq, double dc)
    276 {
    277 	struct gpio_pulse pulse;
    278 	suseconds_t period, on, off;
    279 
    280 	if (freq < 0.0 || (dc < 0.0 || dc >= 100.0))
    281 		errx(EXIT_FAILURE, "%.f Hz, %.f%% duty cycle: invalid value",
    282 		    freq, dc);
    283 
    284 	memset(&pulse, 0, sizeof(pulse));
    285 	if (gp_name != NULL)
    286 		strlcpy(pulse.gp_name, gp_name, sizeof(pulse.gp_name));
    287 	else
    288 		pulse.gp_pin = pin;
    289 
    290 	if (freq > 0.0 && dc > 0.0) {
    291 		period = 1000000 / freq;
    292 		on = period * dc / 100;
    293 		off = period - on;
    294 
    295 		if (on >= 1000000) {
    296 			pulse.gp_pulse_on.tv_sec = on / 1000000;
    297 			on -= pulse.gp_pulse_on.tv_sec * 1000000;
    298 			pulse.gp_pulse_on.tv_usec = on;
    299 		} else {
    300 			pulse.gp_pulse_on.tv_sec = 0;
    301 			pulse.gp_pulse_on.tv_usec = on;
    302 		}
    303 		if (off >= 1000000) {
    304 			pulse.gp_pulse_off.tv_sec = off / 1000000;
    305 			off -= pulse.gp_pulse_off.tv_sec * 1000000;
    306 			pulse.gp_pulse_off.tv_usec = off;
    307 		} else {
    308 			pulse.gp_pulse_off.tv_sec = 0;
    309 			pulse.gp_pulse_off.tv_usec = off;
    310 		}
    311 	} else {	/* gpio(4) defaults */
    312 		freq = 1.0;
    313 		dc = 50.0;
    314 	}
    315 
    316 	if (ioctl(devfd, GPIOPULSE, &pulse) == -1)
    317 		err(EXIT_FAILURE, "GPIOPULSE");
    318 
    319 	if (quiet)
    320 		return;
    321 
    322 	if (gp_name)
    323 		printf("pin %s: pulse at %.f Hz with a %.f%% duty cylce\n",
    324 		    gp_name, freq, dc);
    325 	else
    326 		printf("pin %d: pulse at %.f Hz with a %.f%% duty cylce\n",
    327 		    pin, freq, dc);
    328 }
    329 
    330 static void
    331 gpioset(int pin, char *name, int fl, char *alias)
    332 {
    333 	struct gpio_set set;
    334 	const struct bitstr *bs;
    335 
    336 	memset(&set, 0, sizeof(set));
    337 	if (name != NULL)
    338 		strlcpy(set.gp_name, name, sizeof(set.gp_name));
    339 	else
    340 		set.gp_pin = pin;
    341 	set.gp_flags = fl;
    342 
    343 	if (alias != NULL)
    344 		strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
    345 
    346 	if (ioctl(devfd, GPIOSET, &set) == -1)
    347 		err(EXIT_FAILURE, "GPIOSET");
    348 
    349 	if (quiet)
    350 		return;
    351 
    352 	if (name != NULL)
    353 		printf("pin %s: caps:", name);
    354 	else
    355 		printf("pin %d: caps:", pin);
    356 	for (bs = pinflags; bs->string != NULL; bs++)
    357 		if (set.gp_caps & bs->mask)
    358 			printf(" %s", bs->string);
    359 	printf(", flags:");
    360 	for (bs = pinflags; bs->string != NULL; bs++)
    361 		if (set.gp_flags & bs->mask)
    362 			printf(" %s", bs->string);
    363 	if (fl > 0) {
    364 		printf(" ->");
    365 		for (bs = pinflags; bs->string != NULL; bs++)
    366 			if (fl & bs->mask)
    367 				printf(" %s", bs->string);
    368 	}
    369 	printf("\n");
    370 }
    371 
    372 static void
    373 gpiounset(int pin, char *name)
    374 {
    375 	struct gpio_set set;
    376 
    377 	memset(&set, 0, sizeof(set));
    378 	if (name != NULL)
    379 		strlcpy(set.gp_name, name, sizeof(set.gp_name));
    380 	else
    381 		set.gp_pin = pin;
    382 
    383 	if (ioctl(devfd, GPIOUNSET, &set) == -1)
    384 		err(EXIT_FAILURE, "GPIOUNSET");
    385 }
    386 
    387 static void
    388 devattach(char *dvname, int offset, uint32_t mask)
    389 {
    390 	struct gpio_attach attach;
    391 
    392 	memset(&attach, 0, sizeof(attach));
    393 	strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
    394 	attach.ga_offset = offset;
    395 	attach.ga_mask = mask;
    396 	if (ioctl(devfd, GPIOATTACH, &attach) == -1)
    397 		err(EXIT_FAILURE, "GPIOATTACH");
    398 }
    399 
    400 static void
    401 devdetach(char *dvname)
    402 {
    403 	struct gpio_attach attach;
    404 
    405 	memset(&attach, 0, sizeof(attach));
    406 	strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
    407 	if (ioctl(devfd, GPIODETACH, &attach) == -1)
    408 		err(EXIT_FAILURE, "GPIODETACH");
    409 }
    410 
    411 static void
    412 usage(void)
    413 {
    414 	const char *progname;
    415 
    416 	progname = getprogname();
    417 	fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | "
    418 	    "on | off | toggle]\n", progname);
    419 	fprintf(stderr, "usage: %s [-q] device pin pulse [frequency "
    420 	    "[duty cycle]]\n", progname);
    421 	fprintf(stderr, "       %s [-q] device pin set [flags] [name]\n",
    422 	    progname);
    423 	fprintf(stderr, "       %s [-q] device pin unset\n", progname);
    424 	fprintf(stderr, "       %s [-q] device attach device offset mask\n",
    425 	    progname);
    426 	fprintf(stderr, "       %s [-q] device detach device\n", progname);
    427 
    428 	exit(EXIT_FAILURE);
    429 }
    430