gpioctl.c revision 1.13 1 /* $NetBSD: gpioctl.c,v 1.13 2011/09/15 11:46:32 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);
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 long lval;
85 char *nam = NULL;
86 char devn[32];
87
88 while ((ch = getopt(argc, argv, "q")) != -1)
89 switch (ch) {
90 case 'q':
91 quiet = 1;
92 break;
93 default:
94 usage();
95 /* NOTREACHED */
96 }
97 argc -= optind;
98 argv += optind;
99
100 if (argc < 1)
101 usage();
102 dev = argv[0];
103
104 freq = dc = 0.0;
105
106 if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) {
107 (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev);
108 dev = devn;
109 }
110
111 if ((devfd = open(dev, O_RDWR)) == -1)
112 err(EXIT_FAILURE, "%s", dev);
113
114 if (argc == 1) {
115 getinfo();
116 return EXIT_SUCCESS;
117 }
118
119 if (!strcmp(argv[1], "attach")) {
120 char *driver, *offset, *mask;
121
122 if (argc != 5)
123 usage();
124
125 driver = argv[2];
126 offset = argv[3];
127 mask = argv[4];
128
129 ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
130 if (errstr)
131 errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset);
132 lval = strtol(mask, &ep, 0);
133 if (*mask == '\0' || *ep != '\0')
134 errx(EXIT_FAILURE, "invalid mask (not a number)");
135 if ((errno == ERANGE && (lval == LONG_MAX
136 || lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX)
137 errx(EXIT_FAILURE, "mask out of range");
138 ga_mask = lval;
139 devattach(driver, ga_offset, ga_mask);
140 return EXIT_SUCCESS;
141 } else if (!strcmp(argv[1], "detach")) {
142 if (argc != 3)
143 usage();
144 devdetach(argv[2]);
145 } else {
146 char *nm = NULL;
147
148 /* expecting a pin number or name */
149 pin = strtonum(argv[1], 0, INT_MAX, &errstr);
150 if (errstr)
151 nm = argv[1]; /* try named pin */
152 if (argc > 2) {
153 if (!strcmp(argv[2], "set")) {
154 for (n = 3; n < argc; n++) {
155 for (bs = pinflags; bs->string != NULL;
156 bs++) {
157 if (!strcmp(argv[n],
158 bs->string)) {
159 fl |= bs->mask;
160 break;
161 }
162 }
163 if (bs->string == NULL)
164 nam = argv[n];
165 }
166 gpioset(pin, nm, fl, nam);
167 } else if (!strcmp(argv[2], "unset")) {
168 gpiounset(pin, nm);
169 } else if (!strcmp(argv[2], "pulse")) {
170 if (argc == 4) {
171 freq = atof(argv[3]);
172 dc = 50.0;
173 } else if (argc == 5) {
174 freq = atof(argv[3]);
175 dc = atof(argv[4]);
176 } else
177 freq = dc = 0.0;
178 gpiopulse(pin, nm, freq, dc);
179 } else {
180 value = strtonum(argv[2], INT_MIN, INT_MAX,
181 &errstr);
182 if (errstr) {
183 if (!strcmp(argv[2], "on"))
184 value = GPIO_PIN_HIGH;
185 else if (!strcmp(argv[2], "off"))
186 value = GPIO_PIN_LOW;
187 else if (!strcmp(argv[2], "toggle"))
188 value = 2;
189 else
190 errx(EXIT_FAILURE,
191 "%s: invalid value",
192 argv[2]);
193 }
194 gpiowrite(pin, nm, value);
195 }
196 } else
197 gpioread(pin, nm);
198 }
199
200 return EXIT_SUCCESS;
201 }
202
203 static void
204 getinfo(void)
205 {
206 struct gpio_info info;
207
208 if (ioctl(devfd, GPIOINFO, &info) == -1)
209 err(EXIT_FAILURE, "GPIOINFO");
210
211 if (quiet)
212 return;
213
214 printf("%s: %d pins\n", dev, info.gpio_npins);
215 }
216
217 static void
218 gpioread(int pin, char *gp_name)
219 {
220 struct gpio_req req;
221
222 memset(&req, 0, sizeof(req));
223 if (gp_name != NULL)
224 strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
225 else
226 req.gp_pin = pin;
227
228 if (ioctl(devfd, GPIOREAD, &req) == -1)
229 err(EXIT_FAILURE, "GPIOREAD");
230
231 if (quiet)
232 return;
233
234 if (gp_name)
235 printf("pin %s: state %d\n", gp_name, req.gp_value);
236 else
237 printf("pin %d: state %d\n", pin, req.gp_value);
238 }
239
240 static void
241 gpiowrite(int pin, char *gp_name, int value)
242 {
243 struct gpio_req req;
244
245 if (value < 0 || value > 2)
246 errx(EXIT_FAILURE, "%d: invalid value", value);
247
248 memset(&req, 0, sizeof(req));
249 if (gp_name != NULL)
250 strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
251 else
252 req.gp_pin = pin;
253
254 if (value == GPIO_PIN_HIGH || value == GPIO_PIN_LOW) {
255 req.gp_value = value;
256 if (ioctl(devfd, GPIOWRITE, &req) == -1)
257 err(EXIT_FAILURE, "GPIOWRITE");
258 } else {
259 if (ioctl(devfd, GPIOTOGGLE, &req) == -1)
260 err(EXIT_FAILURE, "GPIOTOGGLE");
261 }
262
263 if (quiet)
264 return;
265
266 if (gp_name)
267 printf("pin %s: state %d -> %d\n", gp_name, req.gp_value,
268 (value < 2 ? value : 1 - req.gp_value));
269 else
270 printf("pin %d: state %d -> %d\n", pin, req.gp_value,
271 (value < 2 ? value : 1 - req.gp_value));
272 }
273
274 static void
275 gpiopulse(int pin, char *gp_name, double freq, double dc)
276 {
277 struct gpio_pulse pulse;
278 suseconds_t period, on, off;
279
280 if (freq < 0.0 || (dc < 0.0 || dc >= 100.0))
281 errx(EXIT_FAILURE, "%.f Hz, %.f%% duty cycle: invalid value",
282 freq, dc);
283
284 memset(&pulse, 0, sizeof(pulse));
285 if (gp_name != NULL)
286 strlcpy(pulse.gp_name, gp_name, sizeof(pulse.gp_name));
287 else
288 pulse.gp_pin = pin;
289
290 if (freq > 0.0 && dc > 0.0) {
291 period = 1000000 / freq;
292 on = period * dc / 100;
293 off = period - on;
294
295 if (on >= 1000000) {
296 pulse.gp_pulse_on.tv_sec = on / 1000000;
297 on -= pulse.gp_pulse_on.tv_sec * 1000000;
298 pulse.gp_pulse_on.tv_usec = on;
299 } else {
300 pulse.gp_pulse_on.tv_sec = 0;
301 pulse.gp_pulse_on.tv_usec = on;
302 }
303 if (off >= 1000000) {
304 pulse.gp_pulse_off.tv_sec = off / 1000000;
305 off -= pulse.gp_pulse_off.tv_sec * 1000000;
306 pulse.gp_pulse_off.tv_usec = off;
307 } else {
308 pulse.gp_pulse_off.tv_sec = 0;
309 pulse.gp_pulse_off.tv_usec = off;
310 }
311 } else { /* gpio(4) defaults */
312 freq = 1.0;
313 dc = 50.0;
314 }
315
316 if (ioctl(devfd, GPIOPULSE, &pulse) == -1)
317 err(EXIT_FAILURE, "GPIOPULSE");
318
319 if (quiet)
320 return;
321
322 if (gp_name)
323 printf("pin %s: pulse at %.f Hz with a %.f%% duty cylce\n",
324 gp_name, freq, dc);
325 else
326 printf("pin %d: pulse at %.f Hz with a %.f%% duty cylce\n",
327 pin, freq, dc);
328 }
329
330 static void
331 gpioset(int pin, char *name, int fl, char *alias)
332 {
333 struct gpio_set set;
334 const struct bitstr *bs;
335
336 memset(&set, 0, sizeof(set));
337 if (name != NULL)
338 strlcpy(set.gp_name, name, sizeof(set.gp_name));
339 else
340 set.gp_pin = pin;
341 set.gp_flags = fl;
342
343 if (alias != NULL)
344 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
345
346 if (ioctl(devfd, GPIOSET, &set) == -1)
347 err(EXIT_FAILURE, "GPIOSET");
348
349 if (quiet)
350 return;
351
352 if (name != NULL)
353 printf("pin %s: caps:", name);
354 else
355 printf("pin %d: caps:", pin);
356 for (bs = pinflags; bs->string != NULL; bs++)
357 if (set.gp_caps & bs->mask)
358 printf(" %s", bs->string);
359 printf(", flags:");
360 for (bs = pinflags; bs->string != NULL; bs++)
361 if (set.gp_flags & bs->mask)
362 printf(" %s", bs->string);
363 if (fl > 0) {
364 printf(" ->");
365 for (bs = pinflags; bs->string != NULL; bs++)
366 if (fl & bs->mask)
367 printf(" %s", bs->string);
368 }
369 printf("\n");
370 }
371
372 static void
373 gpiounset(int pin, char *name)
374 {
375 struct gpio_set set;
376
377 memset(&set, 0, sizeof(set));
378 if (name != NULL)
379 strlcpy(set.gp_name, name, sizeof(set.gp_name));
380 else
381 set.gp_pin = pin;
382
383 if (ioctl(devfd, GPIOUNSET, &set) == -1)
384 err(EXIT_FAILURE, "GPIOUNSET");
385 }
386
387 static void
388 devattach(char *dvname, int offset, uint32_t mask)
389 {
390 struct gpio_attach attach;
391
392 memset(&attach, 0, sizeof(attach));
393 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
394 attach.ga_offset = offset;
395 attach.ga_mask = mask;
396 if (ioctl(devfd, GPIOATTACH, &attach) == -1)
397 err(EXIT_FAILURE, "GPIOATTACH");
398 }
399
400 static void
401 devdetach(char *dvname)
402 {
403 struct gpio_attach attach;
404
405 memset(&attach, 0, sizeof(attach));
406 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
407 if (ioctl(devfd, GPIODETACH, &attach) == -1)
408 err(EXIT_FAILURE, "GPIODETACH");
409 }
410
411 static void
412 usage(void)
413 {
414 const char *progname;
415
416 progname = getprogname();
417 fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | "
418 "on | off | toggle]\n", progname);
419 fprintf(stderr, "usage: %s [-q] device pin pulse [frequency "
420 "[duty cycle]]\n", progname);
421 fprintf(stderr, " %s [-q] device pin set [flags] [name]\n",
422 progname);
423 fprintf(stderr, " %s [-q] device pin unset\n", progname);
424 fprintf(stderr, " %s [-q] device attach device offset mask\n",
425 progname);
426 fprintf(stderr, " %s [-q] device detach device\n", progname);
427
428 exit(EXIT_FAILURE);
429 }
430