1*be149ed8Smbalmer /* $NetBSD: gpioctl.c,v 1.14 2011/10/02 09:33:19 mbalmer Exp $ */ 232eeaba5Smbalmer 3825ff184Sjmcneill /* 4ffeab64fSmbalmer * Copyright (c) 2008, 2010, 2011 Marc Balmer <mbalmer@NetBSD.org> 5825ff184Sjmcneill * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> 6825ff184Sjmcneill * 7825ff184Sjmcneill * Permission to use, copy, modify, and distribute this software for any 8825ff184Sjmcneill * purpose with or without fee is hereby granted, provided that the above 9825ff184Sjmcneill * copyright notice and this permission notice appear in all copies. 10825ff184Sjmcneill * 11825ff184Sjmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12825ff184Sjmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13825ff184Sjmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14825ff184Sjmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15825ff184Sjmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16825ff184Sjmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17825ff184Sjmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18825ff184Sjmcneill */ 19825ff184Sjmcneill 20825ff184Sjmcneill /* 21825ff184Sjmcneill * Program to control GPIO devices. 22825ff184Sjmcneill */ 23825ff184Sjmcneill 24825ff184Sjmcneill #include <sys/types.h> 25825ff184Sjmcneill #include <sys/gpio.h> 26825ff184Sjmcneill #include <sys/ioctl.h> 27825ff184Sjmcneill 28825ff184Sjmcneill #include <err.h> 2932eeaba5Smbalmer #include <errno.h> 30825ff184Sjmcneill #include <fcntl.h> 3132eeaba5Smbalmer #include <limits.h> 3232eeaba5Smbalmer #include <paths.h> 33825ff184Sjmcneill #include <stdio.h> 34825ff184Sjmcneill #include <stdlib.h> 35da668cdfSmbalmer #include <time.h> 36825ff184Sjmcneill #include <string.h> 37825ff184Sjmcneill #include <unistd.h> 38825ff184Sjmcneill 39c45de77dSjoerg static char *dev; 40c45de77dSjoerg static int devfd = -1; 41c45de77dSjoerg static int quiet = 0; 42825ff184Sjmcneill 4357ef84d0Smbalmer static void getinfo(void); 4457ef84d0Smbalmer static void gpioread(int, char *); 4557ef84d0Smbalmer static void gpiowrite(int, char *, int); 46da668cdfSmbalmer static void gpiopulse(int, char *, double, double); 4757ef84d0Smbalmer static void gpioset(int pin, char *name, int flags, char *alias); 4857ef84d0Smbalmer static void gpiounset(int pin, char *name); 49*be149ed8Smbalmer static void devattach(char *, int, uint32_t, uint32_t); 5057ef84d0Smbalmer static void devdetach(char *); 51c45de77dSjoerg __dead static void usage(void); 5232eeaba5Smbalmer 5332eeaba5Smbalmer extern long long strtonum(const char *numstr, long long minval, 5432eeaba5Smbalmer long long maxval, const char **errstrp); 5532eeaba5Smbalmer 56c45de77dSjoerg static const struct bitstr { 57825ff184Sjmcneill unsigned int mask; 58825ff184Sjmcneill const char *string; 59825ff184Sjmcneill } pinflags[] = { 60825ff184Sjmcneill { GPIO_PIN_INPUT, "in" }, 61825ff184Sjmcneill { GPIO_PIN_OUTPUT, "out" }, 62825ff184Sjmcneill { GPIO_PIN_INOUT, "inout" }, 63825ff184Sjmcneill { GPIO_PIN_OPENDRAIN, "od" }, 64825ff184Sjmcneill { GPIO_PIN_PUSHPULL, "pp" }, 65825ff184Sjmcneill { GPIO_PIN_TRISTATE, "tri" }, 66825ff184Sjmcneill { GPIO_PIN_PULLUP, "pu" }, 67cfebb94aSxtraeme { GPIO_PIN_PULLDOWN, "pd" }, 68cfebb94aSxtraeme { GPIO_PIN_INVIN, "iin" }, 6932eeaba5Smbalmer { GPIO_PIN_INVOUT, "iout" }, 7098c90767Smbalmer { GPIO_PIN_PULSATE, "pulsate" }, 71825ff184Sjmcneill { 0, NULL }, 72825ff184Sjmcneill }; 73825ff184Sjmcneill 74825ff184Sjmcneill int 75825ff184Sjmcneill main(int argc, char *argv[]) 76825ff184Sjmcneill { 7732eeaba5Smbalmer const struct bitstr *bs; 78da668cdfSmbalmer double freq, dc; 7932eeaba5Smbalmer int pin, ch, n, fl = 0, value = 0; 8032eeaba5Smbalmer const char *errstr; 81825ff184Sjmcneill char *ep; 8232eeaba5Smbalmer int ga_offset = -1; 83da668cdfSmbalmer uint32_t ga_mask = 0; 84*be149ed8Smbalmer uint32_t ga_flags = 0; 8532eeaba5Smbalmer long lval; 8632eeaba5Smbalmer char *nam = NULL; 87*be149ed8Smbalmer char *flags; 8832eeaba5Smbalmer char devn[32]; 89825ff184Sjmcneill 9032eeaba5Smbalmer while ((ch = getopt(argc, argv, "q")) != -1) 91825ff184Sjmcneill switch (ch) { 92825ff184Sjmcneill case 'q': 93825ff184Sjmcneill quiet = 1; 94825ff184Sjmcneill break; 95825ff184Sjmcneill default: 96825ff184Sjmcneill usage(); 97825ff184Sjmcneill /* NOTREACHED */ 98825ff184Sjmcneill } 99825ff184Sjmcneill argc -= optind; 100825ff184Sjmcneill argv += optind; 101825ff184Sjmcneill 10232eeaba5Smbalmer if (argc < 1) 103825ff184Sjmcneill usage(); 10432eeaba5Smbalmer dev = argv[0]; 10532eeaba5Smbalmer 106da668cdfSmbalmer freq = dc = 0.0; 107da668cdfSmbalmer 10832eeaba5Smbalmer if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) { 10932eeaba5Smbalmer (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev); 11032eeaba5Smbalmer dev = devn; 11132eeaba5Smbalmer } 11232eeaba5Smbalmer 11332eeaba5Smbalmer if ((devfd = open(dev, O_RDWR)) == -1) 11432eeaba5Smbalmer err(EXIT_FAILURE, "%s", dev); 11532eeaba5Smbalmer 11632eeaba5Smbalmer if (argc == 1) { 11732eeaba5Smbalmer getinfo(); 11832eeaba5Smbalmer return EXIT_SUCCESS; 11932eeaba5Smbalmer } 12032eeaba5Smbalmer 12132eeaba5Smbalmer if (!strcmp(argv[1], "attach")) { 12232eeaba5Smbalmer char *driver, *offset, *mask; 12332eeaba5Smbalmer 124*be149ed8Smbalmer if (argc != 5 && argc != 6) 12532eeaba5Smbalmer usage(); 12632eeaba5Smbalmer 12732eeaba5Smbalmer driver = argv[2]; 12832eeaba5Smbalmer offset = argv[3]; 12932eeaba5Smbalmer mask = argv[4]; 130*be149ed8Smbalmer flags = argc == 6 ? argv[5] : NULL; 13132eeaba5Smbalmer 13232eeaba5Smbalmer ga_offset = strtonum(offset, 0, INT_MAX, &errstr); 13332eeaba5Smbalmer if (errstr) 13432eeaba5Smbalmer errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset); 13532eeaba5Smbalmer lval = strtol(mask, &ep, 0); 13632eeaba5Smbalmer if (*mask == '\0' || *ep != '\0') 13732eeaba5Smbalmer errx(EXIT_FAILURE, "invalid mask (not a number)"); 13832eeaba5Smbalmer if ((errno == ERANGE && (lval == LONG_MAX 13932eeaba5Smbalmer || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX) 14032eeaba5Smbalmer errx(EXIT_FAILURE, "mask out of range"); 14132eeaba5Smbalmer ga_mask = lval; 142*be149ed8Smbalmer if (flags != NULL) { 143*be149ed8Smbalmer lval = strtol(flags, &ep, 0); 144*be149ed8Smbalmer if (*flags == '\0' || *ep != '\0') 145*be149ed8Smbalmer errx(EXIT_FAILURE, 146*be149ed8Smbalmer "invalid flags (not a number)"); 147*be149ed8Smbalmer if ((errno == ERANGE && (lval == LONG_MAX 148*be149ed8Smbalmer || lval == LONG_MIN)) 149*be149ed8Smbalmer || (unsigned long)lval > UINT_MAX) 150*be149ed8Smbalmer errx(EXIT_FAILURE, "flags out of range"); 151*be149ed8Smbalmer ga_flags = lval; 152*be149ed8Smbalmer } 153*be149ed8Smbalmer devattach(driver, ga_offset, ga_mask, ga_flags); 15432eeaba5Smbalmer return EXIT_SUCCESS; 15532eeaba5Smbalmer } else if (!strcmp(argv[1], "detach")) { 15632eeaba5Smbalmer if (argc != 3) 15732eeaba5Smbalmer usage(); 15832eeaba5Smbalmer devdetach(argv[2]); 15932eeaba5Smbalmer } else { 16032eeaba5Smbalmer char *nm = NULL; 16132eeaba5Smbalmer 16232eeaba5Smbalmer /* expecting a pin number or name */ 16332eeaba5Smbalmer pin = strtonum(argv[1], 0, INT_MAX, &errstr); 16432eeaba5Smbalmer if (errstr) 16532eeaba5Smbalmer nm = argv[1]; /* try named pin */ 16632eeaba5Smbalmer if (argc > 2) { 16732eeaba5Smbalmer if (!strcmp(argv[2], "set")) { 16832eeaba5Smbalmer for (n = 3; n < argc; n++) { 16932eeaba5Smbalmer for (bs = pinflags; bs->string != NULL; 17032eeaba5Smbalmer bs++) { 17132eeaba5Smbalmer if (!strcmp(argv[n], 17232eeaba5Smbalmer bs->string)) { 17332eeaba5Smbalmer fl |= bs->mask; 17432eeaba5Smbalmer break; 17532eeaba5Smbalmer } 17632eeaba5Smbalmer } 17732eeaba5Smbalmer if (bs->string == NULL) 17832eeaba5Smbalmer nam = argv[n]; 17932eeaba5Smbalmer } 18032eeaba5Smbalmer gpioset(pin, nm, fl, nam); 18132eeaba5Smbalmer } else if (!strcmp(argv[2], "unset")) { 18232eeaba5Smbalmer gpiounset(pin, nm); 183da668cdfSmbalmer } else if (!strcmp(argv[2], "pulse")) { 184da668cdfSmbalmer if (argc == 4) { 185da668cdfSmbalmer freq = atof(argv[3]); 186da668cdfSmbalmer dc = 50.0; 187da668cdfSmbalmer } else if (argc == 5) { 188da668cdfSmbalmer freq = atof(argv[3]); 189da668cdfSmbalmer dc = atof(argv[4]); 190da668cdfSmbalmer } else 191da668cdfSmbalmer freq = dc = 0.0; 192da668cdfSmbalmer gpiopulse(pin, nm, freq, dc); 19332eeaba5Smbalmer } else { 19432eeaba5Smbalmer value = strtonum(argv[2], INT_MIN, INT_MAX, 19532eeaba5Smbalmer &errstr); 19632eeaba5Smbalmer if (errstr) { 19732eeaba5Smbalmer if (!strcmp(argv[2], "on")) 198da668cdfSmbalmer value = GPIO_PIN_HIGH; 19932eeaba5Smbalmer else if (!strcmp(argv[2], "off")) 200da668cdfSmbalmer value = GPIO_PIN_LOW; 20132eeaba5Smbalmer else if (!strcmp(argv[2], "toggle")) 20232eeaba5Smbalmer value = 2; 20332eeaba5Smbalmer else 20432eeaba5Smbalmer errx(EXIT_FAILURE, 20532eeaba5Smbalmer "%s: invalid value", 20632eeaba5Smbalmer argv[2]); 20732eeaba5Smbalmer } 20832eeaba5Smbalmer gpiowrite(pin, nm, value); 20932eeaba5Smbalmer } 21032eeaba5Smbalmer } else 21132eeaba5Smbalmer gpioread(pin, nm); 212825ff184Sjmcneill } 213825ff184Sjmcneill 2149b5c4f42Sxtraeme return EXIT_SUCCESS; 215825ff184Sjmcneill } 216825ff184Sjmcneill 21757ef84d0Smbalmer static void 218825ff184Sjmcneill getinfo(void) 219825ff184Sjmcneill { 220825ff184Sjmcneill struct gpio_info info; 221825ff184Sjmcneill 222825ff184Sjmcneill if (ioctl(devfd, GPIOINFO, &info) == -1) 2239b5c4f42Sxtraeme err(EXIT_FAILURE, "GPIOINFO"); 224825ff184Sjmcneill 225825ff184Sjmcneill if (quiet) 226825ff184Sjmcneill return; 227825ff184Sjmcneill 22832eeaba5Smbalmer printf("%s: %d pins\n", dev, info.gpio_npins); 229825ff184Sjmcneill } 230825ff184Sjmcneill 23157ef84d0Smbalmer static void 23232eeaba5Smbalmer gpioread(int pin, char *gp_name) 233825ff184Sjmcneill { 23432eeaba5Smbalmer struct gpio_req req; 235825ff184Sjmcneill 23632eeaba5Smbalmer memset(&req, 0, sizeof(req)); 23732eeaba5Smbalmer if (gp_name != NULL) 23832eeaba5Smbalmer strlcpy(req.gp_name, gp_name, sizeof(req.gp_name)); 23932eeaba5Smbalmer else 24032eeaba5Smbalmer req.gp_pin = pin; 24132eeaba5Smbalmer 24232eeaba5Smbalmer if (ioctl(devfd, GPIOREAD, &req) == -1) 24332eeaba5Smbalmer err(EXIT_FAILURE, "GPIOREAD"); 244825ff184Sjmcneill 245825ff184Sjmcneill if (quiet) 246825ff184Sjmcneill return; 247825ff184Sjmcneill 24832eeaba5Smbalmer if (gp_name) 24932eeaba5Smbalmer printf("pin %s: state %d\n", gp_name, req.gp_value); 25032eeaba5Smbalmer else 25132eeaba5Smbalmer printf("pin %d: state %d\n", pin, req.gp_value); 252825ff184Sjmcneill } 253825ff184Sjmcneill 25457ef84d0Smbalmer static void 25532eeaba5Smbalmer gpiowrite(int pin, char *gp_name, int value) 256825ff184Sjmcneill { 25732eeaba5Smbalmer struct gpio_req req; 258825ff184Sjmcneill 259825ff184Sjmcneill if (value < 0 || value > 2) 2609b5c4f42Sxtraeme errx(EXIT_FAILURE, "%d: invalid value", value); 261825ff184Sjmcneill 26232eeaba5Smbalmer memset(&req, 0, sizeof(req)); 26332eeaba5Smbalmer if (gp_name != NULL) 26432eeaba5Smbalmer strlcpy(req.gp_name, gp_name, sizeof(req.gp_name)); 26532eeaba5Smbalmer else 26632eeaba5Smbalmer req.gp_pin = pin; 267da668cdfSmbalmer 268da668cdfSmbalmer if (value == GPIO_PIN_HIGH || value == GPIO_PIN_LOW) { 269da668cdfSmbalmer req.gp_value = value; 27032eeaba5Smbalmer if (ioctl(devfd, GPIOWRITE, &req) == -1) 27132eeaba5Smbalmer err(EXIT_FAILURE, "GPIOWRITE"); 272825ff184Sjmcneill } else { 27332eeaba5Smbalmer if (ioctl(devfd, GPIOTOGGLE, &req) == -1) 27432eeaba5Smbalmer err(EXIT_FAILURE, "GPIOTOGGLE"); 275825ff184Sjmcneill } 276825ff184Sjmcneill 277825ff184Sjmcneill if (quiet) 278825ff184Sjmcneill return; 279825ff184Sjmcneill 28032eeaba5Smbalmer if (gp_name) 28132eeaba5Smbalmer printf("pin %s: state %d -> %d\n", gp_name, req.gp_value, 28232eeaba5Smbalmer (value < 2 ? value : 1 - req.gp_value)); 28332eeaba5Smbalmer else 28432eeaba5Smbalmer printf("pin %d: state %d -> %d\n", pin, req.gp_value, 28532eeaba5Smbalmer (value < 2 ? value : 1 - req.gp_value)); 286825ff184Sjmcneill } 287825ff184Sjmcneill 28857ef84d0Smbalmer static void 289da668cdfSmbalmer gpiopulse(int pin, char *gp_name, double freq, double dc) 290da668cdfSmbalmer { 291da668cdfSmbalmer struct gpio_pulse pulse; 292da668cdfSmbalmer suseconds_t period, on, off; 293da668cdfSmbalmer 294da668cdfSmbalmer if (freq < 0.0 || (dc < 0.0 || dc >= 100.0)) 295da668cdfSmbalmer errx(EXIT_FAILURE, "%.f Hz, %.f%% duty cycle: invalid value", 296da668cdfSmbalmer freq, dc); 297da668cdfSmbalmer 298da668cdfSmbalmer memset(&pulse, 0, sizeof(pulse)); 299da668cdfSmbalmer if (gp_name != NULL) 300da668cdfSmbalmer strlcpy(pulse.gp_name, gp_name, sizeof(pulse.gp_name)); 301da668cdfSmbalmer else 302da668cdfSmbalmer pulse.gp_pin = pin; 303da668cdfSmbalmer 304da668cdfSmbalmer if (freq > 0.0 && dc > 0.0) { 305da668cdfSmbalmer period = 1000000 / freq; 306da668cdfSmbalmer on = period * dc / 100; 307da668cdfSmbalmer off = period - on; 308da668cdfSmbalmer 309da668cdfSmbalmer if (on >= 1000000) { 310da668cdfSmbalmer pulse.gp_pulse_on.tv_sec = on / 1000000; 311da668cdfSmbalmer on -= pulse.gp_pulse_on.tv_sec * 1000000; 312da668cdfSmbalmer pulse.gp_pulse_on.tv_usec = on; 313da668cdfSmbalmer } else { 314da668cdfSmbalmer pulse.gp_pulse_on.tv_sec = 0; 315da668cdfSmbalmer pulse.gp_pulse_on.tv_usec = on; 316da668cdfSmbalmer } 317da668cdfSmbalmer if (off >= 1000000) { 318da668cdfSmbalmer pulse.gp_pulse_off.tv_sec = off / 1000000; 319da668cdfSmbalmer off -= pulse.gp_pulse_off.tv_sec * 1000000; 320da668cdfSmbalmer pulse.gp_pulse_off.tv_usec = off; 321da668cdfSmbalmer } else { 322da668cdfSmbalmer pulse.gp_pulse_off.tv_sec = 0; 323da668cdfSmbalmer pulse.gp_pulse_off.tv_usec = off; 324da668cdfSmbalmer } 325da668cdfSmbalmer } else { /* gpio(4) defaults */ 326da668cdfSmbalmer freq = 1.0; 327da668cdfSmbalmer dc = 50.0; 328da668cdfSmbalmer } 329da668cdfSmbalmer 330da668cdfSmbalmer if (ioctl(devfd, GPIOPULSE, &pulse) == -1) 331da668cdfSmbalmer err(EXIT_FAILURE, "GPIOPULSE"); 332da668cdfSmbalmer 333da668cdfSmbalmer if (quiet) 334da668cdfSmbalmer return; 335da668cdfSmbalmer 336da668cdfSmbalmer if (gp_name) 337da668cdfSmbalmer printf("pin %s: pulse at %.f Hz with a %.f%% duty cylce\n", 338da668cdfSmbalmer gp_name, freq, dc); 339da668cdfSmbalmer else 340da668cdfSmbalmer printf("pin %d: pulse at %.f Hz with a %.f%% duty cylce\n", 341da668cdfSmbalmer pin, freq, dc); 342da668cdfSmbalmer } 343da668cdfSmbalmer 344da668cdfSmbalmer static void 34532eeaba5Smbalmer gpioset(int pin, char *name, int fl, char *alias) 346825ff184Sjmcneill { 34732eeaba5Smbalmer struct gpio_set set; 348825ff184Sjmcneill const struct bitstr *bs; 349825ff184Sjmcneill 35032eeaba5Smbalmer memset(&set, 0, sizeof(set)); 35132eeaba5Smbalmer if (name != NULL) 35232eeaba5Smbalmer strlcpy(set.gp_name, name, sizeof(set.gp_name)); 35332eeaba5Smbalmer else 35432eeaba5Smbalmer set.gp_pin = pin; 35532eeaba5Smbalmer set.gp_flags = fl; 35632eeaba5Smbalmer 35732eeaba5Smbalmer if (alias != NULL) 35832eeaba5Smbalmer strlcpy(set.gp_name2, alias, sizeof(set.gp_name2)); 35932eeaba5Smbalmer 36032eeaba5Smbalmer if (ioctl(devfd, GPIOSET, &set) == -1) 36132eeaba5Smbalmer err(EXIT_FAILURE, "GPIOSET"); 362825ff184Sjmcneill 363825ff184Sjmcneill if (quiet) 364825ff184Sjmcneill return; 365825ff184Sjmcneill 36632eeaba5Smbalmer if (name != NULL) 36732eeaba5Smbalmer printf("pin %s: caps:", name); 36832eeaba5Smbalmer else 369825ff184Sjmcneill printf("pin %d: caps:", pin); 370825ff184Sjmcneill for (bs = pinflags; bs->string != NULL; bs++) 37132eeaba5Smbalmer if (set.gp_caps & bs->mask) 372825ff184Sjmcneill printf(" %s", bs->string); 373825ff184Sjmcneill printf(", flags:"); 374825ff184Sjmcneill for (bs = pinflags; bs->string != NULL; bs++) 37532eeaba5Smbalmer if (set.gp_flags & bs->mask) 376825ff184Sjmcneill printf(" %s", bs->string); 377825ff184Sjmcneill if (fl > 0) { 378825ff184Sjmcneill printf(" ->"); 379825ff184Sjmcneill for (bs = pinflags; bs->string != NULL; bs++) 380825ff184Sjmcneill if (fl & bs->mask) 381825ff184Sjmcneill printf(" %s", bs->string); 382825ff184Sjmcneill } 383825ff184Sjmcneill printf("\n"); 384825ff184Sjmcneill } 385825ff184Sjmcneill 38657ef84d0Smbalmer static void 38732eeaba5Smbalmer gpiounset(int pin, char *name) 38832eeaba5Smbalmer { 38932eeaba5Smbalmer struct gpio_set set; 39032eeaba5Smbalmer 39132eeaba5Smbalmer memset(&set, 0, sizeof(set)); 39232eeaba5Smbalmer if (name != NULL) 39332eeaba5Smbalmer strlcpy(set.gp_name, name, sizeof(set.gp_name)); 39432eeaba5Smbalmer else 39532eeaba5Smbalmer set.gp_pin = pin; 39632eeaba5Smbalmer 39732eeaba5Smbalmer if (ioctl(devfd, GPIOUNSET, &set) == -1) 39832eeaba5Smbalmer err(EXIT_FAILURE, "GPIOUNSET"); 39932eeaba5Smbalmer } 40032eeaba5Smbalmer 40157ef84d0Smbalmer static void 402*be149ed8Smbalmer devattach(char *dvname, int offset, uint32_t mask, uint32_t flags) 40332eeaba5Smbalmer { 40432eeaba5Smbalmer struct gpio_attach attach; 40532eeaba5Smbalmer 40632eeaba5Smbalmer memset(&attach, 0, sizeof(attach)); 40732eeaba5Smbalmer strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 40832eeaba5Smbalmer attach.ga_offset = offset; 40932eeaba5Smbalmer attach.ga_mask = mask; 410*be149ed8Smbalmer attach.ga_flags = flags; 41132eeaba5Smbalmer if (ioctl(devfd, GPIOATTACH, &attach) == -1) 41232eeaba5Smbalmer err(EXIT_FAILURE, "GPIOATTACH"); 41332eeaba5Smbalmer } 41432eeaba5Smbalmer 41557ef84d0Smbalmer static void 41632eeaba5Smbalmer devdetach(char *dvname) 41732eeaba5Smbalmer { 41832eeaba5Smbalmer struct gpio_attach attach; 41932eeaba5Smbalmer 42032eeaba5Smbalmer memset(&attach, 0, sizeof(attach)); 42132eeaba5Smbalmer strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 42232eeaba5Smbalmer if (ioctl(devfd, GPIODETACH, &attach) == -1) 42332eeaba5Smbalmer err(EXIT_FAILURE, "GPIODETACH"); 42432eeaba5Smbalmer } 42532eeaba5Smbalmer 42657ef84d0Smbalmer static void 427825ff184Sjmcneill usage(void) 428825ff184Sjmcneill { 42957ef84d0Smbalmer const char *progname; 43032eeaba5Smbalmer 43157ef84d0Smbalmer progname = getprogname(); 43232eeaba5Smbalmer fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | " 43357ef84d0Smbalmer "on | off | toggle]\n", progname); 434da668cdfSmbalmer fprintf(stderr, "usage: %s [-q] device pin pulse [frequency " 435da668cdfSmbalmer "[duty cycle]]\n", progname); 43632eeaba5Smbalmer fprintf(stderr, " %s [-q] device pin set [flags] [name]\n", 43757ef84d0Smbalmer progname); 43857ef84d0Smbalmer fprintf(stderr, " %s [-q] device pin unset\n", progname); 439*be149ed8Smbalmer fprintf(stderr, " %s [-q] device attach device offset mask " 440*be149ed8Smbalmer "[flags]\n", 44157ef84d0Smbalmer progname); 44257ef84d0Smbalmer fprintf(stderr, " %s [-q] device detach device\n", progname); 443825ff184Sjmcneill 4449b5c4f42Sxtraeme exit(EXIT_FAILURE); 445825ff184Sjmcneill } 446