]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - usr.sbin/gpioctl/gpioctl.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / usr.sbin / gpioctl / gpioctl.c
1 /*-
2  * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <fcntl.h>
32 #include <getopt.h>
33 #include <paths.h>
34 #include <stdio.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
39
40 #include <sys/gpio.h>
41
42 struct flag_desc {
43         const char *name;
44         uint32_t flag;
45 };
46
47 static struct flag_desc gpio_flags[] = {
48         { "IN", GPIO_PIN_INPUT },
49         { "OUT", GPIO_PIN_OUTPUT },
50         { "OD", GPIO_PIN_OPENDRAIN },
51         { "PP", GPIO_PIN_PUSHPULL },
52         { "TS", GPIO_PIN_TRISTATE },
53         { "PU", GPIO_PIN_PULLUP },
54         { "PD", GPIO_PIN_PULLDOWN },
55         { "II", GPIO_PIN_INVIN },
56         { "IO", GPIO_PIN_INVOUT },
57         { "PULSE", GPIO_PIN_PULSATE },
58         { NULL, 0 },
59 };
60
61 int str2cap(const char *str);
62
63 static void
64 usage(void)
65 {
66         fprintf(stderr, "Usage:\n");
67         fprintf(stderr, "\tgpioctl [-f ctldev] -l [-v]\n");
68         fprintf(stderr, "\tgpioctl [-f ctldev] -t pin\n");
69         fprintf(stderr, "\tgpioctl [-f ctldev] -c pin flag ...\n");
70         fprintf(stderr, "\tgpioctl [-f ctldev] pin [0|1]\n");
71         exit(1);
72 }
73
74 static const char *
75 cap2str(uint32_t cap)
76 {
77         struct flag_desc * pdesc = gpio_flags;
78         while (pdesc->name) {
79                 if (pdesc->flag == cap)
80                         return pdesc->name;
81                 pdesc++;
82         }
83
84         return "UNKNOWN";
85 }
86
87 int
88 str2cap(const char *str)
89 {
90         struct flag_desc * pdesc = gpio_flags;
91         while (pdesc->name) {
92                 if (strcasecmp(str, pdesc->name) == 0)
93                         return pdesc->flag;
94                 pdesc++;
95         }
96
97         return (-1);
98 }
99
100 /*
101  * Our handmade function for converting string to number
102  */
103 static int 
104 str2int(const char *s, int *ok)
105 {
106         char *endptr;
107         int res = strtod(s, &endptr);
108         if (endptr != s + strlen(s) )
109                 *ok = 0;
110         else
111                 *ok = 1;
112
113         return res;
114 }
115
116 static void
117 print_caps(int caps)
118 {
119         int i, need_coma;
120
121         need_coma = 0;
122         printf("<");
123         for (i = 0; i < 32; i++) {
124                 if (caps & (1 << i)) {
125                         if (need_coma)
126                                 printf(",");
127                         printf("%s", cap2str(1 << i));
128                         need_coma = 1;
129                 }
130         }
131         printf(">");
132 }
133
134 static void
135 dump_pins(int fd, int verbose)
136 {
137         int i, maxpin;
138         struct gpio_pin pin;
139         struct gpio_req req;
140
141         if (ioctl(fd, GPIOMAXPIN, &maxpin) < 0) {
142                 perror("ioctl(GPIOMAXPIN)");
143                 exit(1);
144         }
145
146         for (i = 0; i <= maxpin; i++) {
147                 pin.gp_pin = i;
148                 if (ioctl(fd, GPIOGETCONFIG, &pin) < 0)
149                         /* For some reason this pin is inaccessible */
150                         continue;
151
152                 req.gp_pin = i;
153                 if (ioctl(fd, GPIOGET, &req) < 0) {
154                         /* Now, that's wrong */
155                         perror("ioctl(GPIOGET)");
156                         exit(1);
157                 }
158
159                 printf("pin %02d:\t%d\t%s", pin.gp_pin, req.gp_value, 
160                     pin.gp_name);
161
162                 print_caps(pin.gp_flags);
163
164                 if (verbose) {
165                         printf(", caps:");
166                         print_caps(pin.gp_caps);
167                 }
168                 printf("\n");
169         }
170 }
171
172 static void 
173 fail(const char *fmt, ...)
174 {
175         va_list ap;
176
177         va_start(ap, fmt);
178         vfprintf(stderr, fmt, ap);
179         va_end(ap);
180         exit(1);
181 }
182
183 int 
184 main(int argc, char **argv)
185 {
186         int i;
187         struct gpio_pin pin;
188         struct gpio_req req;
189         char defctlfile[] = _PATH_DEVGPIOC "0";
190         char *ctlfile = NULL;
191         int pinn, pinv, fd, ch;
192         int flags, flag, ok;
193         int config, toggle, verbose, list;
194
195         config = toggle = verbose = list = pinn = 0;
196
197         while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) {
198                 switch (ch) {
199                 case 'c':
200                         config = 1;
201                         pinn = str2int(optarg, &ok);
202                         if (!ok)
203                                 fail("Invalid pin number: %s\n", optarg);
204                         break;
205                 case 'f':
206                         ctlfile = optarg;
207                         break;
208                 case 'l':
209                         list = 1;
210                         break;
211                 case 't':
212                         toggle = 1;
213                         pinn = str2int(optarg, &ok);
214                         if (!ok)
215                                 fail("Invalid pin number: %s\n", optarg);
216                         break;
217                 case 'v':
218                         verbose = 1;
219                         break;
220                 default:
221                         usage();
222                         break;
223                 }
224         }
225         argv += optind;
226         argc -= optind;
227         if (ctlfile == NULL)
228                 ctlfile = defctlfile;
229
230         fd = open(ctlfile, O_RDONLY);
231         if (fd < 0) {
232                 perror("open");
233                 exit(1);
234         }
235
236         if (list) {
237                 dump_pins(fd, verbose);
238                 close(fd);
239                 exit(0);
240         }
241
242         if (toggle) {
243                 /*
244                  * -t pin assumes no additional arguments
245                  */
246                 if(argc > 0) {
247                         usage();
248                         exit(1);
249                 }
250
251                 req.gp_pin = pinn;
252                 if (ioctl(fd, GPIOTOGGLE, &req) < 0) {
253                         perror("ioctl(GPIOTOGGLE)");
254                         exit(1);
255                 }
256
257                 close(fd);
258                 exit (0);
259         }
260
261         if (config) {
262                 flags = 0;
263                 for (i = 0; i < argc; i++) {
264                         flag =  str2cap(argv[i]);
265                         if (flag < 0)
266                                 fail("Invalid flag: %s\n", argv[i]);
267                         flags |= flag;
268                 }
269
270                 pin.gp_pin = pinn;
271                 pin.gp_flags = flags;
272                 if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) {
273                         perror("ioctl(GPIOSETCONFIG)");
274                         exit(1);
275                 }
276
277                 exit(0);
278         }
279
280         /*
281          * Last two cases - set value or print value
282          */
283         if ((argc == 0) || (argc > 2)) {
284                 usage();
285                 exit(1);
286         }
287
288         pinn = str2int(argv[0], &ok);
289         if (!ok)
290                 fail("Invalid pin number: %s\n", argv[0]);
291
292         /*
293          * Read pin value
294          */
295         if (argc == 1) {
296                 req.gp_pin = pinn;
297                 if (ioctl(fd, GPIOGET, &req) < 0) {
298                         perror("ioctl(GPIOGET)");
299                         exit(1);
300                 }
301                 printf("%d\n", req.gp_value);
302                 exit (0);
303         }
304
305         /* Is it valid number (0 or 1) ? */
306         pinv = str2int(argv[1], &ok);
307         if (!ok || ((pinv != 0) && (pinv != 1)))
308                 fail("Invalid pin value: %s\n", argv[1]);
309
310         /*
311          * Set pin value
312          */
313         req.gp_pin = pinn;
314         req.gp_value = pinv;
315         if (ioctl(fd, GPIOSET, &req) < 0) {
316                 perror("ioctl(GPIOSET)");
317                 exit(1);
318         }
319
320         close(fd);
321         exit(0);
322 }