gpioctl.c revision 1.14 1 /* $NetBSD: gpioctl.c,v 1.14 2011/10/02 09:33:19 mbalmer Exp $ */
2
3 /*
4 * Copyright (c) 2008, 2010, 2011 Marc Balmer <mbalmer (at) NetBSD.org>
5 * Copyright (c) 2004 Alexander Yurchenko <grange (at) openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 /*
21 * Program to control GPIO devices.
22 */
23
24 #include <sys/types.h>
25 #include <sys/gpio.h>
26 #include <sys/ioctl.h>
27
28 #include <err.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <limits.h>
32 #include <paths.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <time.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 static char *dev;
40 static int devfd = -1;
41 static int quiet = 0;
42
43 static void getinfo(void);
44 static void gpioread(int, char *);
45 static void gpiowrite(int, char *, int);
46 static void gpiopulse(int, char *, double, double);
47 static void gpioset(int pin, char *name, int flags, char *alias);
48 static void gpiounset(int pin, char *name);
49 static void devattach(char *, int, uint32_t, uint32_t);
50 static void devdetach(char *);
51 __dead static void usage(void);
52
53 extern long long strtonum(const char *numstr, long long minval,
54 long long maxval, const char **errstrp);
55
56 static const struct bitstr {
57 unsigned int mask;
58 const char *string;
59 } pinflags[] = {
60 { GPIO_PIN_INPUT, "in" },
61 { GPIO_PIN_OUTPUT, "out" },
62 { GPIO_PIN_INOUT, "inout" },
63 { GPIO_PIN_OPENDRAIN, "od" },
64 { GPIO_PIN_PUSHPULL, "pp" },
65 { GPIO_PIN_TRISTATE, "tri" },
66 { GPIO_PIN_PULLUP, "pu" },
67 { GPIO_PIN_PULLDOWN, "pd" },
68 { GPIO_PIN_INVIN, "iin" },
69 { GPIO_PIN_INVOUT, "iout" },
70 { GPIO_PIN_PULSATE, "pulsate" },
71 { 0, NULL },
72 };
73
74 int
75 main(int argc, char *argv[])
76 {
77 const struct bitstr *bs;
78 double freq, dc;
79 int pin, ch, n, fl = 0, value = 0;
80 const char *errstr;
81 char *ep;
82 int ga_offset = -1;
83 uint32_t ga_mask = 0;
84 uint32_t ga_flags = 0;
85 long lval;
86 char *nam = NULL;
87 char *flags;
88 char devn[32];
89
90 while ((ch = getopt(argc, argv, "q")) != -1)
91 switch (ch) {
92 case 'q':
93 quiet = 1;
94 break;
95 default:
96 usage();
97 /* NOTREACHED */
98 }
99 argc -= optind;
100 argv += optind;
101
102 if (argc < 1)
103 usage();
104 dev = argv[0];
105
106 freq = dc = 0.0;
107
108 if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) {
109 (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev);
110 dev = devn;
111 }
112
113 if ((devfd = open(dev, O_RDWR)) == -1)
114 err(EXIT_FAILURE, "%s", dev);
115
116 if (argc == 1) {
117 getinfo();
118 return EXIT_SUCCESS;
119 }
120
121 if (!strcmp(argv[1], "attach")) {
122 char *driver, *offset, *mask;
123
124 if (argc != 5 && argc != 6)
125 usage();
126
127 driver = argv[2];
128 offset = argv[3];
129 mask = argv[4];
130 flags = argc == 6 ? argv[5] : NULL;
131
132 ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
133 if (errstr)
134 errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset);
135 lval = strtol(mask, &ep, 0);
136 if (*mask == '\0' || *ep != '\0')
137 errx(EXIT_FAILURE, "invalid mask (not a number)");
138 if ((errno == ERANGE && (lval == LONG_MAX
139 || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX)
140 errx(EXIT_FAILURE, "mask out of range");
141 ga_mask = lval;
142 if (flags != NULL) {
143 lval = strtol(flags, &ep, 0);
144 if (*flags == '\0' || *ep != '\0')
145 errx(EXIT_FAILURE,
146 "invalid flags (not a number)");
147 if ((errno == ERANGE && (lval == LONG_MAX
148 || lval == LONG_MIN))
149 || (unsigned long)lval > UINT_MAX)
150 errx(EXIT_FAILURE, "flags out of range");
151 ga_flags = lval;
152 }
153 devattach(driver, ga_offset, ga_mask, ga_flags);
154 return EXIT_SUCCESS;
155 } else if (!strcmp(argv[1], "detach")) {
156 if (argc != 3)
157 usage();
158 devdetach(argv[2]);
159 } else {
160 char *nm = NULL;
161
162 /* expecting a pin number or name */
163 pin = strtonum(argv[1], 0, INT_MAX, &errstr);
164 if (errstr)
165 nm = argv[1]; /* try named pin */
166 if (argc > 2) {
167 if (!strcmp(argv[2], "set")) {
168 for (n = 3; n < argc; n++) {
169 for (bs = pinflags; bs->string != NULL;
170 bs++) {
171 if (!strcmp(argv[n],
172 bs->string)) {
173 fl |= bs->mask;
174 break;
175 }
176 }
177 if (bs->string == NULL)
178 nam = argv[n];
179 }
180 gpioset(pin, nm, fl, nam);
181 } else if (!strcmp(argv[2], "unset")) {
182 gpiounset(pin, nm);
183 } else if (!strcmp(argv[2], "pulse")) {
184 if (argc == 4) {
185 freq = atof(argv[3]);
186 dc = 50.0;
187 } else if (argc == 5) {
188 freq = atof(argv[3]);
189 dc = atof(argv[4]);
190 } else
191 freq = dc = 0.0;
192 gpiopulse(pin, nm, freq, dc);
193 } else {
194 value = strtonum(argv[2], INT_MIN, INT_MAX,
195 &errstr);
196 if (errstr) {
197 if (!strcmp(argv[2], "on"))
198 value = GPIO_PIN_HIGH;
199 else if (!strcmp(argv[2], "off"))
200 value = GPIO_PIN_LOW;
201 else if (!strcmp(argv[2], "toggle"))
202 value = 2;
203 else
204 errx(EXIT_FAILURE,
205 "%s: invalid value",
206 argv[2]);
207 }
208 gpiowrite(pin, nm, value);
209 }
210 } else
211 gpioread(pin, nm);
212 }
213
214 return EXIT_SUCCESS;
215 }
216
217 static void
218 getinfo(void)
219 {
220 struct gpio_info info;
221
222 if (ioctl(devfd, GPIOINFO, &info) == -1)
223 err(EXIT_FAILURE, "GPIOINFO");
224
225 if (quiet)
226 return;
227
228 printf("%s: %d pins\n", dev, info.gpio_npins);
229 }
230
231 static void
232 gpioread(int pin, char *gp_name)
233 {
234 struct gpio_req req;
235
236 memset(&req, 0, sizeof(req));
237 if (gp_name != NULL)
238 strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
239 else
240 req.gp_pin = pin;
241
242 if (ioctl(devfd, GPIOREAD, &req) == -1)
243 err(EXIT_FAILURE, "GPIOREAD");
244
245 if (quiet)
246 return;
247
248 if (gp_name)
249 printf("pin %s: state %d\n", gp_name, req.gp_value);
250 else
251 printf("pin %d: state %d\n", pin, req.gp_value);
252 }
253
254 static void
255 gpiowrite(int pin, char *gp_name, int value)
256 {
257 struct gpio_req req;
258
259 if (value < 0 || value > 2)
260 errx(EXIT_FAILURE, "%d: invalid value", value);
261
262 memset(&req, 0, sizeof(req));
263 if (gp_name != NULL)
264 strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
265 else
266 req.gp_pin = pin;
267
268 if (value == GPIO_PIN_HIGH || value == GPIO_PIN_LOW) {
269 req.gp_value = value;
270 if (ioctl(devfd, GPIOWRITE, &req) == -1)
271 err(EXIT_FAILURE, "GPIOWRITE");
272 } else {
273 if (ioctl(devfd, GPIOTOGGLE, &req) == -1)
274 err(EXIT_FAILURE, "GPIOTOGGLE");
275 }
276
277 if (quiet)
278 return;
279
280 if (gp_name)
281 printf("pin %s: state %d -> %d\n", gp_name, req.gp_value,
282 (value < 2 ? value : 1 - req.gp_value));
283 else
284 printf("pin %d: state %d -> %d\n", pin, req.gp_value,
285 (value < 2 ? value : 1 - req.gp_value));
286 }
287
288 static void
289 gpiopulse(int pin, char *gp_name, double freq, double dc)
290 {
291 struct gpio_pulse pulse;
292 suseconds_t period, on, off;
293
294 if (freq < 0.0 || (dc < 0.0 || dc >= 100.0))
295 errx(EXIT_FAILURE, "%.f Hz, %.f%% duty cycle: invalid value",
296 freq, dc);
297
298 memset(&pulse, 0, sizeof(pulse));
299 if (gp_name != NULL)
300 strlcpy(pulse.gp_name, gp_name, sizeof(pulse.gp_name));
301 else
302 pulse.gp_pin = pin;
303
304 if (freq > 0.0 && dc > 0.0) {
305 period = 1000000 / freq;
306 on = period * dc / 100;
307 off = period - on;
308
309 if (on >= 1000000) {
310 pulse.gp_pulse_on.tv_sec = on / 1000000;
311 on -= pulse.gp_pulse_on.tv_sec * 1000000;
312 pulse.gp_pulse_on.tv_usec = on;
313 } else {
314 pulse.gp_pulse_on.tv_sec = 0;
315 pulse.gp_pulse_on.tv_usec = on;
316 }
317 if (off >= 1000000) {
318 pulse.gp_pulse_off.tv_sec = off / 1000000;
319 off -= pulse.gp_pulse_off.tv_sec * 1000000;
320 pulse.gp_pulse_off.tv_usec = off;
321 } else {
322 pulse.gp_pulse_off.tv_sec = 0;
323 pulse.gp_pulse_off.tv_usec = off;
324 }
325 } else { /* gpio(4) defaults */
326 freq = 1.0;
327 dc = 50.0;
328 }
329
330 if (ioctl(devfd, GPIOPULSE, &pulse) == -1)
331 err(EXIT_FAILURE, "GPIOPULSE");
332
333 if (quiet)
334 return;
335
336 if (gp_name)
337 printf("pin %s: pulse at %.f Hz with a %.f%% duty cylce\n",
338 gp_name, freq, dc);
339 else
340 printf("pin %d: pulse at %.f Hz with a %.f%% duty cylce\n",
341 pin, freq, dc);
342 }
343
344 static void
345 gpioset(int pin, char *name, int fl, char *alias)
346 {
347 struct gpio_set set;
348 const struct bitstr *bs;
349
350 memset(&set, 0, sizeof(set));
351 if (name != NULL)
352 strlcpy(set.gp_name, name, sizeof(set.gp_name));
353 else
354 set.gp_pin = pin;
355 set.gp_flags = fl;
356
357 if (alias != NULL)
358 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
359
360 if (ioctl(devfd, GPIOSET, &set) == -1)
361 err(EXIT_FAILURE, "GPIOSET");
362
363 if (quiet)
364 return;
365
366 if (name != NULL)
367 printf("pin %s: caps:", name);
368 else
369 printf("pin %d: caps:", pin);
370 for (bs = pinflags; bs->string != NULL; bs++)
371 if (set.gp_caps & bs->mask)
372 printf(" %s", bs->string);
373 printf(", flags:");
374 for (bs = pinflags; bs->string != NULL; bs++)
375 if (set.gp_flags & bs->mask)
376 printf(" %s", bs->string);
377 if (fl > 0) {
378 printf(" ->");
379 for (bs = pinflags; bs->string != NULL; bs++)
380 if (fl & bs->mask)
381 printf(" %s", bs->string);
382 }
383 printf("\n");
384 }
385
386 static void
387 gpiounset(int pin, char *name)
388 {
389 struct gpio_set set;
390
391 memset(&set, 0, sizeof(set));
392 if (name != NULL)
393 strlcpy(set.gp_name, name, sizeof(set.gp_name));
394 else
395 set.gp_pin = pin;
396
397 if (ioctl(devfd, GPIOUNSET, &set) == -1)
398 err(EXIT_FAILURE, "GPIOUNSET");
399 }
400
401 static void
402 devattach(char *dvname, int offset, uint32_t mask, uint32_t flags)
403 {
404 struct gpio_attach attach;
405
406 memset(&attach, 0, sizeof(attach));
407 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
408 attach.ga_offset = offset;
409 attach.ga_mask = mask;
410 attach.ga_flags = flags;
411 if (ioctl(devfd, GPIOATTACH, &attach) == -1)
412 err(EXIT_FAILURE, "GPIOATTACH");
413 }
414
415 static void
416 devdetach(char *dvname)
417 {
418 struct gpio_attach attach;
419
420 memset(&attach, 0, sizeof(attach));
421 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
422 if (ioctl(devfd, GPIODETACH, &attach) == -1)
423 err(EXIT_FAILURE, "GPIODETACH");
424 }
425
426 static void
427 usage(void)
428 {
429 const char *progname;
430
431 progname = getprogname();
432 fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | "
433 "on | off | toggle]\n", progname);
434 fprintf(stderr, "usage: %s [-q] device pin pulse [frequency "
435 "[duty cycle]]\n", progname);
436 fprintf(stderr, " %s [-q] device pin set [flags] [name]\n",
437 progname);
438 fprintf(stderr, " %s [-q] device pin unset\n", progname);
439 fprintf(stderr, " %s [-q] device attach device offset mask "
440 "[flags]\n",
441 progname);
442 fprintf(stderr, " %s [-q] device detach device\n", progname);
443
444 exit(EXIT_FAILURE);
445 }
446