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