1213238Sgonzo/*- 2213238Sgonzo * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3213238Sgonzo * All rights reserved. 4213238Sgonzo * 5213238Sgonzo * Redistribution and use in source and binary forms, with or without 6213238Sgonzo * modification, are permitted provided that the following conditions 7213238Sgonzo * are met: 8213238Sgonzo * 1. Redistributions of source code must retain the above copyright 9213238Sgonzo * notice unmodified, this list of conditions, and the following 10213238Sgonzo * disclaimer. 11213238Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12213238Sgonzo * notice, this list of conditions and the following disclaimer in the 13213238Sgonzo * documentation and/or other materials provided with the distribution. 14213238Sgonzo * 15213238Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16213238Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17213238Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18213238Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19213238Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20213238Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21213238Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22213238Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23213238Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24213238Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25213238Sgonzo * SUCH DAMAGE. 26213238Sgonzo */ 27213238Sgonzo 28213238Sgonzo#include <sys/cdefs.h> 29213238Sgonzo__FBSDID("$FreeBSD$"); 30213238Sgonzo 31213238Sgonzo#include <fcntl.h> 32213238Sgonzo#include <getopt.h> 33255629Ssbruno#include <paths.h> 34213238Sgonzo#include <stdio.h> 35213238Sgonzo#include <stdarg.h> 36213238Sgonzo#include <stdlib.h> 37213238Sgonzo#include <string.h> 38213238Sgonzo#include <unistd.h> 39213238Sgonzo 40213238Sgonzo#include <sys/gpio.h> 41213238Sgonzo 42213238Sgonzostruct flag_desc { 43213238Sgonzo const char *name; 44213238Sgonzo uint32_t flag; 45213238Sgonzo}; 46213238Sgonzo 47241737Sedstatic struct flag_desc gpio_flags[] = { 48213238Sgonzo { "IN", GPIO_PIN_INPUT }, 49213238Sgonzo { "OUT", GPIO_PIN_OUTPUT }, 50213238Sgonzo { "OD", GPIO_PIN_OPENDRAIN }, 51213238Sgonzo { "PP", GPIO_PIN_PUSHPULL }, 52213238Sgonzo { "TS", GPIO_PIN_TRISTATE }, 53213238Sgonzo { "PU", GPIO_PIN_PULLUP }, 54213238Sgonzo { "PD", GPIO_PIN_PULLDOWN }, 55213238Sgonzo { "II", GPIO_PIN_INVIN }, 56213238Sgonzo { "IO", GPIO_PIN_INVOUT }, 57213238Sgonzo { "PULSE", GPIO_PIN_PULSATE }, 58213238Sgonzo { NULL, 0 }, 59213238Sgonzo}; 60213238Sgonzo 61213238Sgonzoint str2cap(const char *str); 62213238Sgonzo 63213238Sgonzostatic void 64213238Sgonzousage(void) 65213238Sgonzo{ 66213238Sgonzo fprintf(stderr, "Usage:\n"); 67255629Ssbruno fprintf(stderr, "\tgpioctl [-f ctldev] -l [-v]\n"); 68255629Ssbruno fprintf(stderr, "\tgpioctl [-f ctldev] -t pin\n"); 69255629Ssbruno fprintf(stderr, "\tgpioctl [-f ctldev] -c pin flag ...\n"); 70255629Ssbruno fprintf(stderr, "\tgpioctl [-f ctldev] pin [0|1]\n"); 71213238Sgonzo exit(1); 72213238Sgonzo} 73213238Sgonzo 74213238Sgonzostatic const char * 75213238Sgonzocap2str(uint32_t cap) 76213238Sgonzo{ 77213238Sgonzo struct flag_desc * pdesc = gpio_flags; 78213238Sgonzo while (pdesc->name) { 79213238Sgonzo if (pdesc->flag == cap) 80213238Sgonzo return pdesc->name; 81213238Sgonzo pdesc++; 82213238Sgonzo } 83213238Sgonzo 84213238Sgonzo return "UNKNOWN"; 85213238Sgonzo} 86213238Sgonzo 87213238Sgonzoint 88213238Sgonzostr2cap(const char *str) 89213238Sgonzo{ 90213238Sgonzo struct flag_desc * pdesc = gpio_flags; 91213238Sgonzo while (pdesc->name) { 92213238Sgonzo if (strcasecmp(str, pdesc->name) == 0) 93213238Sgonzo return pdesc->flag; 94213238Sgonzo pdesc++; 95213238Sgonzo } 96213238Sgonzo 97213238Sgonzo return (-1); 98213238Sgonzo} 99213238Sgonzo 100213238Sgonzo/* 101213238Sgonzo * Our handmade function for converting string to number 102213238Sgonzo */ 103213238Sgonzostatic int 104213238Sgonzostr2int(const char *s, int *ok) 105213238Sgonzo{ 106213238Sgonzo char *endptr; 107213238Sgonzo int res = strtod(s, &endptr); 108213238Sgonzo if (endptr != s + strlen(s) ) 109213238Sgonzo *ok = 0; 110213238Sgonzo else 111213238Sgonzo *ok = 1; 112213238Sgonzo 113213238Sgonzo return res; 114213238Sgonzo} 115213238Sgonzo 116213238Sgonzostatic void 117213238Sgonzoprint_caps(int caps) 118213238Sgonzo{ 119213238Sgonzo int i, need_coma; 120213238Sgonzo 121213238Sgonzo need_coma = 0; 122213238Sgonzo printf("<"); 123213238Sgonzo for (i = 0; i < 32; i++) { 124213238Sgonzo if (caps & (1 << i)) { 125213238Sgonzo if (need_coma) 126213238Sgonzo printf(","); 127213238Sgonzo printf("%s", cap2str(1 << i)); 128213238Sgonzo need_coma = 1; 129213238Sgonzo } 130213238Sgonzo } 131213238Sgonzo printf(">"); 132213238Sgonzo} 133213238Sgonzo 134213238Sgonzostatic void 135213238Sgonzodump_pins(int fd, int verbose) 136213238Sgonzo{ 137213238Sgonzo int i, maxpin; 138213238Sgonzo struct gpio_pin pin; 139213238Sgonzo struct gpio_req req; 140213238Sgonzo 141213238Sgonzo if (ioctl(fd, GPIOMAXPIN, &maxpin) < 0) { 142213238Sgonzo perror("ioctl(GPIOMAXPIN)"); 143213238Sgonzo exit(1); 144213238Sgonzo } 145213238Sgonzo 146213238Sgonzo for (i = 0; i <= maxpin; i++) { 147213238Sgonzo pin.gp_pin = i; 148213238Sgonzo if (ioctl(fd, GPIOGETCONFIG, &pin) < 0) 149213238Sgonzo /* For some reason this pin is inaccessible */ 150213238Sgonzo continue; 151213238Sgonzo 152213238Sgonzo req.gp_pin = i; 153213238Sgonzo if (ioctl(fd, GPIOGET, &req) < 0) { 154213238Sgonzo /* Now, that's wrong */ 155213238Sgonzo perror("ioctl(GPIOGET)"); 156213238Sgonzo exit(1); 157213238Sgonzo } 158213238Sgonzo 159213238Sgonzo printf("pin %02d:\t%d\t%s", pin.gp_pin, req.gp_value, 160213238Sgonzo pin.gp_name); 161213238Sgonzo 162213238Sgonzo print_caps(pin.gp_flags); 163213238Sgonzo 164213238Sgonzo if (verbose) { 165213238Sgonzo printf(", caps:"); 166213238Sgonzo print_caps(pin.gp_caps); 167213238Sgonzo } 168213238Sgonzo printf("\n"); 169213238Sgonzo } 170213238Sgonzo} 171213238Sgonzo 172213238Sgonzostatic void 173213238Sgonzofail(const char *fmt, ...) 174213238Sgonzo{ 175213238Sgonzo va_list ap; 176213238Sgonzo 177213238Sgonzo va_start(ap, fmt); 178213238Sgonzo vfprintf(stderr, fmt, ap); 179213238Sgonzo va_end(ap); 180213238Sgonzo exit(1); 181213238Sgonzo} 182213238Sgonzo 183213238Sgonzoint 184213238Sgonzomain(int argc, char **argv) 185213238Sgonzo{ 186213238Sgonzo int i; 187213238Sgonzo struct gpio_pin pin; 188213238Sgonzo struct gpio_req req; 189255629Ssbruno char defctlfile[] = _PATH_DEVGPIOC "0"; 190213238Sgonzo char *ctlfile = NULL; 191213238Sgonzo int pinn, pinv, fd, ch; 192213238Sgonzo int flags, flag, ok; 193213238Sgonzo int config, toggle, verbose, list; 194213238Sgonzo 195213238Sgonzo config = toggle = verbose = list = pinn = 0; 196213238Sgonzo 197213238Sgonzo while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) { 198213238Sgonzo switch (ch) { 199213238Sgonzo case 'c': 200213238Sgonzo config = 1; 201213238Sgonzo pinn = str2int(optarg, &ok); 202213238Sgonzo if (!ok) 203213238Sgonzo fail("Invalid pin number: %s\n", optarg); 204213238Sgonzo break; 205213238Sgonzo case 'f': 206213238Sgonzo ctlfile = optarg; 207213238Sgonzo break; 208213238Sgonzo case 'l': 209213238Sgonzo list = 1; 210213238Sgonzo break; 211213238Sgonzo case 't': 212213238Sgonzo toggle = 1; 213213238Sgonzo pinn = str2int(optarg, &ok); 214213238Sgonzo if (!ok) 215213238Sgonzo fail("Invalid pin number: %s\n", optarg); 216213238Sgonzo break; 217213238Sgonzo case 'v': 218213238Sgonzo verbose = 1; 219213238Sgonzo break; 220213238Sgonzo default: 221213238Sgonzo usage(); 222213238Sgonzo break; 223213238Sgonzo } 224213238Sgonzo } 225213238Sgonzo argv += optind; 226213238Sgonzo argc -= optind; 227213238Sgonzo for (i = 0; i < argc; i++) 228213238Sgonzo printf("%d/%s\n", i, argv[i]); 229213238Sgonzo 230213238Sgonzo if (ctlfile == NULL) 231255629Ssbruno ctlfile = defctlfile; 232213238Sgonzo 233213238Sgonzo fd = open(ctlfile, O_RDONLY); 234213238Sgonzo if (fd < 0) { 235213238Sgonzo perror("open"); 236213238Sgonzo exit(1); 237213238Sgonzo } 238213238Sgonzo 239213238Sgonzo if (list) { 240213238Sgonzo dump_pins(fd, verbose); 241213238Sgonzo close(fd); 242213238Sgonzo exit(0); 243213238Sgonzo } 244213238Sgonzo 245213238Sgonzo if (toggle) { 246213238Sgonzo /* 247213238Sgonzo * -t pin assumes no additional arguments 248213238Sgonzo */ 249213238Sgonzo if(argc > 0) { 250213238Sgonzo usage(); 251213238Sgonzo exit(1); 252213238Sgonzo } 253213238Sgonzo 254213238Sgonzo req.gp_pin = pinn; 255213238Sgonzo if (ioctl(fd, GPIOTOGGLE, &req) < 0) { 256213238Sgonzo perror("ioctl(GPIOTOGGLE)"); 257213238Sgonzo exit(1); 258213238Sgonzo } 259213238Sgonzo 260213238Sgonzo close(fd); 261213238Sgonzo exit (0); 262213238Sgonzo } 263213238Sgonzo 264213238Sgonzo if (config) { 265213238Sgonzo flags = 0; 266213238Sgonzo for (i = 0; i < argc; i++) { 267213238Sgonzo flag = str2cap(argv[i]); 268213238Sgonzo if (flag < 0) 269213238Sgonzo fail("Invalid flag: %s\n", argv[i]); 270213238Sgonzo flags |= flag; 271213238Sgonzo } 272213238Sgonzo 273213238Sgonzo pin.gp_pin = pinn; 274213238Sgonzo pin.gp_flags = flags; 275213238Sgonzo if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) { 276213238Sgonzo perror("ioctl(GPIOSETCONFIG)"); 277213238Sgonzo exit(1); 278213238Sgonzo } 279213238Sgonzo 280213238Sgonzo exit(0); 281213238Sgonzo } 282213238Sgonzo 283213238Sgonzo /* 284213238Sgonzo * Last two cases - set value or print value 285213238Sgonzo */ 286213238Sgonzo if ((argc == 0) || (argc > 2)) { 287213238Sgonzo usage(); 288213238Sgonzo exit(1); 289213238Sgonzo } 290213238Sgonzo 291213238Sgonzo pinn = str2int(argv[0], &ok); 292213238Sgonzo if (!ok) 293213238Sgonzo fail("Invalid pin number: %s\n", argv[0]); 294213238Sgonzo 295213238Sgonzo /* 296213238Sgonzo * Read pin value 297213238Sgonzo */ 298213238Sgonzo if (argc == 1) { 299213238Sgonzo req.gp_pin = pinn; 300213238Sgonzo if (ioctl(fd, GPIOGET, &req) < 0) { 301213238Sgonzo perror("ioctl(GPIOGET)"); 302213238Sgonzo exit(1); 303213238Sgonzo } 304213238Sgonzo printf("%d\n", req.gp_value); 305213238Sgonzo exit (0); 306213238Sgonzo } 307213238Sgonzo 308213238Sgonzo /* Is it valid number (0 or 1) ? */ 309213238Sgonzo pinv = str2int(argv[1], &ok); 310213238Sgonzo if (!ok || ((pinv != 0) && (pinv != 1))) 311213238Sgonzo fail("Invalid pin value: %s\n", argv[1]); 312213238Sgonzo 313213238Sgonzo /* 314213238Sgonzo * Set pin value 315213238Sgonzo */ 316213238Sgonzo req.gp_pin = pinn; 317213238Sgonzo req.gp_value = pinv; 318213238Sgonzo if (ioctl(fd, GPIOSET, &req) < 0) { 319213238Sgonzo perror("ioctl(GPIOSET)"); 320213238Sgonzo exit(1); 321213238Sgonzo } 322213238Sgonzo 323213238Sgonzo close(fd); 324213238Sgonzo exit(0); 325213238Sgonzo} 326