]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/gpioctl/gpioctl.c
Merge llvm-project release/18.x llvmorg-18.1.1-0-gdba2a75e9c7e
[FreeBSD/FreeBSD.git] / usr.sbin / gpioctl / gpioctl.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 #include <fcntl.h>
34 #include <getopt.h>
35 #include <paths.h>
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include <libgpio.h>
43
44 #define PIN_TYPE_NUMBER         1
45 #define PIN_TYPE_NAME           2
46
47 struct flag_desc {
48         const char *name;
49         uint32_t flag;
50 };
51
52 static struct flag_desc gpio_flags[] = {
53         { "IN", GPIO_PIN_INPUT },
54         { "OUT", GPIO_PIN_OUTPUT },
55         { "OD", GPIO_PIN_OPENDRAIN },
56         { "PP", GPIO_PIN_PUSHPULL },
57         { "TS", GPIO_PIN_TRISTATE },
58         { "PU", GPIO_PIN_PULLUP },
59         { "PD", GPIO_PIN_PULLDOWN },
60         { "II", GPIO_PIN_INVIN },
61         { "IO", GPIO_PIN_INVOUT },
62         { "PULSE", GPIO_PIN_PULSATE },
63         { "INTRLL", GPIO_INTR_LEVEL_LOW},
64         { "INTRLH", GPIO_INTR_LEVEL_HIGH},
65         { "INTRER", GPIO_INTR_EDGE_RISING},
66         { "INTREF", GPIO_INTR_EDGE_FALLING},
67         { "INTREB", GPIO_INTR_EDGE_BOTH},
68         { NULL, 0 },
69 };
70
71 int str2cap(const char *str);
72
73 static void
74 usage(void)
75 {
76         fprintf(stderr, "Usage:\n");
77         fprintf(stderr, "\tgpioctl [-f ctldev] -l [-v]\n");
78         fprintf(stderr, "\tgpioctl [-f ctldev] [-pN] -t pin\n");
79         fprintf(stderr, "\tgpioctl [-f ctldev] [-pN] -c pin flag ...\n");
80         fprintf(stderr, "\tgpioctl [-f ctldev] [-pN] -n pin pin-name\n");
81         fprintf(stderr, "\tgpioctl [-f ctldev] [-pN] pin [0|1]\n");
82         exit(1);
83 }
84
85 static const char *
86 cap2str(uint32_t cap)
87 {
88         struct flag_desc * pdesc = gpio_flags;
89         while (pdesc->name) {
90                 if (pdesc->flag == cap)
91                         return pdesc->name;
92                 pdesc++;
93         }
94
95         return "UNKNOWN";
96 }
97
98 int
99 str2cap(const char *str)
100 {
101         struct flag_desc * pdesc = gpio_flags;
102         while (pdesc->name) {
103                 if (strcasecmp(str, pdesc->name) == 0)
104                         return pdesc->flag;
105                 pdesc++;
106         }
107
108         return (-1);
109 }
110
111 /*
112  * Our handmade function for converting string to number
113  */
114 static int
115 str2int(const char *s, int *ok)
116 {
117         char *endptr;
118         int res = strtod(s, &endptr);
119         if (endptr != s + strlen(s) )
120                 *ok = 0;
121         else
122                 *ok = 1;
123
124         return res;
125 }
126
127 static void
128 print_caps(int caps)
129 {
130         int i, need_coma;
131
132         need_coma = 0;
133         printf("<");
134         for (i = 0; i < 32; i++) {
135                 if (caps & (1 << i)) {
136                         if (need_coma)
137                                 printf(",");
138                         printf("%s", cap2str(1 << i));
139                         need_coma = 1;
140                 }
141         }
142         printf(">");
143 }
144
145 static void
146 dump_pins(gpio_handle_t handle, int verbose)
147 {
148         int i, maxpin, pinv;
149         gpio_config_t *cfgs;
150         gpio_config_t *pin;
151
152         maxpin = gpio_pin_list(handle, &cfgs);
153         if (maxpin < 0) {
154                 perror("gpio_pin_list");
155                 exit(1);
156         }
157
158         for (i = 0; i <= maxpin; i++) {
159                 pin = cfgs + i;
160                 pinv = gpio_pin_get(handle, pin->g_pin);
161                 printf("pin %02d:\t%d\t%s", pin->g_pin, pinv,
162                     pin->g_name);
163
164                 print_caps(pin->g_flags);
165
166                 if (verbose) {
167                         printf(", caps:");
168                         print_caps(pin->g_caps);
169                 }
170                 printf("\n");
171         }
172         free(cfgs);
173 }
174
175 static int
176 get_pinnum_by_name(gpio_handle_t handle, const char *name) {
177         int i, maxpin, pinn;
178         gpio_config_t *cfgs;
179         gpio_config_t *pin;
180
181         pinn = -1;
182         maxpin = gpio_pin_list(handle, &cfgs);
183         if (maxpin < 0) {
184                 perror("gpio_pin_list");
185                 exit(1);
186         }
187
188         for (i = 0; i <= maxpin; i++) {
189                 pin = cfgs + i;
190                 gpio_pin_get(handle, pin->g_pin);
191                 if (!strcmp(name, pin->g_name)) {
192                         pinn = i;
193                         break;
194                 }
195         }
196         free(cfgs);
197
198         return pinn;
199 }
200
201 static void
202 fail(const char *fmt, ...)
203 {
204         va_list ap;
205
206         va_start(ap, fmt);
207         vfprintf(stderr, fmt, ap);
208         va_end(ap);
209         exit(1);
210 }
211
212 int
213 main(int argc, char **argv)
214 {
215         int i;
216         gpio_config_t pin;
217         gpio_handle_t handle;
218         char *ctlfile = NULL;
219         int pinn, pinv, pin_type, ch;
220         int flags, flag, ok;
221         int config, list, name, toggle, verbose;
222
223         config = toggle = verbose = list = name = pin_type = 0;
224
225         while ((ch = getopt(argc, argv, "cf:lntvNp")) != -1) {
226                 switch (ch) {
227                 case 'c':
228                         config = 1;
229                         break;
230                 case 'f':
231                         ctlfile = optarg;
232                         break;
233                 case 'l':
234                         list = 1;
235                         break;
236                 case 'n':
237                         name = 1;
238                         break;
239                 case 'N':
240                         pin_type = PIN_TYPE_NAME;
241                         break;
242                 case'p':
243                         pin_type = PIN_TYPE_NUMBER;
244                         break;
245                 case 't':
246                         toggle = 1;
247                         break;
248                 case 'v':
249                         verbose = 1;
250                         break;
251                 default:
252                         usage();
253                         break;
254                 }
255         }
256         argv += optind;
257         argc -= optind;
258         if (ctlfile == NULL)
259                 handle = gpio_open(0);
260         else
261                 handle = gpio_open_device(ctlfile);
262         if (handle == GPIO_INVALID_HANDLE) {
263                 perror("gpio_open");
264                 exit(1);
265         }
266
267         if (list) {
268                 dump_pins(handle, verbose);
269                 gpio_close(handle);
270                 exit(0);
271         }
272
273         if (argc == 0)
274                 usage();
275
276         /* Find the pin number by the name */
277         switch (pin_type) {
278         default:
279                 /* First test if it is a pin number */
280                 pinn = str2int(argv[0], &ok);
281                 if (ok) {
282                         /* Test if we have any pin named by this number and tell the user */
283                         if (get_pinnum_by_name(handle, argv[0]) != -1)
284                                 fail("%s is also a pin name, use -p or -N\n", argv[0]);
285                 } else {
286                         /* Test if it is a name */
287                         if ((pinn = get_pinnum_by_name(handle, argv[0])) == -1)
288                                 fail("Can't find pin named \"%s\"\n", argv[0]);
289                 }
290                 break;
291         case PIN_TYPE_NUMBER:
292                 pinn = str2int(argv[0], &ok);
293                 if (!ok)
294                         fail("Invalid pin number: %s\n", argv[0]);
295                 break;
296         case PIN_TYPE_NAME:
297                 if ((pinn = get_pinnum_by_name(handle, argv[0])) == -1)
298                         fail("Can't find pin named \"%s\"\n", argv[0]);
299                 break;
300         }
301
302         /* Set the pin name. */
303         if (name) {
304                 if (argc != 2)
305                         usage();
306                 if (gpio_pin_set_name(handle, pinn, argv[1]) < 0) {
307                         perror("gpio_pin_set_name");
308                         exit(1);
309                 }
310                 exit(0);
311         }
312
313         if (toggle) {
314                 /*
315                 * -t pin assumes no additional arguments
316                 */
317                 if (argc > 1)
318                         usage();
319                 if (gpio_pin_toggle(handle, pinn) < 0) {
320                         perror("gpio_pin_toggle");
321                         exit(1);
322                 }
323                 gpio_close(handle);
324                 exit(0);
325         }
326
327         if (config) {
328                 flags = 0;
329                 for (i = 1; i < argc; i++) {
330                         flag =  str2cap(argv[i]);
331                         if (flag < 0)
332                                 fail("Invalid flag: %s\n", argv[i]);
333                         else if ((flag & GPIO_INTR_MASK) != 0)
334                                 fail("Interrupt capability %s cannot be set as configuration flag\n", argv[i]);
335                         flags |= flag;
336                 }
337                 pin.g_pin = pinn;
338                 pin.g_flags = flags;
339                 if (gpio_pin_set_flags(handle, &pin) < 0) {
340                         perror("gpio_pin_set_flags");
341                         exit(1);
342                 }
343                 exit(0);
344         }
345
346         /*
347          * Last two cases - set value or print value
348          */
349         if ((argc == 0) || (argc > 2))
350                 usage();
351
352         /*
353          * Read pin value
354          */
355         if (argc == 1) {
356                 pinv = gpio_pin_get(handle, pinn);
357                 if (pinv < 0) {
358                         perror("gpio_pin_get");
359                         exit(1);
360                 }
361                 printf("%d\n", pinv);
362                 exit(0);
363         }
364
365         /* Is it valid number (0 or 1) ? */
366         pinv = str2int(argv[1], &ok);
367         if (ok == 0 || ((pinv != 0) && (pinv != 1)))
368                 fail("Invalid pin value: %s\n", argv[1]);
369
370         /*
371          * Set pin value
372          */
373         if (gpio_pin_set(handle, pinn, pinv) < 0) {
374                 perror("gpio_pin_set");
375                 exit(1);
376         }
377
378         gpio_close(handle);
379         exit(0);
380 }