Linux 4.19.133
[linux/fpc-iii.git] / tools / testing / selftests / gpio / gpio-mockup-chardev.c
blobaaa1e9f083c372153836764e85feb7a358f0a273
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, ret;
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 ret = asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
63 if (ret < 0)
64 err(EXIT_FAILURE, "failed to format string");
67 mnt_free_iter(itr);
68 mnt_free_context(cxt);
70 if (!found)
71 return -1;
73 return 0;
76 static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
78 char *debugfs;
79 FILE *f;
80 char *line = NULL;
81 size_t len = 0;
82 char *cur;
83 int found = 0;
85 if (get_debugfs(&debugfs) != 0)
86 err(EXIT_FAILURE, "debugfs is not mounted");
88 f = fopen(debugfs, "r");
89 if (!f)
90 err(EXIT_FAILURE, "read from gpio debugfs failed");
93 * gpio-2 ( |gpio-selftest ) in lo
95 while (getline(&line, &len, f) != -1) {
96 cur = strstr(line, consumer);
97 if (cur == NULL)
98 continue;
100 cur = strchr(line, ')');
101 if (!cur)
102 continue;
104 cur += 2;
105 if (!strncmp(cur, "out", 3)) {
106 *dir = OUT;
107 cur += 4;
108 } else if (!strncmp(cur, "in", 2)) {
109 *dir = IN;
110 cur += 4;
113 if (!strncmp(cur, "hi", 2))
114 *value = 1;
115 else if (!strncmp(cur, "lo", 2))
116 *value = 0;
118 found = 1;
119 break;
121 free(debugfs);
122 fclose(f);
123 free(line);
125 if (!found)
126 return -1;
128 return 0;
131 static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
133 struct gpiochip_info *cinfo;
134 struct gpiochip_info *current;
135 const struct dirent *ent;
136 DIR *dp;
137 char *chrdev_name;
138 int fd;
139 int i = 0;
141 cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
142 if (!cinfo)
143 err(EXIT_FAILURE, "gpiochip_info allocation failed");
145 current = cinfo;
146 dp = opendir("/dev");
147 if (!dp) {
148 *ret = -errno;
149 goto error_out;
150 } else {
151 *ret = 0;
154 while (ent = readdir(dp), ent) {
155 if (check_prefix(ent->d_name, "gpiochip")) {
156 *ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name);
157 if (*ret < 0)
158 goto error_out;
160 fd = open(chrdev_name, 0);
161 if (fd == -1) {
162 *ret = -errno;
163 fprintf(stderr, "Failed to open %s\n",
164 chrdev_name);
165 goto error_close_dir;
167 *ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current);
168 if (*ret == -1) {
169 perror("Failed to issue CHIPINFO IOCTL\n");
170 goto error_close_dir;
172 close(fd);
173 if (strcmp(current->label, gpiochip_name) == 0
174 || check_prefix(current->label, gpiochip_name)) {
175 *ret = 0;
176 current++;
177 i++;
182 if ((!*ret && i == 0) || *ret < 0) {
183 free(cinfo);
184 cinfo = NULL;
186 if (!*ret && i > 0) {
187 cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
188 *ret = i;
191 error_close_dir:
192 closedir(dp);
193 error_out:
194 if (*ret < 0)
195 err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
197 return cinfo;
200 int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
202 struct gpiohandle_data data;
203 unsigned int lines[] = {line};
204 int fd;
205 int debugfs_dir = IN;
206 int debugfs_value = 0;
207 int ret;
209 data.values[0] = value;
210 ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data,
211 CONSUMER);
212 if (ret < 0)
213 goto fail_out;
214 else
215 fd = ret;
217 ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
218 if (ret) {
219 ret = -EINVAL;
220 goto fail_out;
222 if (flag & GPIOHANDLE_REQUEST_INPUT) {
223 if (debugfs_dir != IN) {
224 errno = -EINVAL;
225 ret = -errno;
227 } else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
228 if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
229 debugfs_value = !debugfs_value;
231 if (!(debugfs_dir == OUT && value == debugfs_value)) {
232 errno = -EINVAL;
233 ret = -errno;
236 gpiotools_release_linehandle(fd);
238 fail_out:
239 if (ret)
240 err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
241 cinfo->name, line, flag, value);
243 return ret;
246 void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
248 printf("line<%d>", line);
249 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0);
250 printf(".");
251 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1);
252 printf(".");
253 gpio_pin_test(cinfo, line,
254 GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
256 printf(".");
257 gpio_pin_test(cinfo, line,
258 GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
260 printf(".");
261 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
262 printf(".");
266 * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip
267 * Return 0 if successful or exit with EXIT_FAILURE if test failed.
268 * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g.
269 * gpio-mockup
270 * is_valid_gpio_chip: Whether the gpio_chip is valid. 1 means valid,
271 * 0 means invalid which could not be found by
272 * list_gpiochip.
274 int main(int argc, char *argv[])
276 char *prefix;
277 int valid;
278 struct gpiochip_info *cinfo;
279 struct gpiochip_info *current;
280 int i;
281 int ret;
283 if (argc < 3) {
284 printf("Usage: %s prefix is_valid", argv[0]);
285 exit(EXIT_FAILURE);
288 prefix = argv[1];
289 valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
291 printf("Test gpiochip %s: ", prefix);
292 cinfo = list_gpiochip(prefix, &ret);
293 if (!cinfo) {
294 if (!valid && ret == 0) {
295 printf("Invalid test successful\n");
296 ret = 0;
297 goto out;
298 } else {
299 ret = -EINVAL;
300 goto out;
302 } else if (cinfo && !valid) {
303 ret = -EINVAL;
304 goto out;
306 current = cinfo;
307 for (i = 0; i < ret; i++) {
308 gpio_pin_tests(current, 0);
309 gpio_pin_tests(current, current->lines - 1);
310 gpio_pin_tests(current, random() % current->lines);
311 current++;
313 ret = 0;
314 printf("successful\n");
316 out:
317 if (ret)
318 fprintf(stderr, "gpio<%s> test failed\n", prefix);
320 if (cinfo)
321 free(cinfo);
323 if (ret)
324 exit(EXIT_FAILURE);
326 return ret;