1/* $NetBSD: gpioctl.c,v 1.18 2011/11/12 16:34:03 mbalmer Exp $ */ 2 3/* 4 * Copyright (c) 2008, 2010, 2011 Marc Balmer <mbalmer@NetBSD.org> 5 * Copyright (c) 2004 Alexander Yurchenko <grange@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 39static char *dev; 40static int devfd = -1; 41static int quiet = 0; 42 43static void getinfo(void); 44static void gpioread(int, char *); 45static void gpiowrite(int, char *, int); 46static void gpioset(int pin, char *name, int flags, char *alias); 47static void gpiounset(int pin, char *name); 48static void devattach(char *, int, uint32_t, uint32_t); 49__dead static void usage(void); 50 51extern long long strtonum(const char *numstr, long long minval, 52 long long maxval, const char **errstrp); 53 54static const struct bitstr { 55 unsigned int mask; 56 const char *string; 57} pinflags[] = { 58 { GPIO_PIN_INPUT, "in" }, 59 { GPIO_PIN_OUTPUT, "out" }, 60 { GPIO_PIN_INOUT, "inout" }, 61 { GPIO_PIN_OPENDRAIN, "od" }, 62 { GPIO_PIN_PUSHPULL, "pp" }, 63 { GPIO_PIN_TRISTATE, "tri" }, 64 { GPIO_PIN_PULLUP, "pu" }, 65 { GPIO_PIN_PULLDOWN, "pd" }, 66 { GPIO_PIN_INVIN, "iin" }, 67 { GPIO_PIN_INVOUT, "iout" }, 68 { GPIO_PIN_PULSATE, "pulsate" }, 69 { 0, NULL }, 70}; 71 72int 73main(int argc, char *argv[]) 74{ 75 const struct bitstr *bs; 76 int pin, ch, n, fl = 0, value = 0; 77 const char *errstr; 78 char *ep; 79 int ga_offset = -1; 80 uint32_t ga_mask = 0; 81 uint32_t ga_flags = 0; 82 long lval; 83 char *nam = NULL; 84 char *flags; 85 char devn[32]; 86 87 while ((ch = getopt(argc, argv, "q")) != -1) 88 switch (ch) { 89 case 'q': 90 quiet = 1; 91 break; 92 default: 93 usage(); 94 /* NOTREACHED */ 95 } 96 argc -= optind; 97 argv += optind; 98 99 if (argc < 1) 100 usage(); 101 dev = argv[0]; 102 103 if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) { 104 (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev); 105 dev = devn; 106 } 107 108 if ((devfd = open(dev, O_RDWR)) == -1) 109 err(EXIT_FAILURE, "%s", dev); 110 111 if (argc == 1) { 112 getinfo(); 113 return EXIT_SUCCESS; 114 } 115 116 if (!strcmp(argv[1], "attach")) { 117 char *driver, *offset, *mask; 118 119 if (argc != 5 && argc != 6) 120 usage(); 121 122 driver = argv[2]; 123 offset = argv[3]; 124 mask = argv[4]; 125 flags = argc == 6 ? argv[5] : NULL; 126 127 ga_offset = strtonum(offset, 0, INT_MAX, &errstr); 128 if (errstr) 129 errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset); 130 lval = strtol(mask, &ep, 0); 131 if (*mask == '\0' || *ep != '\0') 132 errx(EXIT_FAILURE, "invalid mask (not a number)"); 133 if ((errno == ERANGE && (lval == LONG_MAX 134 || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX) 135 errx(EXIT_FAILURE, "mask out of range"); 136 ga_mask = lval; 137 if (flags != NULL) { 138 lval = strtol(flags, &ep, 0); 139 if (*flags == '\0' || *ep != '\0') 140 errx(EXIT_FAILURE, 141 "invalid flag locator (not a number)"); 142 if ((errno == ERANGE && (lval == LONG_MAX 143 || lval == LONG_MIN)) 144 || (unsigned long)lval > UINT_MAX) 145 errx(EXIT_FAILURE, "flag locator out of range"); 146 147 ga_flags = lval; 148 } 149 devattach(driver, ga_offset, ga_mask, ga_flags); 150 return EXIT_SUCCESS; 151 } else { 152 char *nm = NULL; 153 154 /* expecting a pin number or name */ 155 pin = strtonum(argv[1], 0, INT_MAX, &errstr); 156 if (errstr) 157 nm = argv[1]; /* try named pin */ 158 if (argc > 2) { 159 if (!strcmp(argv[2], "set")) { 160 for (n = 3; n < argc; n++) { 161 for (bs = pinflags; bs->string != NULL; 162 bs++) { 163 if (!strcmp(argv[n], 164 bs->string)) { 165 fl |= bs->mask; 166 break; 167 } 168 } 169 if (bs->string == NULL) 170 nam = argv[n]; 171 } 172 gpioset(pin, nm, fl, nam); 173 } else if (!strcmp(argv[2], "unset")) 174 gpiounset(pin, nm); 175 else { 176 value = strtonum(argv[2], INT_MIN, INT_MAX, 177 &errstr); 178 if (errstr) { 179 if (!strcmp(argv[2], "on")) 180 value = GPIO_PIN_HIGH; 181 else if (!strcmp(argv[2], "off")) 182 value = GPIO_PIN_LOW; 183 else if (!strcmp(argv[2], "toggle")) 184 value = 2; 185 else 186 errx(EXIT_FAILURE, 187 "%s: invalid value", 188 argv[2]); 189 } 190 gpiowrite(pin, nm, value); 191 } 192 } else 193 gpioread(pin, nm); 194 } 195 196 return EXIT_SUCCESS; 197} 198 199static void 200getinfo(void) 201{ 202 struct gpio_info info; 203 204 if (ioctl(devfd, GPIOINFO, &info) == -1) 205 err(EXIT_FAILURE, "GPIOINFO"); 206 207 if (quiet) 208 return; 209 210 printf("%s: %d pins\n", dev, info.gpio_npins); 211} 212 213static void 214gpioread(int pin, char *gp_name) 215{ 216 struct gpio_req req; 217 218 memset(&req, 0, sizeof(req)); 219 if (gp_name != NULL) 220 strlcpy(req.gp_name, gp_name, sizeof(req.gp_name)); 221 else 222 req.gp_pin = pin; 223 224 if (ioctl(devfd, GPIOREAD, &req) == -1) 225 err(EXIT_FAILURE, "GPIOREAD"); 226 227 if (quiet) 228 return; 229 230 if (gp_name) 231 printf("pin %s: state %d\n", gp_name, req.gp_value); 232 else 233 printf("pin %d: state %d\n", pin, req.gp_value); 234} 235 236static void 237gpiowrite(int pin, char *gp_name, int value) 238{ 239 struct gpio_req req; 240 241 if (value < 0 || value > 2) 242 errx(EXIT_FAILURE, "%d: invalid value", value); 243 244 memset(&req, 0, sizeof(req)); 245 if (gp_name != NULL) 246 strlcpy(req.gp_name, gp_name, sizeof(req.gp_name)); 247 else 248 req.gp_pin = pin; 249 250 if (value == GPIO_PIN_HIGH || value == GPIO_PIN_LOW) { 251 req.gp_value = value; 252 if (ioctl(devfd, GPIOWRITE, &req) == -1) 253 err(EXIT_FAILURE, "GPIOWRITE"); 254 } else { 255 if (ioctl(devfd, GPIOTOGGLE, &req) == -1) 256 err(EXIT_FAILURE, "GPIOTOGGLE"); 257 } 258 259 if (quiet) 260 return; 261 262 if (gp_name) 263 printf("pin %s: state %d -> %d\n", gp_name, req.gp_value, 264 (value < 2 ? value : 1 - req.gp_value)); 265 else 266 printf("pin %d: state %d -> %d\n", pin, req.gp_value, 267 (value < 2 ? value : 1 - req.gp_value)); 268} 269 270static void 271gpioset(int pin, char *name, int fl, char *alias) 272{ 273 struct gpio_set set; 274 const struct bitstr *bs; 275 276 memset(&set, 0, sizeof(set)); 277 if (name != NULL) 278 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 279 else 280 set.gp_pin = pin; 281 set.gp_flags = fl; 282 283 if (alias != NULL) 284 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2)); 285 286 if (ioctl(devfd, GPIOSET, &set) == -1) 287 err(EXIT_FAILURE, "GPIOSET"); 288 289 if (quiet) 290 return; 291 292 if (name != NULL) 293 printf("pin %s: caps:", name); 294 else 295 printf("pin %d: caps:", pin); 296 for (bs = pinflags; bs->string != NULL; bs++) 297 if (set.gp_caps & bs->mask) 298 printf(" %s", bs->string); 299 printf(", flags:"); 300 for (bs = pinflags; bs->string != NULL; bs++) 301 if (set.gp_flags & bs->mask) 302 printf(" %s", bs->string); 303 if (fl > 0) { 304 printf(" ->"); 305 for (bs = pinflags; bs->string != NULL; bs++) 306 if (fl & bs->mask) 307 printf(" %s", bs->string); 308 } 309 printf("\n"); 310} 311 312static void 313gpiounset(int pin, char *name) 314{ 315 struct gpio_set set; 316 317 memset(&set, 0, sizeof(set)); 318 if (name != NULL) 319 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 320 else 321 set.gp_pin = pin; 322 323 if (ioctl(devfd, GPIOUNSET, &set) == -1) 324 err(EXIT_FAILURE, "GPIOUNSET"); 325} 326 327static void 328devattach(char *dvname, int offset, uint32_t mask, uint32_t flags) 329{ 330 struct gpio_attach attach; 331 332 memset(&attach, 0, sizeof(attach)); 333 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 334 attach.ga_offset = offset; 335 attach.ga_mask = mask; 336 attach.ga_flags = flags; 337 if (ioctl(devfd, GPIOATTACH, &attach) == -1) 338 err(EXIT_FAILURE, "GPIOATTACH"); 339} 340 341static void 342usage(void) 343{ 344 const char *progname; 345 346 progname = getprogname(); 347 fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | " 348 "on | off | toggle]\n", progname); 349 fprintf(stderr, " %s [-q] device pin set [flags] [name]\n", 350 progname); 351 fprintf(stderr, " %s [-q] device pin unset\n", progname); 352 fprintf(stderr, " %s [-q] device attach device offset mask " 353 "[flag]\n", 354 progname); 355 356 exit(EXIT_FAILURE); 357} 358