1
2
3
4
5
6
7
8
9
10
11#define _GNU_SOURCE
12#include <unistd.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include <errno.h>
17#include <string.h>
18#include <fcntl.h>
19#include <getopt.h>
20#include <sys/ioctl.h>
21#include <libmount.h>
22#include <err.h>
23#include <dirent.h>
24#include <linux/gpio.h>
25#include "../../../gpio/gpio-utils.h"
26
27#define CONSUMER "gpio-selftest"
28#define GC_NUM 10
29enum direction {
30 OUT,
31 IN
32};
33
34static int get_debugfs(char **path)
35{
36 struct libmnt_context *cxt;
37 struct libmnt_table *tb;
38 struct libmnt_iter *itr = NULL;
39 struct libmnt_fs *fs;
40 int found = 0;
41
42 cxt = mnt_new_context();
43 if (!cxt)
44 err(EXIT_FAILURE, "libmount context allocation failed");
45
46 itr = mnt_new_iter(MNT_ITER_FORWARD);
47 if (!itr)
48 err(EXIT_FAILURE, "failed to initialize libmount iterator");
49
50 if (mnt_context_get_mtab(cxt, &tb))
51 err(EXIT_FAILURE, "failed to read mtab");
52
53 while (mnt_table_next_fs(tb, itr, &fs) == 0) {
54 const char *type = mnt_fs_get_fstype(fs);
55
56 if (!strcmp(type, "debugfs")) {
57 found = 1;
58 break;
59 }
60 }
61 if (found)
62 asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
63
64 mnt_free_iter(itr);
65 mnt_free_context(cxt);
66
67 if (!found)
68 return -1;
69
70 return 0;
71}
72
73static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
74{
75 char *debugfs;
76 FILE *f;
77 char *line = NULL;
78 size_t len = 0;
79 char *cur;
80 int found = 0;
81
82 if (get_debugfs(&debugfs) != 0)
83 err(EXIT_FAILURE, "debugfs is not mounted");
84
85 f = fopen(debugfs, "r");
86 if (!f)
87 err(EXIT_FAILURE, "read from gpio debugfs failed");
88
89
90
91
92 while (getline(&line, &len, f) != -1) {
93 cur = strstr(line, consumer);
94 if (cur == NULL)
95 continue;
96
97 cur = strchr(line, ')');
98 if (!cur)
99 continue;
100
101 cur += 2;
102 if (!strncmp(cur, "out", 3)) {
103 *dir = OUT;
104 cur += 4;
105 } else if (!strncmp(cur, "in", 2)) {
106 *dir = IN;
107 cur += 4;
108 }
109
110 if (!strncmp(cur, "hi", 2))
111 *value = 1;
112 else if (!strncmp(cur, "lo", 2))
113 *value = 0;
114
115 found = 1;
116 break;
117 }
118 free(debugfs);
119 fclose(f);
120 free(line);
121
122 if (!found)
123 return -1;
124
125 return 0;
126}
127
128static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
129{
130 struct gpiochip_info *cinfo;
131 struct gpiochip_info *current;
132 const struct dirent *ent;
133 DIR *dp;
134 char *chrdev_name;
135 int fd;
136 int i = 0;
137
138 cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
139 if (!cinfo)
140 err(EXIT_FAILURE, "gpiochip_info allocation failed");
141
142 current = cinfo;
143 dp = opendir("/dev");
144 if (!dp) {
145 *ret = -errno;
146 goto error_out;
147 } else {
148 *ret = 0;
149 }
150
151 while (ent = readdir(dp), ent) {
152 if (check_prefix(ent->d_name, "gpiochip")) {
153 *ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name);
154 if (*ret < 0)
155 goto error_out;
156
157 fd = open(chrdev_name, 0);
158 if (fd == -1) {
159 *ret = -errno;
160 fprintf(stderr, "Failed to open %s\n",
161 chrdev_name);
162 goto error_close_dir;
163 }
164 *ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current);
165 if (*ret == -1) {
166 perror("Failed to issue CHIPINFO IOCTL\n");
167 goto error_close_dir;
168 }
169 close(fd);
170 if (strcmp(current->label, gpiochip_name) == 0
171 || check_prefix(current->label, gpiochip_name)) {
172 *ret = 0;
173 current++;
174 i++;
175 }
176 }
177 }
178
179 if ((!*ret && i == 0) || *ret < 0) {
180 free(cinfo);
181 cinfo = NULL;
182 }
183 if (!*ret && i > 0) {
184 cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
185 *ret = i;
186 }
187
188error_close_dir:
189 closedir(dp);
190error_out:
191 if (*ret < 0)
192 err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
193
194 return cinfo;
195}
196
197int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
198{
199 struct gpiohandle_data data;
200 unsigned int lines[] = {line};
201 int fd;
202 int debugfs_dir = IN;
203 int debugfs_value = 0;
204 int ret;
205
206 data.values[0] = value;
207 ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data,
208 CONSUMER);
209 if (ret < 0)
210 goto fail_out;
211 else
212 fd = ret;
213
214 ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
215 if (ret) {
216 ret = -EINVAL;
217 goto fail_out;
218 }
219 if (flag & GPIOHANDLE_REQUEST_INPUT) {
220 if (debugfs_dir != IN) {
221 errno = -EINVAL;
222 ret = -errno;
223 }
224 } else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
225 if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
226 debugfs_value = !debugfs_value;
227
228 if (!(debugfs_dir == OUT && value == debugfs_value))
229 errno = -EINVAL;
230 ret = -errno;
231
232 }
233 gpiotools_release_linehandle(fd);
234
235fail_out:
236 if (ret)
237 err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
238 cinfo->name, line, flag, value);
239
240 return ret;
241}
242
243void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
244{
245 printf("line<%d>", line);
246 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0);
247 printf(".");
248 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1);
249 printf(".");
250 gpio_pin_test(cinfo, line,
251 GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
252 0);
253 printf(".");
254 gpio_pin_test(cinfo, line,
255 GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
256 1);
257 printf(".");
258 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
259 printf(".");
260}
261
262
263
264
265
266
267
268
269
270
271int main(int argc, char *argv[])
272{
273 char *prefix;
274 int valid;
275 struct gpiochip_info *cinfo;
276 struct gpiochip_info *current;
277 int i;
278 int ret;
279
280 if (argc < 3) {
281 printf("Usage: %s prefix is_valid", argv[0]);
282 exit(EXIT_FAILURE);
283 }
284
285 prefix = argv[1];
286 valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
287
288 printf("Test gpiochip %s: ", prefix);
289 cinfo = list_gpiochip(prefix, &ret);
290 if (!cinfo) {
291 if (!valid && ret == 0) {
292 printf("Invalid test successful\n");
293 ret = 0;
294 goto out;
295 } else {
296 ret = -EINVAL;
297 goto out;
298 }
299 } else if (cinfo && !valid) {
300 ret = -EINVAL;
301 goto out;
302 }
303 current = cinfo;
304 for (i = 0; i < ret; i++) {
305 gpio_pin_tests(current, 0);
306 gpio_pin_tests(current, current->lines - 1);
307 gpio_pin_tests(current, random() % current->lines);
308 current++;
309 }
310 ret = 0;
311 printf("successful\n");
312
313out:
314 if (ret)
315 fprintf(stderr, "gpio<%s> test failed\n", prefix);
316
317 if (cinfo)
318 free(cinfo);
319
320 if (ret)
321 exit(EXIT_FAILURE);
322
323 return ret;
324}
325