]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/gpioctl/gpioctl.c
Remove spurious newline
[FreeBSD/FreeBSD.git] / usr.sbin / gpioctl / gpioctl.c
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 }