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