gpioctl.c revision 275395
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: head/usr.sbin/gpioctl/gpioctl.c 275395 2014-12-02 06:11:32Z rpaulo $"); 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 43struct flag_desc { 44 const char *name; 45 uint32_t flag; 46}; 47 48static 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 62int str2cap(const char *str); 63 64static void 65usage(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] pin [0|1]\n"); 72 exit(1); 73} 74 75static const char * 76cap2str(uint32_t cap) 77{ 78 struct flag_desc * pdesc = gpio_flags; 79 while (pdesc->name) { 80 if (pdesc->flag == cap) 81 return pdesc->name; 82 pdesc++; 83 } 84 85 return "UNKNOWN"; 86} 87 88int 89str2cap(const char *str) 90{ 91 struct flag_desc * pdesc = gpio_flags; 92 while (pdesc->name) { 93 if (strcasecmp(str, pdesc->name) == 0) 94 return pdesc->flag; 95 pdesc++; 96 } 97 98 return (-1); 99} 100 101/* 102 * Our handmade function for converting string to number 103 */ 104static int 105str2int(const char *s, int *ok) 106{ 107 char *endptr; 108 int res = strtod(s, &endptr); 109 if (endptr != s + strlen(s) ) 110 *ok = 0; 111 else 112 *ok = 1; 113 114 return res; 115} 116 117static void 118print_caps(int caps) 119{ 120 int i, need_coma; 121 122 need_coma = 0; 123 printf("<"); 124 for (i = 0; i < 32; i++) { 125 if (caps & (1 << i)) { 126 if (need_coma) 127 printf(","); 128 printf("%s", cap2str(1 << i)); 129 need_coma = 1; 130 } 131 } 132 printf(">"); 133} 134 135static void 136dump_pins(gpio_handle_t handle, int verbose) 137{ 138 int i, maxpin, pinv; 139 gpio_config_t *cfgs; 140 gpio_config_t *pin; 141 142 maxpin = gpio_pin_list(handle, &cfgs); 143 if (maxpin < 0) { 144 perror("gpio_pin_list"); 145 exit(1); 146 } 147 148 for (i = 0; i <= maxpin; i++) { 149 pin = cfgs + i; 150 pinv = gpio_pin_get(handle, pin->g_pin); 151 printf("pin %02d:\t%d\t%s", pin->g_pin, pinv, 152 pin->g_name); 153 154 print_caps(pin->g_flags); 155 156 if (verbose) { 157 printf(", caps:"); 158 print_caps(pin->g_caps); 159 } 160 printf("\n"); 161 } 162} 163 164static void 165fail(const char *fmt, ...) 166{ 167 va_list ap; 168 169 va_start(ap, fmt); 170 vfprintf(stderr, fmt, ap); 171 va_end(ap); 172 exit(1); 173} 174 175int 176main(int argc, char **argv) 177{ 178 int i; 179 gpio_config_t pin; 180 gpio_handle_t handle; 181 char *ctlfile = NULL; 182 int pinn, pinv, ch; 183 int flags, flag, ok; 184 int config, toggle, verbose, list; 185 186 config = toggle = verbose = list = pinn = 0; 187 188 while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) { 189 switch (ch) { 190 case 'c': 191 config = 1; 192 pinn = str2int(optarg, &ok); 193 if (!ok) 194 fail("Invalid pin number: %s\n", optarg); 195 break; 196 case 'f': 197 ctlfile = optarg; 198 break; 199 case 'l': 200 list = 1; 201 break; 202 case 't': 203 toggle = 1; 204 pinn = str2int(optarg, &ok); 205 if (!ok) 206 fail("Invalid pin number: %s\n", optarg); 207 break; 208 case 'v': 209 verbose = 1; 210 break; 211 default: 212 usage(); 213 break; 214 } 215 } 216 argv += optind; 217 argc -= optind; 218 for (i = 0; i < argc; i++) 219 printf("%d/%s\n", i, argv[i]); 220 221 if (ctlfile == NULL) 222 handle = gpio_open(0); 223 else 224 handle = gpio_open_device(ctlfile); 225 if (handle == GPIO_INVALID_HANDLE) { 226 perror("gpio_open"); 227 exit(1); 228 } 229 230 if (list) { 231 dump_pins(handle, verbose); 232 gpio_close(handle); 233 exit(0); 234 } 235 236 if (toggle) { 237 /* 238 * -t pin assumes no additional arguments 239 */ 240 if (argc > 0) { 241 usage(); 242 exit(1); 243 } 244 if (gpio_pin_toggle(handle, pinn) < 0) { 245 perror("gpio_pin_toggle"); 246 exit(1); 247 } 248 gpio_close(handle); 249 exit(0); 250 } 251 252 if (config) { 253 flags = 0; 254 for (i = 0; i < argc; i++) { 255 flag = str2cap(argv[i]); 256 if (flag < 0) 257 fail("Invalid flag: %s\n", argv[i]); 258 flags |= flag; 259 } 260 pin.g_pin = pinn; 261 pin.g_flags = flags; 262 if (gpio_pin_set_flags(handle, &pin) < 0) { 263 perror("gpio_pin_set_flags"); 264 exit(1); 265 } 266 exit(0); 267 } 268 269 /* 270 * Last two cases - set value or print value 271 */ 272 if ((argc == 0) || (argc > 2)) { 273 usage(); 274 exit(1); 275 } 276 277 pinn = str2int(argv[0], &ok); 278 if (!ok) 279 fail("Invalid pin number: %s\n", argv[0]); 280 281 /* 282 * Read pin value 283 */ 284 if (argc == 1) { 285 pinv = gpio_pin_get(handle, pinn); 286 if (pinv < 0) { 287 perror("gpio_pin_get"); 288 exit(1); 289 } 290 printf("%d\n", pinv); 291 exit(0); 292 } 293 294 /* Is it valid number (0 or 1) ? */ 295 pinv = str2int(argv[1], &ok); 296 if (!ok || ((pinv != 0) && (pinv != 1))) 297 fail("Invalid pin value: %s\n", argv[1]); 298 299 /* 300 * Set pin value 301 */ 302 if (gpio_pin_set(handle, pinn, pinv) < 0) { 303 perror("gpio_pin_set"); 304 exit(1); 305 } 306 307 gpio_close(handle); 308 exit(0); 309} 310