File: | src/usr.sbin/gpioctl/gpioctl.c |
Warning: | line 138, column 3 Address of stack memory associated with local variable 'devn' is still referred to by the global variable 'dev' upon returning to the caller. This will be a dangling reference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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(*__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__attribute__((__noreturn__)) void usage(void); | |||
51 | ||||
52 | const struct bitstr { | |||
53 | unsigned int mask; | |||
54 | const char *string; | |||
55 | } pinflags[] = { | |||
56 | { GPIO_PIN_INPUT0x0001, "in" }, | |||
57 | { GPIO_PIN_OUTPUT0x0002, "out" }, | |||
58 | { GPIO_PIN_INOUT0x0004, "inout" }, | |||
59 | { GPIO_PIN_OPENDRAIN0x0008, "od" }, | |||
60 | { GPIO_PIN_PUSHPULL0x0010, "pp" }, | |||
61 | { GPIO_PIN_TRISTATE0x0020, "tri" }, | |||
62 | { GPIO_PIN_PULLUP0x0040, "pu" }, | |||
63 | { GPIO_PIN_PULLDOWN0x0080, "pd" }, | |||
64 | { GPIO_PIN_INVIN0x0100, "iin" }, | |||
65 | { GPIO_PIN_INVOUT0x0200, "iout" }, | |||
66 | { 0, NULL((void *)0) }, | |||
67 | }; | |||
68 | ||||
69 | int | |||
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((void *)0); | |||
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/", dev, sizeof(_PATH_DEV"/dev/") - 1)) { | |||
97 | (void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV"/dev/", dev); | |||
98 | dev = devn; | |||
99 | } | |||
100 | ||||
101 | if ((devfd = open(dev, O_RDWR0x0002)) == -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
| |||
119 | ||||
120 | ga_offset = strtonum(offset, 0, INT_MAX0x7fffffff, &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(*__errno()) == ERANGE34 && (lval == LONG_MAX0x7fffffffffffffffL | |||
128 | || lval == LONG_MIN(-0x7fffffffffffffffL-1))) || lval > UINT_MAX0xffffffffU) | |||
129 | errx(1, "mask out of range"); | |||
130 | ga_mask = lval; | |||
131 | if (flags
| |||
132 | lval = strtonum(flags, 0, UINT_MAX0xffffffffU, &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((void *)0); | |||
145 | ||||
146 | /* expecting a pin number or name */ | |||
147 | pin = strtonum(argv[1], 0, INT_MAX0x7fffffff, &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((void *)0); | |||
154 | bs++) { | |||
155 | if (!strcmp(argv[n], | |||
156 | bs->string)) { | |||
157 | fl |= bs->mask; | |||
158 | break; | |||
159 | } | |||
160 | } | |||
161 | if (bs->string == NULL((void *)0)) | |||
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(-0x7fffffff-1), INT_MAX0x7fffffff, | |||
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 | |||
191 | getinfo(void) | |||
192 | { | |||
193 | struct gpio_info info; | |||
194 | ||||
195 | memset(&info, 0, sizeof(info)); | |||
196 | if (ioctl(devfd, GPIOINFO((unsigned long)0x40000000 | ((sizeof(struct gpio_info) & 0x1fff) << 16) | ((('G')) << 8) | ((0))), &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 | |||
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((void *)0)) | |||
212 | strlcpy(op.gp_name, gp_name, sizeof(op.gp_name)); | |||
213 | else | |||
214 | op.gp_pin = pin; | |||
215 | ||||
216 | if (ioctl(devfd, GPIOPINREAD(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct gpio_pin_op) & 0x1fff) << 16) | ((('G')) << 8) | ((1))), &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 | |||
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((void *)0)) | |||
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_LOW0x00 : GPIO_PIN_HIGH0x01); | |||
242 | if (value < 2) { | |||
243 | if (ioctl(devfd, GPIOPINWRITE(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct gpio_pin_op) & 0x1fff) << 16) | ((('G')) << 8) | ((2))), &op) == -1) | |||
244 | err(1, "GPIOPINWRITE"); | |||
245 | } else { | |||
246 | if (ioctl(devfd, GPIOPINTOGGLE(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct gpio_pin_op) & 0x1fff) << 16) | ((('G')) << 8) | ((3))), &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 | |||
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((void *)0)) | |||
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((void *)0)) | |||
275 | strlcpy(set.gp_name2, alias, sizeof(set.gp_name2)); | |||
276 | ||||
277 | if (ioctl(devfd, GPIOPINSET(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct gpio_pin_set) & 0x1fff) << 16) | ((('G')) << 8) | ((4))), &set) == -1) | |||
278 | err(1, "GPIOPINSET"); | |||
279 | ||||
280 | if (quiet) | |||
281 | return; | |||
282 | ||||
283 | if (name != NULL((void *)0)) | |||
284 | printf("pin %s: caps:", name); | |||
285 | else | |||
286 | printf("pin %d: caps:", pin); | |||
287 | for (bs = pinflags; bs->string != NULL((void *)0); bs++) | |||
288 | if (set.gp_caps & bs->mask) | |||
289 | printf(" %s", bs->string); | |||
290 | printf(", flags:"); | |||
291 | for (bs = pinflags; bs->string != NULL((void *)0); 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((void *)0); bs++) | |||
297 | if (fl & bs->mask) | |||
298 | printf(" %s", bs->string); | |||
299 | } | |||
300 | printf("\n"); | |||
301 | } | |||
302 | ||||
303 | void | |||
304 | unset(int pin, char *name) | |||
305 | { | |||
306 | struct gpio_pin_set set; | |||
307 | ||||
308 | memset(&set, 0, sizeof(set)); | |||
309 | if (name != NULL((void *)0)) | |||
310 | strlcpy(set.gp_name, name, sizeof(set.gp_name)); | |||
311 | else | |||
312 | set.gp_pin = pin; | |||
313 | ||||
314 | if (ioctl(devfd, GPIOPINUNSET(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct gpio_pin_set) & 0x1fff) << 16) | ((('G')) << 8) | ((5))), &set) == -1) | |||
315 | err(1, "GPIOPINUNSET"); | |||
316 | } | |||
317 | ||||
318 | void | |||
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(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct gpio_attach) & 0x1fff) << 16) | ((('G')) << 8) | ((6))), &attach) == -1) | |||
329 | err(1, "GPIOATTACH"); | |||
330 | } | |||
331 | ||||
332 | void | |||
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(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct gpio_attach) & 0x1fff) << 16) | ((('G')) << 8) | ((7))), &attach) == -1) | |||
340 | err(1, "GPIODETACH"); | |||
341 | } | |||
342 | void | |||
343 | usage(void) | |||
344 | { | |||
345 | extern char *__progname; | |||
346 | ||||
347 | fprintf(stderr(&__sF[2]), "usage: %s [-q] device pin [0 | 1 | 2 | " | |||
348 | "on | off | toggle]\n", __progname); | |||
349 | fprintf(stderr(&__sF[2]), " %s [-q] device pin set [flags] [name]\n", | |||
350 | __progname); | |||
351 | fprintf(stderr(&__sF[2]), " %s [-q] device pin unset\n", __progname); | |||
352 | fprintf(stderr(&__sF[2]), " %s [-q] device attach device offset mask " | |||
353 | "[flag]\n", __progname); | |||
354 | fprintf(stderr(&__sF[2]), " %s [-q] device detach device\n", __progname); | |||
355 | ||||
356 | exit(1); | |||
357 | } |