1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60#define FOR_gpiodetect
61#define TT this.gpiod
62#include "toys.h"
63
64GLOBALS(
65 struct double_list *chips;
66 int chip_count;
67)
68
69#include <linux/gpio.h>
70
71static int open_chip(char *chip)
72{
73 sprintf(toybuf, isdigit(*chip) ? "/dev/gpiochip%s" : "/dev/%s", chip);
74 return xopen(toybuf, O_RDWR);
75}
76
77static int collect_chips(struct dirtree *node)
78{
79 int n;
80
81 if (!node->parent) return DIRTREE_RECURSE;
82
83 if (sscanf(node->name, "gpiochip%d", &n)!=1) return 0;
84
85 dlist_add(&TT.chips, strdup(node->name));
86 TT.chip_count++;
87
88 return 0;
89}
90
91static int comparator(const void *a, const void *b)
92{
93 struct double_list *lhs = *(struct double_list **)a,
94 *rhs = *(struct double_list **)b;
95
96 return strcmp(lhs->data, rhs->data);
97}
98
99
100static void foreach_chip(void (*cb)(char *name))
101{
102 struct double_list **sorted;
103 int i = 0;
104
105 dirtree_flagread("/dev", DIRTREE_SHUTUP, collect_chips);
106 if (!TT.chips) return;
107
108 sorted = xmalloc(TT.chip_count*sizeof(void *));
109 for (i = 0; i<TT.chip_count; i++) sorted[i] = TT.chips = TT.chips->next;
110 qsort(sorted, TT.chip_count, sizeof(void *), comparator);
111
112 for (i = 0; i<TT.chip_count; i++) {
113 sprintf(toybuf, "/dev/%s", sorted[i]->data);
114 cb(toybuf);
115 }
116
117 free(sorted);
118 llist_traverse(&TT.chips, llist_free_arg);
119}
120
121static void gpiodetect(char *path)
122{
123 struct gpiochip_info chip;
124 int fd = xopen(path, O_RDWR);
125
126 xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip);
127 close(fd);
128
129
130 printf("%s [%s] (%u line%s)\n", chip.name, chip.label, chip.lines,
131 chip.lines==1?"":"s");
132}
133
134void gpiodetect_main(void)
135{
136 foreach_chip(gpiodetect);
137}
138
139#define FOR_gpiofind
140#include "generated/flags.h"
141
142static void gpiofind(char *path)
143{
144 struct gpiochip_info chip;
145 struct gpioline_info line;
146 int fd = xopen(path, O_RDWR);
147
148 xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip);
149
150 for (line.line_offset=0; line.line_offset<chip.lines; line.line_offset++) {
151 xioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line);
152 if (!strcmp(line.name, *toys.optargs)) {
153 printf("%s %d\n", chip.name, line.line_offset);
154 break;
155 }
156 }
157 close(fd);
158}
159
160void gpiofind_main(void)
161{
162 foreach_chip(gpiofind);
163}
164
165#define FOR_gpioinfo
166#include "generated/flags.h"
167
168static void gpioinfo_fd(int fd)
169{
170 struct gpiochip_info chip;
171 struct gpioline_info line;
172
173 xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip);
174
175
176 printf("%s - %d line%s:\n", chip.name, chip.lines, chip.lines==1?"":"s");
177
178
179
180
181 for (line.line_offset=0; line.line_offset<chip.lines; line.line_offset++) {
182 xioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line);
183 if (*line.name) sprintf(toybuf, "\"%s\"", line.name);
184 else strcpy(toybuf, "unnamed");
185 if (*line.consumer) sprintf(toybuf+64, "\"%s\"", line.consumer);
186 else strcpy(toybuf+64, "unused");
187 printf("\tline %3d:%18s %18s", line.line_offset, toybuf, toybuf+64);
188 printf(" %sput", line.flags&GPIOLINE_FLAG_IS_OUT?"out":" in");
189 printf(" active-%s", line.flags&GPIOLINE_FLAG_ACTIVE_LOW?"low ":"high");
190 if (line.flags&GPIOLINE_FLAG_KERNEL) printf(" [used]");
191 printf("\n");
192 }
193
194 close(fd);
195}
196
197static void gpioinfo(char *path)
198{
199 gpioinfo_fd(xopen(path, O_RDWR));
200}
201
202void gpioinfo_main(void)
203{
204 int i;
205
206 if (!toys.optc) foreach_chip(gpioinfo);
207 else for (i = 0; toys.optargs[i];i++) gpioinfo_fd(open_chip(toys.optargs[i]));
208}
209
210#define FOR_gpioget
211#include "generated/flags.h"
212
213void gpioget_main(void)
214{
215 struct gpiohandle_request req = { .flags = GPIOHANDLE_REQUEST_INPUT };
216 struct gpiohandle_data data;
217 struct gpiochip_info chip;
218 char **args = toys.optargs;
219 int fd, line;
220
221 fd = open_chip(*args);
222 xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip);
223 if (FLAG(l)) req.flags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
224 for (args++; *args; args++, req.lines++) {
225 if (req.lines >= GPIOHANDLES_MAX) error_exit("too many requests!");
226 line = atolx_range(*args, 0, chip.lines);
227 req.lineoffsets[req.lines] = line;
228 }
229 xioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
230 xioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data);
231 for (line = 0; line<req.lines; line++)
232 printf("%s%d", " "+(line<1), data.values[line]);
233 xputc('\n');
234}
235
236#define FOR_gpioset
237#include "generated/flags.h"
238
239void gpioset_main(void)
240{
241 struct gpiohandle_request req = { .flags = GPIOHANDLE_REQUEST_OUTPUT };
242 char **args = toys.optargs;
243 int fd, value;
244
245 fd = open_chip(*args);
246 if (FLAG(l)) req.flags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
247 for (args++; *args; args++, req.lines++) {
248 if (req.lines == GPIOHANDLES_MAX) error_exit("too many requests!");
249 if (sscanf(*args, "%d=%d", req.lineoffsets+req.lines, &value) != 2)
250 perror_exit("not LINE=VALUE: %s", *args);
251 req.default_values[req.lines] = value;
252 }
253 xioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
254}
255