1 /* $OpenBSD: gpioctl.c,v 1.13 2008/11/30 10:58:44 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 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 pinctl(int, char *, char *[], int); 46 void pinset(int pin, char *name, int flags, char *alias); 47 void unset(int pin, char *name); 48 void devattach(char *, int, u_int32_t); 49 void devdetach(char *); 50 51 __dead void usage(void); 52 53 const 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 70 int 71 main(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 if (!strcmp(argv[2], "on")) 166 value = 1; 167 else if (!strcmp(argv[2], "off")) 168 value = 0; 169 else if (!strcmp(argv[2], "toggle")) 170 value = 2; 171 else 172 errx(1, "%s: invalid value", 173 argv[2]); 174 } 175 pinwrite(pin, nm, value); 176 } 177 } else 178 pinread(pin, nm); 179 } 180 181 return (0); 182 } 183 184 void 185 getinfo(void) 186 { 187 struct gpio_info info; 188 189 bzero(&info, sizeof(info)); 190 if (ioctl(devfd, GPIOINFO, &info) == -1) 191 err(1, "GPIOINFO"); 192 193 if (quiet) 194 return; 195 196 printf("%s: %d pins\n", dev, info.gpio_npins); 197 } 198 199 void 200 pinread(int pin, char *gp_name) 201 { 202 struct gpio_pin_op op; 203 204 bzero(&op, sizeof(op)); 205 if (gp_name != NULL) 206 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); 207 else 208 op.gp_pin = pin; 209 210 if (ioctl(devfd, GPIOPINREAD, &op) == -1) 211 err(1, "GPIOPINREAD"); 212 213 if (quiet) 214 return; 215 216 if (gp_name) 217 printf("pin %s: state %d\n", gp_name, op.gp_value); 218 else 219 printf("pin %d: state %d\n", pin, op.gp_value); 220 } 221 222 void 223 pinwrite(int pin, char *gp_name, int value) 224 { 225 struct gpio_pin_op op; 226 227 if (value < 0 || value > 2) 228 errx(1, "%d: invalid value", value); 229 230 bzero(&op, sizeof(op)); 231 if (gp_name != NULL) 232 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); 233 else 234 op.gp_pin = pin; 235 op.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH); 236 if (value < 2) { 237 if (ioctl(devfd, GPIOPINWRITE, &op) == -1) 238 err(1, "GPIOPINWRITE"); 239 } else { 240 if (ioctl(devfd, GPIOPINTOGGLE, &op) == -1) 241 err(1, "GPIOPINTOGGLE"); 242 } 243 244 if (quiet) 245 return; 246 247 if (gp_name) 248 printf("pin %s: state %d -> %d\n", gp_name, op.gp_value, 249 (value < 2 ? value : 1 - op.gp_value)); 250 else 251 printf("pin %d: state %d -> %d\n", pin, op.gp_value, 252 (value < 2 ? value : 1 - op.gp_value)); 253 } 254 255 void 256 pinset(int pin, char *name, int fl, char *alias) 257 { 258 struct gpio_pin_set set; 259 const struct bitstr *bs; 260 261 bzero(&set, sizeof(set)); 262 if (name != NULL) 263 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 264 else 265 set.gp_pin = pin; 266 set.gp_flags = fl; 267 268 if (alias != NULL) 269 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2)); 270 271 if (ioctl(devfd, GPIOPINSET, &set) == -1) 272 err(1, "GPIOPINSET"); 273 274 if (quiet) 275 return; 276 277 if (name != NULL) 278 printf("pin %s: caps:", name); 279 else 280 printf("pin %d: caps:", pin); 281 for (bs = pinflags; bs->string != NULL; bs++) 282 if (set.gp_caps & bs->mask) 283 printf(" %s", bs->string); 284 printf(", flags:"); 285 for (bs = pinflags; bs->string != NULL; bs++) 286 if (set.gp_flags & bs->mask) 287 printf(" %s", bs->string); 288 if (fl > 0) { 289 printf(" ->"); 290 for (bs = pinflags; bs->string != NULL; bs++) 291 if (fl & bs->mask) 292 printf(" %s", bs->string); 293 } 294 printf("\n"); 295 } 296 297 void 298 unset(int pin, char *name) 299 { 300 struct gpio_pin_set set; 301 302 bzero(&set, sizeof(set)); 303 if (name != NULL) 304 strlcpy(set.gp_name, name, sizeof(set.gp_name)); 305 else 306 set.gp_pin = pin; 307 308 if (ioctl(devfd, GPIOPINUNSET, &set) == -1) 309 err(1, "GPIOPINUNSET"); 310 } 311 312 void 313 devattach(char *dvname, int offset, u_int32_t mask) 314 { 315 struct gpio_attach attach; 316 317 bzero(&attach, sizeof(attach)); 318 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 319 attach.ga_offset = offset; 320 attach.ga_mask = mask; 321 if (ioctl(devfd, GPIOATTACH, &attach) == -1) 322 err(1, "GPIOATTACH"); 323 } 324 325 void 326 devdetach(char *dvname) 327 { 328 struct gpio_attach attach; 329 330 bzero(&attach, sizeof(attach)); 331 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname)); 332 if (ioctl(devfd, GPIODETACH, &attach) == -1) 333 err(1, "GPIODETACH"); 334 } 335 void 336 usage(void) 337 { 338 extern char *__progname; 339 340 fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | " 341 "on | off | toggle]\n", __progname); 342 fprintf(stderr, " %s [-q] device pin set [flags] [name]\n", 343 __progname); 344 fprintf(stderr, " %s [-q] device pin unset\n", __progname); 345 fprintf(stderr, " %s [-q] device attach device offset mask\n", 346 __progname); 347 fprintf(stderr, " %s [-q] device detach device\n", __progname); 348 349 exit(1); 350 } 351