gpioctl.c revision 1.11
1/* $OpenBSD: gpioctl.c,v 1.11 2008/11/26 15:02:43 mbalmer Exp $ */ 2/* 3 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org> 4 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19/* 20 * Program to control GPIO devices. 21 */ 22 23#include <sys/types.h> 24#include <sys/gpio.h> 25#include <sys/ioctl.h> 26#include <sys/limits.h> 27 28#include <err.h> 29#include <errno.h> 30#include <fcntl.h> 31#include <paths.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <unistd.h> 36 37 38char *dev; 39int devfd = -1; 40int quiet = 0; 41 42void getinfo(void); 43void pinread(int, char *); 44void pinwrite(int, char *, int); 45void pinctl(int, char *, char *[], int); 46void pinset(int pin, char *name, int flags, char *alias); 47void unset(int pin, char *name); 48void devattach(char *, int, u_int32_t); 49void devdetach(char *); 50 51__dead void usage(void); 52 53const struct bitstr { 54 unsigned int mask; 55 const char *string; 56} pinflags[] = { 57 { GPIO_PIN_INPUT, "in" }, 58 { GPIO_PIN_OUTPUT, "out" }, 59 { GPIO_PIN_INOUT, "inout" }, 60 { GPIO_PIN_OPENDRAIN, "od" }, 61 { GPIO_PIN_PUSHPULL, "pp" }, 62 { GPIO_PIN_TRISTATE, "tri" }, 63 { GPIO_PIN_PULLUP, "pu" }, 64 { GPIO_PIN_PULLDOWN, "pd" }, 65 { GPIO_PIN_INVIN, "iin" }, 66 { GPIO_PIN_INVOUT, "iout" }, 67 { 0, NULL }, 68}; 69 70int 71main(int argc, char *argv[]) 72{ 73 const struct bitstr *bs; 74 long lval; 75 u_int32_t ga_mask = 0; 76 int pin, ch, ga_offset = -1, n, fl = 0, value = 0; 77 const char *errstr; 78 char *ep, *nam = NULL; 79 char devn[32]; 80 81 while ((ch = getopt(argc, argv, "q")) != -1) 82 switch (ch) { 83 case 'q': 84 quiet = 1; 85 break; 86 default: 87 usage(); 88 /* NOTREACHED */ 89 } 90 argc -= optind; 91 argv += optind; 92 93 if (argc < 1) 94 usage(); 95 dev = argv[0]; 96 97 if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) { 98 (void)snprintf(devn, sizeof(devn), "%s/%s", _PATH_DEV, dev); 99 dev = devn; 100 } 101 102 if ((devfd = open(dev, O_RDWR)) == -1) 103 err(1, "%s", dev); 104 105 if (argc == 1) { 106 getinfo(); 107 return 0; 108 } 109 110 if (!strcmp(argv[1], "attach")) { 111 char *driver, *offset, *mask; 112 113 if (argc != 5) 114 usage(); 115 116 driver = argv[2]; 117 offset = argv[3]; 118 mask = argv[4]; 119 120 ga_offset = strtonum(offset, 0, INT_MAX, &errstr); 121 if (errstr) 122 errx(1, "offset is %s: %s", errstr, offset); 123 124 lval = strtol(mask, &ep, 0); 125 if (*mask == '\0' || *ep != '\0') 126 errx(1, "invalid mask (not a number)"); 127 if ((errno == ERANGE && (lval == LONG_MAX 128 || lval == LONG_MIN)) || lval > UINT_MAX) 129 errx(1, "mask out of range"); 130 ga_mask = lval; 131 devattach(driver, ga_offset, ga_mask); 132 return 0; 133 } else if (!strcmp(argv[1], "detach")) { 134 if (argc != 3) 135 usage(); 136 devdetach(argv[2]); 137 } else { 138 char *nm = NULL; 139 140 /* expecting a pin number or name */ 141 pin = strtonum(argv[1], 0, INT_MAX, &errstr); 142 if (errstr) 143 nm = argv[1]; /* try named pin */ 144 if (argc > 2) { 145 if (!strcmp(argv[2], "set")) { 146 for (n = 3; n < argc; n++) { 147 for (bs = pinflags; bs->string != NULL; 148 bs++) { 149 if (!strcmp(argv[n], 150 bs->string)) { 151 fl |= bs->mask; 152 break; 153 } 154 } 155 if (bs->string == NULL) 156 nam = argv[n]; 157 } 158 pinset(pin, nm, fl, nam); 159 } else if (!strcmp(argv[2], "unset")) { 160 unset(pin, nm); 161 } else { 162 value = strtonum(argv[2], INT_MIN, INT_MAX, 163 &errstr); 164 if (errstr) 165 errx(1, "%s: invalid value", argv[2]); 166 pinwrite(pin, nm, value); 167 } 168 } else 169 pinread(pin, nm); 170 } 171 172 return (0); 173} 174 175void 176getinfo(void) 177{ 178 struct gpio_info info; 179 180 bzero(&info, sizeof(info)); 181 if (ioctl(devfd, GPIOINFO, &info) == -1) 182 err(1, "GPIOINFO"); 183 184 if (quiet) 185 return; 186 187 printf("%s: %d pins\n", dev, info.gpio_npins); 188} 189 190void 191pinread(int pin, char *gp_name) 192{ 193 struct gpio_pin_op op; 194 195 bzero(&op, sizeof(op)); 196 if (gp_name != NULL) 197 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); 198 else 199 op.gp_pin = pin; 200 201 if (ioctl(devfd, GPIOPINREAD, &op) == -1) 202 err(1, "GPIOPINREAD"); 203 204 if (quiet) 205 return; 206 207 if (gp_name) 208 printf("pin %s: state %d\n", gp_name, op.gp_value); 209 else 210 printf("pin %d: state %d\n", pin, op.gp_value); 211} 212 213void 214pinwrite(int pin, char *gp_name, int value) 215{ 216 struct gpio_pin_op op; 217 218 if (value < 0 || value > 2) 219 errx(1, "%d: invalid value", value); 220 221 bzero(&op, sizeof(op)); 222 if (gp_name != NULL) 223 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); 224 else 225 op.gp_pin = pin; 226 op.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH); 227 if (value < 2) { 228 if (ioctl(devfd, GPIOPINWRITE, &op) == -1) 229 err(1, "GPIOPINWR"); 230 } else { 231 if (ioctl(devfd, GPIOPINTOGGLE, &op) == -1) 232 err(1, "GPIOPINTOGGLE"); 233 } 234 235 if (quiet) 236 return; 237 238 if (gp_name) 239 printf("pin %s: state %d -> %d\n", gp_name, op.gp_value, 240 (value < 2 ? value : 1 - op.gp_value)); 241 else 242 printf("pin %d: state %d -> %d\n", pin, op.gp_value, 243 (value < 2 ? value : 1 - op.gp_value)); 244} 245 246void 247pinset(int pin, char *name, int fl, char *alias) 248{ 249 struct gpio_pin_set set; 250 const struct bitstr *bs; 251 252 bzero(&set, sizeof(set)); 253 if (name != NULL) 254 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 255 else 256 set.gp_pin = pin; 257 set.gp_flags = fl; 258 259 if (alias != NULL) 260 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2)); 261 262 if (ioctl(devfd, GPIOPINSET, &set) == -1) 263 err(1, "GPIOPINSET"); 264 265 if (quiet) 266 return; 267 268 if (name != NULL) 269 printf("pin %s: caps:", name); 270 else 271 printf("pin %d: caps:", pin); 272 for (bs = pinflags; bs->string != NULL; bs++) 273 if (set.gp_caps & bs->mask) 274 printf(" %s", bs->string); 275 printf(", flags:"); 276 for (bs = pinflags; bs->string != NULL; bs++) 277 if (set.gp_flags & bs->mask) 278 printf(" %s", bs->string); 279 if (fl > 0) { 280 printf(" ->"); 281 for (bs = pinflags; bs->string != NULL; bs++) 282 if (fl & bs->mask) 283 printf(" %s", bs->string); 284 } 285 printf("\n"); 286} 287 288void 289unset(int pin, char *name) 290{ 291 struct gpio_pin_set set; 292 293 bzero(&set, sizeof(set)); 294 if (name != NULL) 295 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 296 else 297 set.gp_pin = pin; 298 299 if (ioctl(devfd, GPIOPINUNSET, &set) == -1) 300 err(1, "GPIOPINUNSET"); 301} 302 303void 304devattach(char *dvname, int offset, u_int32_t mask) 305{ 306 struct gpio_attach attach; 307 308 bzero(&attach, sizeof(attach)); 309 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 310 attach.ga_offset = offset; 311 attach.ga_mask = mask; 312 if (ioctl(devfd, GPIOATTACH, &attach) == -1) 313 err(1, "GPIOATTACH"); 314} 315 316void 317devdetach(char *dvname) 318{ 319 struct gpio_attach attach; 320 321 bzero(&attach, sizeof(attach)); 322 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 323 if (ioctl(devfd, GPIODETACH, &attach) == -1) 324 err(1, "GPIODETACH"); 325} 326void 327usage(void) 328{ 329 extern char *__progname; 330 331 fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2]\n", 332 __progname); 333 fprintf(stderr, " %s [-q] device pin set [flags] [name]\n", 334 __progname); 335 fprintf(stderr, " %s [-q] device pin unset\n", __progname); 336 fprintf(stderr, " %s [-q] device attach device offset mask\n", 337 __progname); 338 fprintf(stderr, " %s [-q] device detach device\n", __progname); 339 340 exit(1); 341} 342