xref: /freebsd/usr.sbin/gpioctl/gpioctl.c (revision db3cb3640f547c063293e9fdc4db69e9dc120951)
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$");
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 
43 struct flag_desc {
44 	const char *name;
45 	uint32_t flag;
46 };
47 
48 static 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 
62 int str2cap(const char *str);
63 
64 static void
65 usage(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 
75 static const char *
76 cap2str(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 
88 int
89 str2cap(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  */
104 static int
105 str2int(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 
117 static void
118 print_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 
135 static void
136 dump_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 	free(cfgs);
163 }
164 
165 static void
166 fail(const char *fmt, ...)
167 {
168 	va_list ap;
169 
170 	va_start(ap, fmt);
171 	vfprintf(stderr, fmt, ap);
172 	va_end(ap);
173 	exit(1);
174 }
175 
176 int
177 main(int argc, char **argv)
178 {
179 	int i;
180 	gpio_config_t pin;
181 	gpio_handle_t handle;
182 	char *ctlfile = NULL;
183 	int pinn, pinv, ch;
184 	int flags, flag, ok;
185 	int config, toggle, verbose, list;
186 
187 	config = toggle = verbose = list = pinn = 0;
188 
189 	while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) {
190 		switch (ch) {
191 		case 'c':
192 			config = 1;
193 			pinn = str2int(optarg, &ok);
194 			if (!ok)
195 				fail("Invalid pin number: %s\n", optarg);
196 			break;
197 		case 'f':
198 			ctlfile = optarg;
199 			break;
200 		case 'l':
201 			list = 1;
202 			break;
203 		case 't':
204 			toggle = 1;
205 			pinn = str2int(optarg, &ok);
206 			if (!ok)
207 				fail("Invalid pin number: %s\n", optarg);
208 			break;
209 		case 'v':
210 			verbose = 1;
211 			break;
212 		default:
213 			usage();
214 			break;
215 		}
216 	}
217 	argv += optind;
218 	argc -= optind;
219 	if (ctlfile == NULL)
220 		handle = gpio_open(0);
221 	else
222 		handle = gpio_open_device(ctlfile);
223 	if (handle == GPIO_INVALID_HANDLE) {
224 		perror("gpio_open");
225 		exit(1);
226 	}
227 
228 	if (list) {
229 		dump_pins(handle, verbose);
230 		gpio_close(handle);
231 		exit(0);
232 	}
233 
234 	if (toggle) {
235 		/*
236 		 * -t pin assumes no additional arguments
237 		 */
238 		if (argc > 0) {
239 			usage();
240 			exit(1);
241 		}
242 		if (gpio_pin_toggle(handle, pinn) < 0) {
243 			perror("gpio_pin_toggle");
244 			exit(1);
245 		}
246 		gpio_close(handle);
247 		exit(0);
248 	}
249 
250 	if (config) {
251 		flags = 0;
252 		for (i = 0; i < argc; i++) {
253 			flag = 	str2cap(argv[i]);
254 			if (flag < 0)
255 				fail("Invalid flag: %s\n", argv[i]);
256 			flags |= flag;
257 		}
258 		pin.g_pin = pinn;
259 		pin.g_flags = flags;
260 		if (gpio_pin_set_flags(handle, &pin) < 0) {
261 			perror("gpio_pin_set_flags");
262 			exit(1);
263 		}
264 		exit(0);
265 	}
266 
267 	/*
268 	 * Last two cases - set value or print value
269 	 */
270 	if ((argc == 0) || (argc > 2)) {
271 		usage();
272 		exit(1);
273 	}
274 
275 	pinn = str2int(argv[0], &ok);
276 	if (!ok)
277 		fail("Invalid pin number: %s\n", argv[0]);
278 
279 	/*
280 	 * Read pin value
281 	 */
282 	if (argc == 1) {
283 		pinv = gpio_pin_get(handle, pinn);
284 		if (pinv < 0) {
285 			perror("gpio_pin_get");
286 			exit(1);
287 		}
288 		printf("%d\n", pinv);
289 		exit(0);
290 	}
291 
292 	/* Is it valid number (0 or 1) ? */
293 	pinv = str2int(argv[1], &ok);
294 	if (!ok || ((pinv != 0) && (pinv != 1)))
295 		fail("Invalid pin value: %s\n", argv[1]);
296 
297 	/*
298 	 * Set pin value
299 	 */
300 	if (gpio_pin_set(handle, pinn, pinv) < 0) {
301 		perror("gpio_pin_set");
302 		exit(1);
303 	}
304 
305 	gpio_close(handle);
306 	exit(0);
307 }
308