1 /*- 2 * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <fcntl.h> 32 #include <getopt.h> 33 #include <paths.h> 34 #include <stdio.h> 35 #include <stdarg.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 40 #include <sys/gpio.h> 41 42 struct flag_desc { 43 const char *name; 44 uint32_t flag; 45 }; 46 47 static struct flag_desc gpio_flags[] = { 48 { "IN", GPIO_PIN_INPUT }, 49 { "OUT", GPIO_PIN_OUTPUT }, 50 { "OD", GPIO_PIN_OPENDRAIN }, 51 { "PP", GPIO_PIN_PUSHPULL }, 52 { "TS", GPIO_PIN_TRISTATE }, 53 { "PU", GPIO_PIN_PULLUP }, 54 { "PD", GPIO_PIN_PULLDOWN }, 55 { "II", GPIO_PIN_INVIN }, 56 { "IO", GPIO_PIN_INVOUT }, 57 { "PULSE", GPIO_PIN_PULSATE }, 58 { NULL, 0 }, 59 }; 60 61 int str2cap(const char *str); 62 63 static void 64 usage(void) 65 { 66 fprintf(stderr, "Usage:\n"); 67 fprintf(stderr, "\tgpioctl [-f ctldev] -l [-v]\n"); 68 fprintf(stderr, "\tgpioctl [-f ctldev] -t pin\n"); 69 fprintf(stderr, "\tgpioctl [-f ctldev] -c pin flag ...\n"); 70 fprintf(stderr, "\tgpioctl [-f ctldev] pin [0|1]\n"); 71 exit(1); 72 } 73 74 static const char * 75 cap2str(uint32_t cap) 76 { 77 struct flag_desc * pdesc = gpio_flags; 78 while (pdesc->name) { 79 if (pdesc->flag == cap) 80 return pdesc->name; 81 pdesc++; 82 } 83 84 return "UNKNOWN"; 85 } 86 87 int 88 str2cap(const char *str) 89 { 90 struct flag_desc * pdesc = gpio_flags; 91 while (pdesc->name) { 92 if (strcasecmp(str, pdesc->name) == 0) 93 return pdesc->flag; 94 pdesc++; 95 } 96 97 return (-1); 98 } 99 100 /* 101 * Our handmade function for converting string to number 102 */ 103 static int 104 str2int(const char *s, int *ok) 105 { 106 char *endptr; 107 int res = strtod(s, &endptr); 108 if (endptr != s + strlen(s) ) 109 *ok = 0; 110 else 111 *ok = 1; 112 113 return res; 114 } 115 116 static void 117 print_caps(int caps) 118 { 119 int i, need_coma; 120 121 need_coma = 0; 122 printf("<"); 123 for (i = 0; i < 32; i++) { 124 if (caps & (1 << i)) { 125 if (need_coma) 126 printf(","); 127 printf("%s", cap2str(1 << i)); 128 need_coma = 1; 129 } 130 } 131 printf(">"); 132 } 133 134 static void 135 dump_pins(int fd, int verbose) 136 { 137 int i, maxpin; 138 struct gpio_pin pin; 139 struct gpio_req req; 140 141 if (ioctl(fd, GPIOMAXPIN, &maxpin) < 0) { 142 perror("ioctl(GPIOMAXPIN)"); 143 exit(1); 144 } 145 146 for (i = 0; i <= maxpin; i++) { 147 pin.gp_pin = i; 148 if (ioctl(fd, GPIOGETCONFIG, &pin) < 0) 149 /* For some reason this pin is inaccessible */ 150 continue; 151 152 req.gp_pin = i; 153 if (ioctl(fd, GPIOGET, &req) < 0) { 154 /* Now, that's wrong */ 155 perror("ioctl(GPIOGET)"); 156 exit(1); 157 } 158 159 printf("pin %02d:\t%d\t%s", pin.gp_pin, req.gp_value, 160 pin.gp_name); 161 162 print_caps(pin.gp_flags); 163 164 if (verbose) { 165 printf(", caps:"); 166 print_caps(pin.gp_caps); 167 } 168 printf("\n"); 169 } 170 } 171 172 static void 173 fail(const char *fmt, ...) 174 { 175 va_list ap; 176 177 va_start(ap, fmt); 178 vfprintf(stderr, fmt, ap); 179 va_end(ap); 180 exit(1); 181 } 182 183 int 184 main(int argc, char **argv) 185 { 186 int i; 187 struct gpio_pin pin; 188 struct gpio_req req; 189 char defctlfile[] = _PATH_DEVGPIOC "0"; 190 char *ctlfile = NULL; 191 int pinn, pinv, fd, ch; 192 int flags, flag, ok; 193 int config, toggle, verbose, list; 194 195 config = toggle = verbose = list = pinn = 0; 196 197 while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) { 198 switch (ch) { 199 case 'c': 200 config = 1; 201 pinn = str2int(optarg, &ok); 202 if (!ok) 203 fail("Invalid pin number: %s\n", optarg); 204 break; 205 case 'f': 206 ctlfile = optarg; 207 break; 208 case 'l': 209 list = 1; 210 break; 211 case 't': 212 toggle = 1; 213 pinn = str2int(optarg, &ok); 214 if (!ok) 215 fail("Invalid pin number: %s\n", optarg); 216 break; 217 case 'v': 218 verbose = 1; 219 break; 220 default: 221 usage(); 222 break; 223 } 224 } 225 argv += optind; 226 argc -= optind; 227 for (i = 0; i < argc; i++) 228 printf("%d/%s\n", i, argv[i]); 229 230 if (ctlfile == NULL) 231 ctlfile = defctlfile; 232 233 fd = open(ctlfile, O_RDONLY); 234 if (fd < 0) { 235 perror("open"); 236 exit(1); 237 } 238 239 if (list) { 240 dump_pins(fd, verbose); 241 close(fd); 242 exit(0); 243 } 244 245 if (toggle) { 246 /* 247 * -t pin assumes no additional arguments 248 */ 249 if(argc > 0) { 250 usage(); 251 exit(1); 252 } 253 254 req.gp_pin = pinn; 255 if (ioctl(fd, GPIOTOGGLE, &req) < 0) { 256 perror("ioctl(GPIOTOGGLE)"); 257 exit(1); 258 } 259 260 close(fd); 261 exit (0); 262 } 263 264 if (config) { 265 flags = 0; 266 for (i = 0; i < argc; i++) { 267 flag = str2cap(argv[i]); 268 if (flag < 0) 269 fail("Invalid flag: %s\n", argv[i]); 270 flags |= flag; 271 } 272 273 pin.gp_pin = pinn; 274 pin.gp_flags = flags; 275 if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) { 276 perror("ioctl(GPIOSETCONFIG)"); 277 exit(1); 278 } 279 280 exit(0); 281 } 282 283 /* 284 * Last two cases - set value or print value 285 */ 286 if ((argc == 0) || (argc > 2)) { 287 usage(); 288 exit(1); 289 } 290 291 pinn = str2int(argv[0], &ok); 292 if (!ok) 293 fail("Invalid pin number: %s\n", argv[0]); 294 295 /* 296 * Read pin value 297 */ 298 if (argc == 1) { 299 req.gp_pin = pinn; 300 if (ioctl(fd, GPIOGET, &req) < 0) { 301 perror("ioctl(GPIOGET)"); 302 exit(1); 303 } 304 printf("%d\n", req.gp_value); 305 exit (0); 306 } 307 308 /* Is it valid number (0 or 1) ? */ 309 pinv = str2int(argv[1], &ok); 310 if (!ok || ((pinv != 0) && (pinv != 1))) 311 fail("Invalid pin value: %s\n", argv[1]); 312 313 /* 314 * Set pin value 315 */ 316 req.gp_pin = pinn; 317 req.gp_value = pinv; 318 if (ioctl(fd, GPIOSET, &req) < 0) { 319 perror("ioctl(GPIOSET)"); 320 exit(1); 321 } 322 323 close(fd); 324 exit(0); 325 } 326