]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/gpioctl/gpioctl.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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         for (i = 0; i < argc; i++)
228                 printf("%d/%s\n", i, argv[i]);
229
230         if (ctlfile == NULL)
231                 ctlfile = defctlfile;
232
233         fd = open(ctlfile, O_RDONLY);
234         if (fd < 0) {
235                 perror("open");
236                 exit(1);
237         }
238
239         if (list) {
240                 dump_pins(fd, verbose);
241                 close(fd);
242                 exit(0);
243         }
244
245         if (toggle) {
246                 /*
247                  * -t pin assumes no additional arguments
248                  */
249                 if(argc > 0) {
250                         usage();
251                         exit(1);
252                 }
253
254                 req.gp_pin = pinn;
255                 if (ioctl(fd, GPIOTOGGLE, &req) < 0) {
256                         perror("ioctl(GPIOTOGGLE)");
257                         exit(1);
258                 }
259
260                 close(fd);
261                 exit (0);
262         }
263
264         if (config) {
265                 flags = 0;
266                 for (i = 0; i < argc; i++) {
267                         flag =  str2cap(argv[i]);
268                         if (flag < 0)
269                                 fail("Invalid flag: %s\n", argv[i]);
270                         flags |= flag;
271                 }
272
273                 pin.gp_pin = pinn;
274                 pin.gp_flags = flags;
275                 if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) {
276                         perror("ioctl(GPIOSETCONFIG)");
277                         exit(1);
278                 }
279
280                 exit(0);
281         }
282
283         /*
284          * Last two cases - set value or print value
285          */
286         if ((argc == 0) || (argc > 2)) {
287                 usage();
288                 exit(1);
289         }
290
291         pinn = str2int(argv[0], &ok);
292         if (!ok)
293                 fail("Invalid pin number: %s\n", argv[0]);
294
295         /*
296          * Read pin value
297          */
298         if (argc == 1) {
299                 req.gp_pin = pinn;
300                 if (ioctl(fd, GPIOGET, &req) < 0) {
301                         perror("ioctl(GPIOGET)");
302                         exit(1);
303                 }
304                 printf("%d\n", req.gp_value);
305                 exit (0);
306         }
307
308         /* Is it valid number (0 or 1) ? */
309         pinv = str2int(argv[1], &ok);
310         if (!ok || ((pinv != 0) && (pinv != 1)))
311                 fail("Invalid pin value: %s\n", argv[1]);
312
313         /*
314          * Set pin value
315          */
316         req.gp_pin = pinn;
317         req.gp_value = pinv;
318         if (ioctl(fd, GPIOSET, &req) < 0) {
319                 perror("ioctl(GPIOSET)");
320                 exit(1);
321         }
322
323         close(fd);
324         exit(0);
325 }