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