gpioctl.c revision 1.14
1/* $OpenBSD: gpioctl.c,v 1.14 2008/12/03 20:12:44 stevesk 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 pinset(int pin, char *name, int flags, char *alias); 46void unset(int pin, char *name); 47void devattach(char *, int, u_int32_t); 48void devdetach(char *); 49 50__dead void usage(void); 51 52const 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 69int 70main(int argc, char *argv[]) 71{ 72 const struct bitstr *bs; 73 long lval; 74 u_int32_t ga_mask = 0; 75 int pin, ch, ga_offset = -1, n, fl = 0, value = 0; 76 const char *errstr; 77 char *ep, *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) 113 usage(); 114 115 driver = argv[2]; 116 offset = argv[3]; 117 mask = argv[4]; 118 119 ga_offset = strtonum(offset, 0, INT_MAX, &errstr); 120 if (errstr) 121 errx(1, "offset is %s: %s", errstr, offset); 122 123 lval = strtol(mask, &ep, 0); 124 if (*mask == '\0' || *ep != '\0') 125 errx(1, "invalid mask (not a number)"); 126 if ((errno == ERANGE && (lval == LONG_MAX 127 || lval == LONG_MIN)) || lval > UINT_MAX) 128 errx(1, "mask out of range"); 129 ga_mask = lval; 130 devattach(driver, ga_offset, ga_mask); 131 return 0; 132 } else if (!strcmp(argv[1], "detach")) { 133 if (argc != 3) 134 usage(); 135 devdetach(argv[2]); 136 } else { 137 char *nm = NULL; 138 139 /* expecting a pin number or name */ 140 pin = strtonum(argv[1], 0, INT_MAX, &errstr); 141 if (errstr) 142 nm = argv[1]; /* try named pin */ 143 if (argc > 2) { 144 if (!strcmp(argv[2], "set")) { 145 for (n = 3; n < argc; n++) { 146 for (bs = pinflags; bs->string != NULL; 147 bs++) { 148 if (!strcmp(argv[n], 149 bs->string)) { 150 fl |= bs->mask; 151 break; 152 } 153 } 154 if (bs->string == NULL) 155 nam = argv[n]; 156 } 157 pinset(pin, nm, fl, nam); 158 } else if (!strcmp(argv[2], "unset")) { 159 unset(pin, nm); 160 } else { 161 value = strtonum(argv[2], INT_MIN, INT_MAX, 162 &errstr); 163 if (errstr) { 164 if (!strcmp(argv[2], "on")) 165 value = 1; 166 else if (!strcmp(argv[2], "off")) 167 value = 0; 168 else if (!strcmp(argv[2], "toggle")) 169 value = 2; 170 else 171 errx(1, "%s: invalid value", 172 argv[2]); 173 } 174 pinwrite(pin, nm, value); 175 } 176 } else 177 pinread(pin, nm); 178 } 179 180 return (0); 181} 182 183void 184getinfo(void) 185{ 186 struct gpio_info info; 187 188 bzero(&info, sizeof(info)); 189 if (ioctl(devfd, GPIOINFO, &info) == -1) 190 err(1, "GPIOINFO"); 191 192 if (quiet) 193 return; 194 195 printf("%s: %d pins\n", dev, info.gpio_npins); 196} 197 198void 199pinread(int pin, char *gp_name) 200{ 201 struct gpio_pin_op op; 202 203 bzero(&op, sizeof(op)); 204 if (gp_name != NULL) 205 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); 206 else 207 op.gp_pin = pin; 208 209 if (ioctl(devfd, GPIOPINREAD, &op) == -1) 210 err(1, "GPIOPINREAD"); 211 212 if (quiet) 213 return; 214 215 if (gp_name) 216 printf("pin %s: state %d\n", gp_name, op.gp_value); 217 else 218 printf("pin %d: state %d\n", pin, op.gp_value); 219} 220 221void 222pinwrite(int pin, char *gp_name, int value) 223{ 224 struct gpio_pin_op op; 225 226 if (value < 0 || value > 2) 227 errx(1, "%d: invalid value", value); 228 229 bzero(&op, sizeof(op)); 230 if (gp_name != NULL) 231 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); 232 else 233 op.gp_pin = pin; 234 op.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH); 235 if (value < 2) { 236 if (ioctl(devfd, GPIOPINWRITE, &op) == -1) 237 err(1, "GPIOPINWRITE"); 238 } else { 239 if (ioctl(devfd, GPIOPINTOGGLE, &op) == -1) 240 err(1, "GPIOPINTOGGLE"); 241 } 242 243 if (quiet) 244 return; 245 246 if (gp_name) 247 printf("pin %s: state %d -> %d\n", gp_name, op.gp_value, 248 (value < 2 ? value : 1 - op.gp_value)); 249 else 250 printf("pin %d: state %d -> %d\n", pin, op.gp_value, 251 (value < 2 ? value : 1 - op.gp_value)); 252} 253 254void 255pinset(int pin, char *name, int fl, char *alias) 256{ 257 struct gpio_pin_set set; 258 const struct bitstr *bs; 259 260 bzero(&set, sizeof(set)); 261 if (name != NULL) 262 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 263 else 264 set.gp_pin = pin; 265 set.gp_flags = fl; 266 267 if (alias != NULL) 268 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2)); 269 270 if (ioctl(devfd, GPIOPINSET, &set) == -1) 271 err(1, "GPIOPINSET"); 272 273 if (quiet) 274 return; 275 276 if (name != NULL) 277 printf("pin %s: caps:", name); 278 else 279 printf("pin %d: caps:", pin); 280 for (bs = pinflags; bs->string != NULL; bs++) 281 if (set.gp_caps & bs->mask) 282 printf(" %s", bs->string); 283 printf(", flags:"); 284 for (bs = pinflags; bs->string != NULL; bs++) 285 if (set.gp_flags & bs->mask) 286 printf(" %s", bs->string); 287 if (fl > 0) { 288 printf(" ->"); 289 for (bs = pinflags; bs->string != NULL; bs++) 290 if (fl & bs->mask) 291 printf(" %s", bs->string); 292 } 293 printf("\n"); 294} 295 296void 297unset(int pin, char *name) 298{ 299 struct gpio_pin_set set; 300 301 bzero(&set, sizeof(set)); 302 if (name != NULL) 303 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 304 else 305 set.gp_pin = pin; 306 307 if (ioctl(devfd, GPIOPINUNSET, &set) == -1) 308 err(1, "GPIOPINUNSET"); 309} 310 311void 312devattach(char *dvname, int offset, u_int32_t mask) 313{ 314 struct gpio_attach attach; 315 316 bzero(&attach, sizeof(attach)); 317 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 318 attach.ga_offset = offset; 319 attach.ga_mask = mask; 320 if (ioctl(devfd, GPIOATTACH, &attach) == -1) 321 err(1, "GPIOATTACH"); 322} 323 324void 325devdetach(char *dvname) 326{ 327 struct gpio_attach attach; 328 329 bzero(&attach, sizeof(attach)); 330 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 331 if (ioctl(devfd, GPIODETACH, &attach) == -1) 332 err(1, "GPIODETACH"); 333} 334void 335usage(void) 336{ 337 extern char *__progname; 338 339 fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | " 340 "on | off | toggle]\n", __progname); 341 fprintf(stderr, " %s [-q] device pin set [flags] [name]\n", 342 __progname); 343 fprintf(stderr, " %s [-q] device pin unset\n", __progname); 344 fprintf(stderr, " %s [-q] device attach device offset mask\n", 345 __progname); 346 fprintf(stderr, " %s [-q] device detach device\n", __progname); 347 348 exit(1); 349} 350