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