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> 33213238Sgonzo#include <stdio.h> 34213238Sgonzo#include <stdarg.h> 35213238Sgonzo#include <stdlib.h> 36213238Sgonzo#include <string.h> 37213238Sgonzo#include <unistd.h> 38213238Sgonzo 39213238Sgonzo#include <sys/gpio.h> 40213238Sgonzo 41213238Sgonzostruct flag_desc { 42213238Sgonzo const char *name; 43213238Sgonzo uint32_t flag; 44213238Sgonzo}; 45213238Sgonzo 46213238Sgonzostruct flag_desc gpio_flags[] = { 47213238Sgonzo { "IN", GPIO_PIN_INPUT }, 48213238Sgonzo { "OUT", GPIO_PIN_OUTPUT }, 49213238Sgonzo { "OD", GPIO_PIN_OPENDRAIN }, 50213238Sgonzo { "PP", GPIO_PIN_PUSHPULL }, 51213238Sgonzo { "TS", GPIO_PIN_TRISTATE }, 52213238Sgonzo { "PU", GPIO_PIN_PULLUP }, 53213238Sgonzo { "PD", GPIO_PIN_PULLDOWN }, 54213238Sgonzo { "II", GPIO_PIN_INVIN }, 55213238Sgonzo { "IO", GPIO_PIN_INVOUT }, 56213238Sgonzo { "PULSE", GPIO_PIN_PULSATE }, 57213238Sgonzo { NULL, 0 }, 58213238Sgonzo}; 59213238Sgonzo 60213238Sgonzoint str2cap(const char *str); 61213238Sgonzo 62213238Sgonzostatic void 63213238Sgonzousage(void) 64213238Sgonzo{ 65213238Sgonzo fprintf(stderr, "Usage:\n"); 66213238Sgonzo fprintf(stderr, "\tgpioctl -f ctldev -l [-v]\n"); 67213238Sgonzo fprintf(stderr, "\tgpioctl -f ctldev -t pin\n"); 68213238Sgonzo fprintf(stderr, "\tgpioctl -f ctldev -c pin flag ...\n"); 69213238Sgonzo fprintf(stderr, "\tgpioctl -f ctldev pin [0|1]\n"); 70213238Sgonzo exit(1); 71213238Sgonzo} 72213238Sgonzo 73213238Sgonzostatic const char * 74213238Sgonzocap2str(uint32_t cap) 75213238Sgonzo{ 76213238Sgonzo struct flag_desc * pdesc = gpio_flags; 77213238Sgonzo while (pdesc->name) { 78213238Sgonzo if (pdesc->flag == cap) 79213238Sgonzo return pdesc->name; 80213238Sgonzo pdesc++; 81213238Sgonzo } 82213238Sgonzo 83213238Sgonzo return "UNKNOWN"; 84213238Sgonzo} 85213238Sgonzo 86213238Sgonzoint 87213238Sgonzostr2cap(const char *str) 88213238Sgonzo{ 89213238Sgonzo struct flag_desc * pdesc = gpio_flags; 90213238Sgonzo while (pdesc->name) { 91213238Sgonzo if (strcasecmp(str, pdesc->name) == 0) 92213238Sgonzo return pdesc->flag; 93213238Sgonzo pdesc++; 94213238Sgonzo } 95213238Sgonzo 96213238Sgonzo return (-1); 97213238Sgonzo} 98213238Sgonzo 99213238Sgonzo/* 100213238Sgonzo * Our handmade function for converting string to number 101213238Sgonzo */ 102213238Sgonzostatic int 103213238Sgonzostr2int(const char *s, int *ok) 104213238Sgonzo{ 105213238Sgonzo char *endptr; 106213238Sgonzo int res = strtod(s, &endptr); 107213238Sgonzo if (endptr != s + strlen(s) ) 108213238Sgonzo *ok = 0; 109213238Sgonzo else 110213238Sgonzo *ok = 1; 111213238Sgonzo 112213238Sgonzo return res; 113213238Sgonzo} 114213238Sgonzo 115213238Sgonzostatic void 116213238Sgonzoprint_caps(int caps) 117213238Sgonzo{ 118213238Sgonzo int i, need_coma; 119213238Sgonzo 120213238Sgonzo need_coma = 0; 121213238Sgonzo printf("<"); 122213238Sgonzo for (i = 0; i < 32; i++) { 123213238Sgonzo if (caps & (1 << i)) { 124213238Sgonzo if (need_coma) 125213238Sgonzo printf(","); 126213238Sgonzo printf("%s", cap2str(1 << i)); 127213238Sgonzo need_coma = 1; 128213238Sgonzo } 129213238Sgonzo } 130213238Sgonzo printf(">"); 131213238Sgonzo} 132213238Sgonzo 133213238Sgonzostatic void 134213238Sgonzodump_pins(int fd, int verbose) 135213238Sgonzo{ 136213238Sgonzo int i, maxpin; 137213238Sgonzo struct gpio_pin pin; 138213238Sgonzo struct gpio_req req; 139213238Sgonzo 140213238Sgonzo if (ioctl(fd, GPIOMAXPIN, &maxpin) < 0) { 141213238Sgonzo perror("ioctl(GPIOMAXPIN)"); 142213238Sgonzo exit(1); 143213238Sgonzo } 144213238Sgonzo 145213238Sgonzo for (i = 0; i <= maxpin; i++) { 146213238Sgonzo pin.gp_pin = i; 147213238Sgonzo if (ioctl(fd, GPIOGETCONFIG, &pin) < 0) 148213238Sgonzo /* For some reason this pin is inaccessible */ 149213238Sgonzo continue; 150213238Sgonzo 151213238Sgonzo req.gp_pin = i; 152213238Sgonzo if (ioctl(fd, GPIOGET, &req) < 0) { 153213238Sgonzo /* Now, that's wrong */ 154213238Sgonzo perror("ioctl(GPIOGET)"); 155213238Sgonzo exit(1); 156213238Sgonzo } 157213238Sgonzo 158213238Sgonzo printf("pin %02d:\t%d\t%s", pin.gp_pin, req.gp_value, 159213238Sgonzo pin.gp_name); 160213238Sgonzo 161213238Sgonzo print_caps(pin.gp_flags); 162213238Sgonzo 163213238Sgonzo if (verbose) { 164213238Sgonzo printf(", caps:"); 165213238Sgonzo print_caps(pin.gp_caps); 166213238Sgonzo } 167213238Sgonzo printf("\n"); 168213238Sgonzo } 169213238Sgonzo} 170213238Sgonzo 171213238Sgonzostatic void 172213238Sgonzofail(const char *fmt, ...) 173213238Sgonzo{ 174213238Sgonzo va_list ap; 175213238Sgonzo 176213238Sgonzo va_start(ap, fmt); 177213238Sgonzo vfprintf(stderr, fmt, ap); 178213238Sgonzo va_end(ap); 179213238Sgonzo exit(1); 180213238Sgonzo} 181213238Sgonzo 182213238Sgonzoint 183213238Sgonzomain(int argc, char **argv) 184213238Sgonzo{ 185213238Sgonzo int i; 186213238Sgonzo struct gpio_pin pin; 187213238Sgonzo struct gpio_req req; 188213238Sgonzo char *ctlfile = NULL; 189213238Sgonzo int pinn, pinv, fd, ch; 190213238Sgonzo int flags, flag, ok; 191213238Sgonzo int config, toggle, verbose, list; 192213238Sgonzo 193213238Sgonzo config = toggle = verbose = list = pinn = 0; 194213238Sgonzo 195213238Sgonzo while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) { 196213238Sgonzo switch (ch) { 197213238Sgonzo case 'c': 198213238Sgonzo config = 1; 199213238Sgonzo pinn = str2int(optarg, &ok); 200213238Sgonzo if (!ok) 201213238Sgonzo fail("Invalid pin number: %s\n", optarg); 202213238Sgonzo break; 203213238Sgonzo case 'f': 204213238Sgonzo ctlfile = optarg; 205213238Sgonzo break; 206213238Sgonzo case 'l': 207213238Sgonzo list = 1; 208213238Sgonzo break; 209213238Sgonzo case 't': 210213238Sgonzo toggle = 1; 211213238Sgonzo pinn = str2int(optarg, &ok); 212213238Sgonzo if (!ok) 213213238Sgonzo fail("Invalid pin number: %s\n", optarg); 214213238Sgonzo break; 215213238Sgonzo case 'v': 216213238Sgonzo verbose = 1; 217213238Sgonzo break; 218213238Sgonzo default: 219213238Sgonzo usage(); 220213238Sgonzo break; 221213238Sgonzo } 222213238Sgonzo } 223213238Sgonzo argv += optind; 224213238Sgonzo argc -= optind; 225213238Sgonzo for (i = 0; i < argc; i++) 226213238Sgonzo printf("%d/%s\n", i, argv[i]); 227213238Sgonzo 228213238Sgonzo if (ctlfile == NULL) 229213238Sgonzo fail("No gpioctl device provided\n"); 230213238Sgonzo 231213238Sgonzo fd = open(ctlfile, O_RDONLY); 232213238Sgonzo if (fd < 0) { 233213238Sgonzo perror("open"); 234213238Sgonzo exit(1); 235213238Sgonzo } 236213238Sgonzo 237213238Sgonzo if (list) { 238213238Sgonzo dump_pins(fd, verbose); 239213238Sgonzo close(fd); 240213238Sgonzo exit(0); 241213238Sgonzo } 242213238Sgonzo 243213238Sgonzo if (toggle) { 244213238Sgonzo /* 245213238Sgonzo * -t pin assumes no additional arguments 246213238Sgonzo */ 247213238Sgonzo if(argc > 0) { 248213238Sgonzo usage(); 249213238Sgonzo exit(1); 250213238Sgonzo } 251213238Sgonzo 252213238Sgonzo req.gp_pin = pinn; 253213238Sgonzo if (ioctl(fd, GPIOTOGGLE, &req) < 0) { 254213238Sgonzo perror("ioctl(GPIOTOGGLE)"); 255213238Sgonzo exit(1); 256213238Sgonzo } 257213238Sgonzo 258213238Sgonzo close(fd); 259213238Sgonzo exit (0); 260213238Sgonzo } 261213238Sgonzo 262213238Sgonzo if (config) { 263213238Sgonzo flags = 0; 264213238Sgonzo for (i = 0; i < argc; i++) { 265213238Sgonzo flag = str2cap(argv[i]); 266213238Sgonzo if (flag < 0) 267213238Sgonzo fail("Invalid flag: %s\n", argv[i]); 268213238Sgonzo flags |= flag; 269213238Sgonzo } 270213238Sgonzo 271213238Sgonzo pin.gp_pin = pinn; 272213238Sgonzo pin.gp_flags = flags; 273213238Sgonzo if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) { 274213238Sgonzo perror("ioctl(GPIOSETCONFIG)"); 275213238Sgonzo exit(1); 276213238Sgonzo } 277213238Sgonzo 278213238Sgonzo exit(0); 279213238Sgonzo } 280213238Sgonzo 281213238Sgonzo /* 282213238Sgonzo * Last two cases - set value or print value 283213238Sgonzo */ 284213238Sgonzo if ((argc == 0) || (argc > 2)) { 285213238Sgonzo usage(); 286213238Sgonzo exit(1); 287213238Sgonzo } 288213238Sgonzo 289213238Sgonzo pinn = str2int(argv[0], &ok); 290213238Sgonzo if (!ok) 291213238Sgonzo fail("Invalid pin number: %s\n", argv[0]); 292213238Sgonzo 293213238Sgonzo /* 294213238Sgonzo * Read pin value 295213238Sgonzo */ 296213238Sgonzo if (argc == 1) { 297213238Sgonzo req.gp_pin = pinn; 298213238Sgonzo if (ioctl(fd, GPIOGET, &req) < 0) { 299213238Sgonzo perror("ioctl(GPIOGET)"); 300213238Sgonzo exit(1); 301213238Sgonzo } 302213238Sgonzo printf("%d\n", req.gp_value); 303213238Sgonzo exit (0); 304213238Sgonzo } 305213238Sgonzo 306213238Sgonzo /* Is it valid number (0 or 1) ? */ 307213238Sgonzo pinv = str2int(argv[1], &ok); 308213238Sgonzo if (!ok || ((pinv != 0) && (pinv != 1))) 309213238Sgonzo fail("Invalid pin value: %s\n", argv[1]); 310213238Sgonzo 311213238Sgonzo /* 312213238Sgonzo * Set pin value 313213238Sgonzo */ 314213238Sgonzo req.gp_pin = pinn; 315213238Sgonzo req.gp_value = pinv; 316213238Sgonzo if (ioctl(fd, GPIOSET, &req) < 0) { 317213238Sgonzo perror("ioctl(GPIOSET)"); 318213238Sgonzo exit(1); 319213238Sgonzo } 320213238Sgonzo 321213238Sgonzo close(fd); 322213238Sgonzo exit(0); 323213238Sgonzo} 324