OSDN Git Service

Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[uclinux-h8/linux.git] / tools / testing / selftests / gpio / gpio-mockup-chardev.c
1 /*
2  * GPIO chardev test helper
3  *
4  * Copyright (C) 2016 Bamvor Jian Zhang
5  *
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  */
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
29 enum direction {
30         OUT,
31         IN
32 };
33
34 static 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, ret;
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                 ret = asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
63                 if (ret < 0)
64                         err(EXIT_FAILURE, "failed to format string");
65         }
66
67         mnt_free_iter(itr);
68         mnt_free_context(cxt);
69
70         if (!found)
71                 return -1;
72
73         return 0;
74 }
75
76 static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
77 {
78         char *debugfs;
79         FILE *f;
80         char *line = NULL;
81         size_t len = 0;
82         char *cur;
83         int found = 0;
84
85         if (get_debugfs(&debugfs) != 0)
86                 err(EXIT_FAILURE, "debugfs is not mounted");
87
88         f = fopen(debugfs, "r");
89         if (!f)
90                 err(EXIT_FAILURE, "read from gpio debugfs failed");
91
92         /*
93          * gpio-2   (                    |gpio-selftest               ) in  lo
94          */
95         while (getline(&line, &len, f) != -1) {
96                 cur = strstr(line, consumer);
97                 if (cur == NULL)
98                         continue;
99
100                 cur = strchr(line, ')');
101                 if (!cur)
102                         continue;
103
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;
111                 }
112
113                 if (!strncmp(cur, "hi", 2))
114                         *value = 1;
115                 else if (!strncmp(cur, "lo", 2))
116                         *value = 0;
117
118                 found = 1;
119                 break;
120         }
121         free(debugfs);
122         fclose(f);
123         free(line);
124
125         if (!found)
126                 return -1;
127
128         return 0;
129 }
130
131 static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
132 {
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;
140
141         cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
142         if (!cinfo)
143                 err(EXIT_FAILURE, "gpiochip_info allocation failed");
144
145         current = cinfo;
146         dp = opendir("/dev");
147         if (!dp) {
148                 *ret = -errno;
149                 goto error_out;
150         } else {
151                 *ret = 0;
152         }
153
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;
159
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;
166                         }
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;
171                         }
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++;
178                         }
179                 }
180         }
181
182         if ((!*ret && i == 0) || *ret < 0) {
183                 free(cinfo);
184                 cinfo = NULL;
185         }
186         if (!*ret && i > 0) {
187                 cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
188                 *ret = i;
189         }
190
191 error_close_dir:
192         closedir(dp);
193 error_out:
194         if (*ret < 0)
195                 err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
196
197         return cinfo;
198 }
199
200 int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
201 {
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;
208
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;
216
217         ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
218         if (ret) {
219                 ret = -EINVAL;
220                 goto fail_out;
221         }
222         if (flag & GPIOHANDLE_REQUEST_INPUT) {
223                 if (debugfs_dir != IN) {
224                         errno = -EINVAL;
225                         ret = -errno;
226                 }
227         } else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
228                 if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
229                         debugfs_value = !debugfs_value;
230
231                 if (!(debugfs_dir == OUT && value == debugfs_value)) {
232                         errno = -EINVAL;
233                         ret = -errno;
234                 }
235         }
236         gpiotools_release_linehandle(fd);
237
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);
242
243         return ret;
244 }
245
246 void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
247 {
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,
255                       0);
256         printf(".");
257         gpio_pin_test(cinfo, line,
258                       GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
259                       1);
260         printf(".");
261         gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
262         printf(".");
263 }
264
265 /*
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.
273  */
274 int main(int argc, char *argv[])
275 {
276         char *prefix;
277         int valid;
278         struct gpiochip_info *cinfo;
279         struct gpiochip_info *current;
280         int i;
281         int ret;
282
283         if (argc < 3) {
284                 printf("Usage: %s prefix is_valid", argv[0]);
285                 exit(EXIT_FAILURE);
286         }
287
288         prefix = argv[1];
289         valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
290
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;
301                 }
302         } else if (cinfo && !valid) {
303                 ret = -EINVAL;
304                 goto out;
305         }
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++;
312         }
313         ret = 0;
314         printf("successful\n");
315
316 out:
317         if (ret)
318                 fprintf(stderr, "gpio<%s> test failed\n", prefix);
319
320         if (cinfo)
321                 free(cinfo);
322
323         if (ret)
324                 exit(EXIT_FAILURE);
325
326         return ret;
327 }