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