Merge branch 'locking-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cris-mirror.git] / tools / testing / selftests / gpio / gpio-mockup-chardev.c
blob667e916fa7cc1805e3bf6ddff301e1da24d4bda7
1 /*
2 * GPIO chardev test helper
4 * Copyright (C) 2016 Bamvor Jian Zhang
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published by
8 * the Free Software Foundation.
9 */
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"
27 #define CONSUMER "gpio-selftest"
28 #define GC_NUM 10
29 enum direction {
30 OUT,
34 static int get_debugfs(char **path)
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;
42 cxt = mnt_new_context();
43 if (!cxt)
44 err(EXIT_FAILURE, "libmount context allocation failed");
46 itr = mnt_new_iter(MNT_ITER_FORWARD);
47 if (!itr)
48 err(EXIT_FAILURE, "failed to initialize libmount iterator");
50 if (mnt_context_get_mtab(cxt, &tb))
51 err(EXIT_FAILURE, "failed to read mtab");
53 while (mnt_table_next_fs(tb, itr, &fs) == 0) {
54 const char *type = mnt_fs_get_fstype(fs);
56 if (!strcmp(type, "debugfs")) {
57 found = 1;
58 break;
61 if (found)
62 asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
64 mnt_free_iter(itr);
65 mnt_free_context(cxt);
67 if (!found)
68 return -1;
70 return 0;
73 static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
75 char *debugfs;
76 FILE *f;
77 char *line = NULL;
78 size_t len = 0;
79 char *cur;
80 int found = 0;
82 if (get_debugfs(&debugfs) != 0)
83 err(EXIT_FAILURE, "debugfs is not mounted");
85 f = fopen(debugfs, "r");
86 if (!f)
87 err(EXIT_FAILURE, "read from gpio debugfs failed");
90 * gpio-2 ( |gpio-selftest ) in lo
92 while (getline(&line, &len, f) != -1) {
93 cur = strstr(line, consumer);
94 if (cur == NULL)
95 continue;
97 cur = strchr(line, ')');
98 if (!cur)
99 continue;
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;
110 if (!strncmp(cur, "hi", 2))
111 *value = 1;
112 else if (!strncmp(cur, "lo", 2))
113 *value = 0;
115 found = 1;
116 break;
118 free(debugfs);
119 fclose(f);
120 free(line);
122 if (!found)
123 return -1;
125 return 0;
128 static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
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;
138 cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
139 if (!cinfo)
140 err(EXIT_FAILURE, "gpiochip_info allocation failed");
142 current = cinfo;
143 dp = opendir("/dev");
144 if (!dp) {
145 *ret = -errno;
146 goto error_out;
147 } else {
148 *ret = 0;
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;
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;
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;
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++;
179 if ((!*ret && i == 0) || *ret < 0) {
180 free(cinfo);
181 cinfo = NULL;
183 if (!*ret && i > 0) {
184 cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
185 *ret = i;
188 error_close_dir:
189 closedir(dp);
190 error_out:
191 if (*ret < 0)
192 err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
194 return cinfo;
197 int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
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;
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;
214 ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
215 if (ret) {
216 ret = -EINVAL;
217 goto fail_out;
219 if (flag & GPIOHANDLE_REQUEST_INPUT) {
220 if (debugfs_dir != IN) {
221 errno = -EINVAL;
222 ret = -errno;
224 } else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
225 if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
226 debugfs_value = !debugfs_value;
228 if (!(debugfs_dir == OUT && value == debugfs_value))
229 errno = -EINVAL;
230 ret = -errno;
233 gpiotools_release_linehandle(fd);
235 fail_out:
236 if (ret)
237 err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
238 cinfo->name, line, flag, value);
240 return ret;
243 void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
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,
253 printf(".");
254 gpio_pin_test(cinfo, line,
255 GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
257 printf(".");
258 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
259 printf(".");
263 * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip
264 * Return 0 if successful or exit with EXIT_FAILURE if test failed.
265 * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g.
266 * gpio-mockup
267 * is_valid_gpio_chip: Whether the gpio_chip is valid. 1 means valid,
268 * 0 means invalid which could not be found by
269 * list_gpiochip.
271 int main(int argc, char *argv[])
273 char *prefix;
274 int valid;
275 struct gpiochip_info *cinfo;
276 struct gpiochip_info *current;
277 int i;
278 int ret;
280 if (argc < 3) {
281 printf("Usage: %s prefix is_valid", argv[0]);
282 exit(EXIT_FAILURE);
285 prefix = argv[1];
286 valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
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;
299 } else if (cinfo && !valid) {
300 ret = -EINVAL;
301 goto out;
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++;
310 ret = 0;
311 printf("successful\n");
313 out:
314 if (ret)
315 fprintf(stderr, "gpio<%s> test failed\n", prefix);
317 if (cinfo)
318 free(cinfo);
320 if (ret)
321 exit(EXIT_FAILURE);
323 return ret;