xref: /freebsd/usr.sbin/gpioctl/gpioctl.c (revision d0bd1251350a0564fb20f0044f061f1c6b6079c2)
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 }
163 
164 static void
165 fail(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 
175 int
176 main(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 	if (ctlfile == NULL)
219 		handle = gpio_open(0);
220 	else
221 		handle = gpio_open_device(ctlfile);
222 	if (handle == GPIO_INVALID_HANDLE) {
223 		perror("gpio_open");
224 		exit(1);
225 	}
226 
227 	if (list) {
228 		dump_pins(handle, verbose);
229 		gpio_close(handle);
230 		exit(0);
231 	}
232 
233 	if (toggle) {
234 		/*
235 		 * -t pin assumes no additional arguments
236 		 */
237 		if (argc > 0) {
238 			usage();
239 			exit(1);
240 		}
241 		if (gpio_pin_toggle(handle, pinn) < 0) {
242 			perror("gpio_pin_toggle");
243 			exit(1);
244 		}
245 		gpio_close(handle);
246 		exit(0);
247 	}
248 
249 	if (config) {
250 		flags = 0;
251 		for (i = 0; i < argc; i++) {
252 			flag = 	str2cap(argv[i]);
253 			if (flag < 0)
254 				fail("Invalid flag: %s\n", argv[i]);
255 			flags |= flag;
256 		}
257 		pin.g_pin = pinn;
258 		pin.g_flags = flags;
259 		if (gpio_pin_set_flags(handle, &pin) < 0) {
260 			perror("gpio_pin_set_flags");
261 			exit(1);
262 		}
263 		exit(0);
264 	}
265 
266 	/*
267 	 * Last two cases - set value or print value
268 	 */
269 	if ((argc == 0) || (argc > 2)) {
270 		usage();
271 		exit(1);
272 	}
273 
274 	pinn = str2int(argv[0], &ok);
275 	if (!ok)
276 		fail("Invalid pin number: %s\n", argv[0]);
277 
278 	/*
279 	 * Read pin value
280 	 */
281 	if (argc == 1) {
282 		pinv = gpio_pin_get(handle, pinn);
283 		if (pinv < 0) {
284 			perror("gpio_pin_get");
285 			exit(1);
286 		}
287 		printf("%d\n", pinv);
288 		exit(0);
289 	}
290 
291 	/* Is it valid number (0 or 1) ? */
292 	pinv = str2int(argv[1], &ok);
293 	if (!ok || ((pinv != 0) && (pinv != 1)))
294 		fail("Invalid pin value: %s\n", argv[1]);
295 
296 	/*
297 	 * Set pin value
298 	 */
299 	if (gpio_pin_set(handle, pinn, pinv) < 0) {
300 		perror("gpio_pin_set");
301 		exit(1);
302 	}
303 
304 	gpio_close(handle);
305 	exit(0);
306 }
307