]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.sbin/gpioctl/gpioctl.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.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 <stdio.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include <sys/gpio.h>
40
41 struct flag_desc {
42         const char *name;
43         uint32_t flag;
44 };
45
46 struct flag_desc gpio_flags[] = {
47         { "IN", GPIO_PIN_INPUT },
48         { "OUT", GPIO_PIN_OUTPUT },
49         { "OD", GPIO_PIN_OPENDRAIN },
50         { "PP", GPIO_PIN_PUSHPULL },
51         { "TS", GPIO_PIN_TRISTATE },
52         { "PU", GPIO_PIN_PULLUP },
53         { "PD", GPIO_PIN_PULLDOWN },
54         { "II", GPIO_PIN_INVIN },
55         { "IO", GPIO_PIN_INVOUT },
56         { "PULSE", GPIO_PIN_PULSATE },
57         { NULL, 0 },
58 };
59
60 int str2cap(const char *str);
61
62 static void
63 usage(void)
64 {
65         fprintf(stderr, "Usage:\n");
66         fprintf(stderr, "\tgpioctl -f ctldev -l [-v]\n");
67         fprintf(stderr, "\tgpioctl -f ctldev -t pin\n");
68         fprintf(stderr, "\tgpioctl -f ctldev -c pin flag ...\n");
69         fprintf(stderr, "\tgpioctl -f ctldev pin [0|1]\n");
70         exit(1);
71 }
72
73 static const char *
74 cap2str(uint32_t cap)
75 {
76         struct flag_desc * pdesc = gpio_flags;
77         while (pdesc->name) {
78                 if (pdesc->flag == cap)
79                         return pdesc->name;
80                 pdesc++;
81         }
82
83         return "UNKNOWN";
84 }
85
86 int
87 str2cap(const char *str)
88 {
89         struct flag_desc * pdesc = gpio_flags;
90         while (pdesc->name) {
91                 if (strcasecmp(str, pdesc->name) == 0)
92                         return pdesc->flag;
93                 pdesc++;
94         }
95
96         return (-1);
97 }
98
99 /*
100  * Our handmade function for converting string to number
101  */
102 static int 
103 str2int(const char *s, int *ok)
104 {
105         char *endptr;
106         int res = strtod(s, &endptr);
107         if (endptr != s + strlen(s) )
108                 *ok = 0;
109         else
110                 *ok = 1;
111
112         return res;
113 }
114
115 static void
116 print_caps(int caps)
117 {
118         int i, need_coma;
119
120         need_coma = 0;
121         printf("<");
122         for (i = 0; i < 32; i++) {
123                 if (caps & (1 << i)) {
124                         if (need_coma)
125                                 printf(",");
126                         printf("%s", cap2str(1 << i));
127                         need_coma = 1;
128                 }
129         }
130         printf(">");
131 }
132
133 static void
134 dump_pins(int fd, int verbose)
135 {
136         int i, maxpin;
137         struct gpio_pin pin;
138         struct gpio_req req;
139
140         if (ioctl(fd, GPIOMAXPIN, &maxpin) < 0) {
141                 perror("ioctl(GPIOMAXPIN)");
142                 exit(1);
143         }
144
145         for (i = 0; i <= maxpin; i++) {
146                 pin.gp_pin = i;
147                 if (ioctl(fd, GPIOGETCONFIG, &pin) < 0)
148                         /* For some reason this pin is inaccessible */
149                         continue;
150
151                 req.gp_pin = i;
152                 if (ioctl(fd, GPIOGET, &req) < 0) {
153                         /* Now, that's wrong */
154                         perror("ioctl(GPIOGET)");
155                         exit(1);
156                 }
157
158                 printf("pin %02d:\t%d\t%s", pin.gp_pin, req.gp_value, 
159                     pin.gp_name);
160
161                 print_caps(pin.gp_flags);
162
163                 if (verbose) {
164                         printf(", caps:");
165                         print_caps(pin.gp_caps);
166                 }
167                 printf("\n");
168         }
169 }
170
171 static void 
172 fail(const char *fmt, ...)
173 {
174         va_list ap;
175
176         va_start(ap, fmt);
177         vfprintf(stderr, fmt, ap);
178         va_end(ap);
179         exit(1);
180 }
181
182 int 
183 main(int argc, char **argv)
184 {
185         int i;
186         struct gpio_pin pin;
187         struct gpio_req req;
188         char *ctlfile = NULL;
189         int pinn, pinv, fd, ch;
190         int flags, flag, ok;
191         int config, toggle, verbose, list;
192
193         config = toggle = verbose = list = pinn = 0;
194
195         while ((ch = getopt(argc, argv, "c:f:lt:v")) != -1) {
196                 switch (ch) {
197                 case 'c':
198                         config = 1;
199                         pinn = str2int(optarg, &ok);
200                         if (!ok)
201                                 fail("Invalid pin number: %s\n", optarg);
202                         break;
203                 case 'f':
204                         ctlfile = optarg;
205                         break;
206                 case 'l':
207                         list = 1;
208                         break;
209                 case 't':
210                         toggle = 1;
211                         pinn = str2int(optarg, &ok);
212                         if (!ok)
213                                 fail("Invalid pin number: %s\n", optarg);
214                         break;
215                 case 'v':
216                         verbose = 1;
217                         break;
218                 default:
219                         usage();
220                         break;
221                 }
222         }
223         argv += optind;
224         argc -= optind;
225         for (i = 0; i < argc; i++)
226                 printf("%d/%s\n", i, argv[i]);
227
228         if (ctlfile == NULL)
229                 fail("No gpioctl device provided\n");
230
231         fd = open(ctlfile, O_RDONLY);
232         if (fd < 0) {
233                 perror("open");
234                 exit(1);
235         }
236
237         if (list) {
238                 dump_pins(fd, verbose);
239                 close(fd);
240                 exit(0);
241         }
242
243         if (toggle) {
244                 /*
245                  * -t pin assumes no additional arguments
246                  */
247                 if(argc > 0) {
248                         usage();
249                         exit(1);
250                 }
251
252                 req.gp_pin = pinn;
253                 if (ioctl(fd, GPIOTOGGLE, &req) < 0) {
254                         perror("ioctl(GPIOTOGGLE)");
255                         exit(1);
256                 }
257
258                 close(fd);
259                 exit (0);
260         }
261
262         if (config) {
263                 flags = 0;
264                 for (i = 0; i < argc; i++) {
265                         flag =  str2cap(argv[i]);
266                         if (flag < 0)
267                                 fail("Invalid flag: %s\n", argv[i]);
268                         flags |= flag;
269                 }
270
271                 pin.gp_pin = pinn;
272                 pin.gp_flags = flags;
273                 if (ioctl(fd, GPIOSETCONFIG, &pin) < 0) {
274                         perror("ioctl(GPIOSETCONFIG)");
275                         exit(1);
276                 }
277
278                 exit(0);
279         }
280
281         /*
282          * Last two cases - set value or print value
283          */
284         if ((argc == 0) || (argc > 2)) {
285                 usage();
286                 exit(1);
287         }
288
289         pinn = str2int(argv[0], &ok);
290         if (!ok)
291                 fail("Invalid pin number: %s\n", argv[0]);
292
293         /*
294          * Read pin value
295          */
296         if (argc == 1) {
297                 req.gp_pin = pinn;
298                 if (ioctl(fd, GPIOGET, &req) < 0) {
299                         perror("ioctl(GPIOGET)");
300                         exit(1);
301                 }
302                 printf("%d\n", req.gp_value);
303                 exit (0);
304         }
305
306         /* Is it valid number (0 or 1) ? */
307         pinv = str2int(argv[1], &ok);
308         if (!ok || ((pinv != 0) && (pinv != 1)))
309                 fail("Invalid pin value: %s\n", argv[1]);
310
311         /*
312          * Set pin value
313          */
314         req.gp_pin = pinn;
315         req.gp_value = pinv;
316         if (ioctl(fd, GPIOSET, &req) < 0) {
317                 perror("ioctl(GPIOSET)");
318                 exit(1);
319         }
320
321         close(fd);
322         exit(0);
323 }