1 /* $OpenBSD: gpioctl.c,v 1.17 2015/12/26 20:52:03 mmcc Exp $ */
2 /*
3 * Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
4 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Program to control GPIO devices.
21 */
22
23 #include <sys/types.h>
24 #include <sys/gpio.h>
25 #include <sys/ioctl.h>
26 #include <sys/limits.h>
27
28 #include <err.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <paths.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37
38 char *dev;
39 int devfd = -1;
40 int quiet = 0;
41
42 void getinfo(void);
43 void pinread(int, char *);
44 void pinwrite(int, char *, int);
45 void pinset(int pin, char *name, int flags, char *alias);
46 void unset(int pin, char *name);
47 void devattach(char *, int, u_int32_t, u_int32_t);
48 void devdetach(char *);
49
50 __dead void usage(void);
51
52 const struct bitstr {
53 unsigned int mask;
54 const char *string;
55 } pinflags[] = {
56 { GPIO_PIN_INPUT, "in" },
57 { GPIO_PIN_OUTPUT, "out" },
58 { GPIO_PIN_INOUT, "inout" },
59 { GPIO_PIN_OPENDRAIN, "od" },
60 { GPIO_PIN_PUSHPULL, "pp" },
61 { GPIO_PIN_TRISTATE, "tri" },
62 { GPIO_PIN_PULLUP, "pu" },
63 { GPIO_PIN_PULLDOWN, "pd" },
64 { GPIO_PIN_INVIN, "iin" },
65 { GPIO_PIN_INVOUT, "iout" },
66 { 0, NULL },
67 };
68
69 int
main(int argc,char * argv[])70 main(int argc, char *argv[])
71 {
72 const struct bitstr *bs;
73 long lval;
74 u_int32_t ga_mask = 0, ga_flags = 0;
75 int pin, ch, ga_offset = -1, n, fl = 0, value = 0;
76 const char *errstr;
77 char *ep, *flags, *nam = NULL;
78 char devn[32];
79
80 while ((ch = getopt(argc, argv, "q")) != -1)
81 switch (ch) {
82 case 'q':
83 quiet = 1;
84 break;
85 default:
86 usage();
87 /* NOTREACHED */
88 }
89 argc -= optind;
90 argv += optind;
91
92 if (argc < 1)
93 usage();
94 dev = argv[0];
95
96 if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) {
97 (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev);
98 dev = devn;
99 }
100
101 if ((devfd = open(dev, O_RDWR)) == -1)
102 err(1, "%s", dev);
103
104 if (argc == 1) {
105 getinfo();
106 return 0;
107 }
108
109 if (!strcmp(argv[1], "attach")) {
110 char *driver, *offset, *mask;
111
112 if (argc != 5 && argc != 6)
113 usage();
114
115 driver = argv[2];
116 offset = argv[3];
117 mask = argv[4];
118 flags = argc == 6 ? argv[5] : NULL;
119
120 ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
121 if (errstr)
122 errx(1, "offset is %s: %s", errstr, offset);
123
124 lval = strtol(mask, &ep, 0);
125 if (*mask == '\0' || *ep != '\0')
126 errx(1, "invalid mask (not a number)");
127 if ((errno == ERANGE && (lval == LONG_MAX
128 || lval == LONG_MIN)) || lval > UINT_MAX)
129 errx(1, "mask out of range");
130 ga_mask = lval;
131 if (flags != NULL) {
132 lval = strtonum(flags, 0, UINT_MAX, &errstr);
133 if (errstr)
134 errx(1, "flags is %s: %s", errstr, flags);
135 ga_flags = lval;
136 }
137 devattach(driver, ga_offset, ga_mask, ga_flags);
138 return 0;
139 } else if (!strcmp(argv[1], "detach")) {
140 if (argc != 3)
141 usage();
142 devdetach(argv[2]);
143 } else {
144 char *nm = NULL;
145
146 /* expecting a pin number or name */
147 pin = strtonum(argv[1], 0, INT_MAX, &errstr);
148 if (errstr)
149 nm = argv[1]; /* try named pin */
150 if (argc > 2) {
151 if (!strcmp(argv[2], "set")) {
152 for (n = 3; n < argc; n++) {
153 for (bs = pinflags; bs->string != NULL;
154 bs++) {
155 if (!strcmp(argv[n],
156 bs->string)) {
157 fl |= bs->mask;
158 break;
159 }
160 }
161 if (bs->string == NULL)
162 nam = argv[n];
163 }
164 pinset(pin, nm, fl, nam);
165 } else if (!strcmp(argv[2], "unset")) {
166 unset(pin, nm);
167 } else {
168 value = strtonum(argv[2], INT_MIN, INT_MAX,
169 &errstr);
170 if (errstr) {
171 if (!strcmp(argv[2], "on"))
172 value = 1;
173 else if (!strcmp(argv[2], "off"))
174 value = 0;
175 else if (!strcmp(argv[2], "toggle"))
176 value = 2;
177 else
178 errx(1, "%s: invalid value",
179 argv[2]);
180 }
181 pinwrite(pin, nm, value);
182 }
183 } else
184 pinread(pin, nm);
185 }
186
187 return (0);
188 }
189
190 void
getinfo(void)191 getinfo(void)
192 {
193 struct gpio_info info;
194
195 memset(&info, 0, sizeof(info));
196 if (ioctl(devfd, GPIOINFO, &info) == -1)
197 err(1, "GPIOINFO");
198
199 if (quiet)
200 return;
201
202 printf("%s: %d pins\n", dev, info.gpio_npins);
203 }
204
205 void
pinread(int pin,char * gp_name)206 pinread(int pin, char *gp_name)
207 {
208 struct gpio_pin_op op;
209
210 memset(&op, 0, sizeof(op));
211 if (gp_name != NULL)
212 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name));
213 else
214 op.gp_pin = pin;
215
216 if (ioctl(devfd, GPIOPINREAD, &op) == -1)
217 err(1, "GPIOPINREAD");
218
219 if (quiet)
220 return;
221
222 if (gp_name)
223 printf("pin %s: state %d\n", gp_name, op.gp_value);
224 else
225 printf("pin %d: state %d\n", pin, op.gp_value);
226 }
227
228 void
pinwrite(int pin,char * gp_name,int value)229 pinwrite(int pin, char *gp_name, int value)
230 {
231 struct gpio_pin_op op;
232
233 if (value < 0 || value > 2)
234 errx(1, "%d: invalid value", value);
235
236 memset(&op, 0, sizeof(op));
237 if (gp_name != NULL)
238 strlcpy(op.gp_name, gp_name, sizeof(op.gp_name));
239 else
240 op.gp_pin = pin;
241 op.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH);
242 if (value < 2) {
243 if (ioctl(devfd, GPIOPINWRITE, &op) == -1)
244 err(1, "GPIOPINWRITE");
245 } else {
246 if (ioctl(devfd, GPIOPINTOGGLE, &op) == -1)
247 err(1, "GPIOPINTOGGLE");
248 }
249
250 if (quiet)
251 return;
252
253 if (gp_name)
254 printf("pin %s: state %d -> %d\n", gp_name, op.gp_value,
255 (value < 2 ? value : 1 - op.gp_value));
256 else
257 printf("pin %d: state %d -> %d\n", pin, op.gp_value,
258 (value < 2 ? value : 1 - op.gp_value));
259 }
260
261 void
pinset(int pin,char * name,int fl,char * alias)262 pinset(int pin, char *name, int fl, char *alias)
263 {
264 struct gpio_pin_set set;
265 const struct bitstr *bs;
266
267 memset(&set, 0, sizeof(set));
268 if (name != NULL)
269 strlcpy(set.gp_name, name, sizeof(set.gp_name));
270 else
271 set.gp_pin = pin;
272 set.gp_flags = fl;
273
274 if (alias != NULL)
275 strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
276
277 if (ioctl(devfd, GPIOPINSET, &set) == -1)
278 err(1, "GPIOPINSET");
279
280 if (quiet)
281 return;
282
283 if (name != NULL)
284 printf("pin %s: caps:", name);
285 else
286 printf("pin %d: caps:", pin);
287 for (bs = pinflags; bs->string != NULL; bs++)
288 if (set.gp_caps & bs->mask)
289 printf(" %s", bs->string);
290 printf(", flags:");
291 for (bs = pinflags; bs->string != NULL; bs++)
292 if (set.gp_flags & bs->mask)
293 printf(" %s", bs->string);
294 if (fl > 0) {
295 printf(" ->");
296 for (bs = pinflags; bs->string != NULL; bs++)
297 if (fl & bs->mask)
298 printf(" %s", bs->string);
299 }
300 printf("\n");
301 }
302
303 void
unset(int pin,char * name)304 unset(int pin, char *name)
305 {
306 struct gpio_pin_set set;
307
308 memset(&set, 0, sizeof(set));
309 if (name != NULL)
310 strlcpy(set.gp_name, name, sizeof(set.gp_name));
311 else
312 set.gp_pin = pin;
313
314 if (ioctl(devfd, GPIOPINUNSET, &set) == -1)
315 err(1, "GPIOPINUNSET");
316 }
317
318 void
devattach(char * dvname,int offset,u_int32_t mask,u_int32_t flags)319 devattach(char *dvname, int offset, u_int32_t mask, u_int32_t flags)
320 {
321 struct gpio_attach attach;
322
323 memset(&attach, 0, sizeof(attach));
324 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
325 attach.ga_offset = offset;
326 attach.ga_mask = mask;
327 attach.ga_flags = flags;
328 if (ioctl(devfd, GPIOATTACH, &attach) == -1)
329 err(1, "GPIOATTACH");
330 }
331
332 void
devdetach(char * dvname)333 devdetach(char *dvname)
334 {
335 struct gpio_attach attach;
336
337 memset(&attach, 0, sizeof(attach));
338 strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
339 if (ioctl(devfd, GPIODETACH, &attach) == -1)
340 err(1, "GPIODETACH");
341 }
342 void
usage(void)343 usage(void)
344 {
345 extern char *__progname;
346
347 fprintf(stderr, "usage: %s [-q] device pin [0 | 1 | 2 | "
348 "on | off | toggle]\n", __progname);
349 fprintf(stderr, " %s [-q] device pin set [flags] [name]\n",
350 __progname);
351 fprintf(stderr, " %s [-q] device pin unset\n", __progname);
352 fprintf(stderr, " %s [-q] device attach device offset mask "
353 "[flag]\n", __progname);
354 fprintf(stderr, " %s [-q] device detach device\n", __progname);
355
356 exit(1);
357 }
358