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