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
usage(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] -n pin pin-name\n");
72 fprintf(stderr, "\tgpioctl [-f ctldev] pin [0|1]\n");
73 exit(1);
74 }
75
76 static const char *
cap2str(uint32_t cap)77 cap2str(uint32_t cap)
78 {
79 struct flag_desc * pdesc = gpio_flags;
80 while (pdesc->name) {
81 if (pdesc->flag == cap)
82 return pdesc->name;
83 pdesc++;
84 }
85
86 return "UNKNOWN";
87 }
88
89 int
str2cap(const char * str)90 str2cap(const char *str)
91 {
92 struct flag_desc * pdesc = gpio_flags;
93 while (pdesc->name) {
94 if (strcasecmp(str, pdesc->name) == 0)
95 return pdesc->flag;
96 pdesc++;
97 }
98
99 return (-1);
100 }
101
102 /*
103 * Our handmade function for converting string to number
104 */
105 static int
str2int(const char * s,int * ok)106 str2int(const char *s, int *ok)
107 {
108 char *endptr;
109 int res = strtod(s, &endptr);
110 if (endptr != s + strlen(s) )
111 *ok = 0;
112 else
113 *ok = 1;
114
115 return res;
116 }
117
118 static void
print_caps(int caps)119 print_caps(int caps)
120 {
121 int i, need_coma;
122
123 need_coma = 0;
124 printf("<");
125 for (i = 0; i < 32; i++) {
126 if (caps & (1 << i)) {
127 if (need_coma)
128 printf(",");
129 printf("%s", cap2str(1 << i));
130 need_coma = 1;
131 }
132 }
133 printf(">");
134 }
135
136 static void
dump_pins(gpio_handle_t handle,int verbose)137 dump_pins(gpio_handle_t handle, int verbose)
138 {
139 int i, maxpin, pinv;
140 gpio_config_t *cfgs;
141 gpio_config_t *pin;
142
143 maxpin = gpio_pin_list(handle, &cfgs);
144 if (maxpin < 0) {
145 perror("gpio_pin_list");
146 exit(1);
147 }
148
149 for (i = 0; i <= maxpin; i++) {
150 pin = cfgs + i;
151 pinv = gpio_pin_get(handle, pin->g_pin);
152 printf("pin %02d:\t%d\t%s", pin->g_pin, pinv,
153 pin->g_name);
154
155 print_caps(pin->g_flags);
156
157 if (verbose) {
158 printf(", caps:");
159 print_caps(pin->g_caps);
160 }
161 printf("\n");
162 }
163 free(cfgs);
164 }
165
166 static void
fail(const char * fmt,...)167 fail(const char *fmt, ...)
168 {
169 va_list ap;
170
171 va_start(ap, fmt);
172 vfprintf(stderr, fmt, ap);
173 va_end(ap);
174 exit(1);
175 }
176
177 int
main(int argc,char ** argv)178 main(int argc, char **argv)
179 {
180 int i;
181 gpio_config_t pin;
182 gpio_handle_t handle;
183 char *ctlfile = NULL;
184 int pinn, pinv, ch;
185 int flags, flag, ok;
186 int config, list, name, toggle, verbose;
187
188 config = toggle = verbose = list = name = pinn = 0;
189
190 while ((ch = getopt(argc, argv, "c:f:ln:t:v")) != -1) {
191 switch (ch) {
192 case 'c':
193 config = 1;
194 pinn = str2int(optarg, &ok);
195 if (!ok)
196 fail("Invalid pin number: %s\n", optarg);
197 break;
198 case 'f':
199 ctlfile = optarg;
200 break;
201 case 'l':
202 list = 1;
203 break;
204 case 'n':
205 name = 1;
206 pinn = str2int(optarg, &ok);
207 if (!ok)
208 fail("Invalid pin number: %s\n", optarg);
209 break;
210 case 't':
211 toggle = 1;
212 pinn = str2int(optarg, &ok);
213 if (!ok)
214 fail("Invalid pin number: %s\n", optarg);
215 break;
216 case 'v':
217 verbose = 1;
218 break;
219 default:
220 usage();
221 break;
222 }
223 }
224 argv += optind;
225 argc -= optind;
226 if (ctlfile == NULL)
227 handle = gpio_open(0);
228 else
229 handle = gpio_open_device(ctlfile);
230 if (handle == GPIO_INVALID_HANDLE) {
231 perror("gpio_open");
232 exit(1);
233 }
234
235 /* Set the pin name. */
236 if (name) {
237 if (argc == 0) {
238 usage();
239 exit(1);
240 }
241 if (gpio_pin_set_name(handle, pinn, argv[0]) < 0) {
242 perror("gpio_pin_set_name");
243 exit(1);
244 }
245 exit(0);
246 }
247
248 if (list) {
249 dump_pins(handle, verbose);
250 gpio_close(handle);
251 exit(0);
252 }
253
254 if (toggle) {
255 /*
256 * -t pin assumes no additional arguments
257 */
258 if (argc > 0) {
259 usage();
260 exit(1);
261 }
262 if (gpio_pin_toggle(handle, pinn) < 0) {
263 perror("gpio_pin_toggle");
264 exit(1);
265 }
266 gpio_close(handle);
267 exit(0);
268 }
269
270 if (config) {
271 flags = 0;
272 for (i = 0; i < argc; i++) {
273 flag = str2cap(argv[i]);
274 if (flag < 0)
275 fail("Invalid flag: %s\n", argv[i]);
276 flags |= flag;
277 }
278 pin.g_pin = pinn;
279 pin.g_flags = flags;
280 if (gpio_pin_set_flags(handle, &pin) < 0) {
281 perror("gpio_pin_set_flags");
282 exit(1);
283 }
284 exit(0);
285 }
286
287 /*
288 * Last two cases - set value or print value
289 */
290 if ((argc == 0) || (argc > 2)) {
291 usage();
292 exit(1);
293 }
294
295 pinn = str2int(argv[0], &ok);
296 if (!ok)
297 fail("Invalid pin number: %s\n", argv[0]);
298
299 /*
300 * Read pin value
301 */
302 if (argc == 1) {
303 pinv = gpio_pin_get(handle, pinn);
304 if (pinv < 0) {
305 perror("gpio_pin_get");
306 exit(1);
307 }
308 printf("%d\n", pinv);
309 exit(0);
310 }
311
312 /* Is it valid number (0 or 1) ? */
313 pinv = str2int(argv[1], &ok);
314 if (!ok || ((pinv != 0) && (pinv != 1)))
315 fail("Invalid pin value: %s\n", argv[1]);
316
317 /*
318 * Set pin value
319 */
320 if (gpio_pin_set(handle, pinn, pinv) < 0) {
321 perror("gpio_pin_set");
322 exit(1);
323 }
324
325 gpio_close(handle);
326 exit(0);
327 }
328