xref: /freebsd/usr.sbin/gpioctl/gpioctl.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
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$");
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 
47 struct flag_desc {
48 	const char *name;
49 	uint32_t flag;
50 };
51 
52 static 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 
66 int str2cap(const char *str);
67 
68 static void
69 usage(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 
80 static const char *
81 cap2str(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 
93 int
94 str2cap(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  */
109 static int
110 str2int(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 
122 static void
123 print_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 
140 static void
141 dump_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 
170 static int
171 get_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 
196 static void
197 fail(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 
207 int
208 main(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