1 /* $OpenBSD: gpioctl.c,v 1.17 2015/12/26 20:52:03 mmcc 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 38 char *dev; 39 int devfd = -1; 40 int quiet = 0; 41 42 void getinfo(void); 43 void pinread(int, char *); 44 void pinwrite(int, char *, int); 45 void pinset(int pin, char *name, int flags, char *alias); 46 void unset(int pin, char *name); 47 void devattach(char *, int, u_int32_t, u_int32_t); 48 void devdetach(char *); 49 50 __dead void usage(void); 51 52 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 { 0, NULL }, 67 }; 68 69 int 70 main(int argc, char *argv[]) 71 { 72 const struct bitstr *bs; 73 long lval; 74 u_int32_t ga_mask = 0, ga_flags = 0; 75 int pin, ch, ga_offset = -1, n, fl = 0, value = 0; 76 const char *errstr; 77 char *ep, *flags, *nam = NULL; 78 char devn[32]; 79 80 while ((ch = getopt(argc, argv, "q")) != -1) 81 switch (ch) { 82 case 'q': 83 quiet = 1; 84 break; 85 default: 86 usage(); 87 /* NOTREACHED */ 88 } 89 argc -= optind; 90 argv += optind; 91 92 if (argc < 1) 93 usage(); 94 dev = argv[0]; 95 96 if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) { 97 (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev); 98 dev = devn; 99 } 100 101 if ((devfd = open(dev, O_RDWR)) == -1) 102 err(1, "%s", dev); 103 104 if (argc == 1) { 105 getinfo(); 106 return 0; 107 } 108 109 if (!strcmp(argv[1], "attach")) { 110 char *driver, *offset, *mask; 111 112 if (argc != 5 && argc != 6) 113 usage(); 114 115 driver = argv[2]; 116 offset = argv[3]; 117 mask = argv[4]; 118 flags = argc == 6 ? argv[5] : NULL; 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 if (flags != NULL) { 132 lval = strtonum(flags, 0, UINT_MAX, &errstr); 133 if (errstr) 134 errx(1, "flags is %s: %s", errstr, flags); 135 ga_flags = lval; 136 } 137 devattach(driver, ga_offset, ga_mask, ga_flags); 138 return 0; 139 } else if (!strcmp(argv[1], "detach")) { 140 if (argc != 3) 141 usage(); 142 devdetach(argv[2]); 143 } else { 144 char *nm = NULL; 145 146 /* expecting a pin number or name */ 147 pin = strtonum(argv[1], 0, INT_MAX, &errstr); 148 if (errstr) 149 nm = argv[1]; /* try named pin */ 150 if (argc > 2) { 151 if (!strcmp(argv[2], "set")) { 152 for (n = 3; n < argc; n++) { 153 for (bs = pinflags; bs->string != NULL; 154 bs++) { 155 if (!strcmp(argv[n], 156 bs->string)) { 157 fl |= bs->mask; 158 break; 159 } 160 } 161 if (bs->string == NULL) 162 nam = argv[n]; 163 } 164 pinset(pin, nm, fl, nam); 165 } else if (!strcmp(argv[2], "unset")) { 166 unset(pin, nm); 167 } else { 168 value = strtonum(argv[2], INT_MIN, INT_MAX, 169 &errstr); 170 if (errstr) { 171 if (!strcmp(argv[2], "on")) 172 value = 1; 173 else if (!strcmp(argv[2], "off")) 174 value = 0; 175 else if (!strcmp(argv[2], "toggle")) 176 value = 2; 177 else 178 errx(1, "%s: invalid value", 179 argv[2]); 180 } 181 pinwrite(pin, nm, value); 182 } 183 } else 184 pinread(pin, nm); 185 } 186 187 return (0); 188 } 189 190 void 191 getinfo(void) 192 { 193 struct gpio_info info; 194 195 memset(&info, 0, sizeof(info)); 196 if (ioctl(devfd, GPIOINFO, &info) == -1) 197 err(1, "GPIOINFO"); 198 199 if (quiet) 200 return; 201 202 printf("%s: %d pins\n", dev, info.gpio_npins); 203 } 204 205 void 206 pinread(int pin, char *gp_name) 207 { 208 struct gpio_pin_op op; 209 210 memset(&op, 0, sizeof(op)); 211 if (gp_name != NULL) 212 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); 213 else 214 op.gp_pin = pin; 215 216 if (ioctl(devfd, GPIOPINREAD, &op) == -1) 217 err(1, "GPIOPINREAD"); 218 219 if (quiet) 220 return; 221 222 if (gp_name) 223 printf("pin %s: state %d\n", gp_name, op.gp_value); 224 else 225 printf("pin %d: state %d\n", pin, op.gp_value); 226 } 227 228 void 229 pinwrite(int pin, char *gp_name, int value) 230 { 231 struct gpio_pin_op op; 232 233 if (value < 0 || value > 2) 234 errx(1, "%d: invalid value", value); 235 236 memset(&op, 0, sizeof(op)); 237 if (gp_name != NULL) 238 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); 239 else 240 op.gp_pin = pin; 241 op.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH); 242 if (value < 2) { 243 if (ioctl(devfd, GPIOPINWRITE, &op) == -1) 244 err(1, "GPIOPINWRITE"); 245 } else { 246 if (ioctl(devfd, GPIOPINTOGGLE, &op) == -1) 247 err(1, "GPIOPINTOGGLE"); 248 } 249 250 if (quiet) 251 return; 252 253 if (gp_name) 254 printf("pin %s: state %d -> %d\n", gp_name, op.gp_value, 255 (value < 2 ? value : 1 - op.gp_value)); 256 else 257 printf("pin %d: state %d -> %d\n", pin, op.gp_value, 258 (value < 2 ? value : 1 - op.gp_value)); 259 } 260 261 void 262 pinset(int pin, char *name, int fl, char *alias) 263 { 264 struct gpio_pin_set set; 265 const struct bitstr *bs; 266 267 memset(&set, 0, sizeof(set)); 268 if (name != NULL) 269 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 270 else 271 set.gp_pin = pin; 272 set.gp_flags = fl; 273 274 if (alias != NULL) 275 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2)); 276 277 if (ioctl(devfd, GPIOPINSET, &set) == -1) 278 err(1, "GPIOPINSET"); 279 280 if (quiet) 281 return; 282 283 if (name != NULL) 284 printf("pin %s: caps:", name); 285 else 286 printf("pin %d: caps:", pin); 287 for (bs = pinflags; bs->string != NULL; bs++) 288 if (set.gp_caps & bs->mask) 289 printf(" %s", bs->string); 290 printf(", flags:"); 291 for (bs = pinflags; bs->string != NULL; bs++) 292 if (set.gp_flags & bs->mask) 293 printf(" %s", bs->string); 294 if (fl > 0) { 295 printf(" ->"); 296 for (bs = pinflags; bs->string != NULL; bs++) 297 if (fl & bs->mask) 298 printf(" %s", bs->string); 299 } 300 printf("\n"); 301 } 302 303 void 304 unset(int pin, char *name) 305 { 306 struct gpio_pin_set set; 307 308 memset(&set, 0, sizeof(set)); 309 if (name != NULL) 310 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 311 else 312 set.gp_pin = pin; 313 314 if (ioctl(devfd, GPIOPINUNSET, &set) == -1) 315 err(1, "GPIOPINUNSET"); 316 } 317 318 void 319 devattach(char *dvname, int offset, u_int32_t mask, u_int32_t flags) 320 { 321 struct gpio_attach attach; 322 323 memset(&attach, 0, sizeof(attach)); 324 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 325 attach.ga_offset = offset; 326 attach.ga_mask = mask; 327 attach.ga_flags = flags; 328 if (ioctl(devfd, GPIOATTACH, &attach) == -1) 329 err(1, "GPIOATTACH"); 330 } 331 332 void 333 devdetach(char *dvname) 334 { 335 struct gpio_attach attach; 336 337 memset(&attach, 0, sizeof(attach)); 338 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 339 if (ioctl(devfd, GPIODETACH, &attach) == -1) 340 err(1, "GPIODETACH"); 341 } 342 void 343 usage(void) 344 { 345 extern char *__progname; 346 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", __progname); 354 fprintf(stderr, " %s [-q] device detach device\n", __progname); 355 356 exit(1); 357 } 358