1 // SPDX-License-Identifier: GPL-2.0-only
3 * GPIO chardev test helper
5 * Copyright (C) 2016 Bamvor Jian Zhang
16 #include <sys/ioctl.h>
20 #include <linux/gpio.h>
21 #include "../../../gpio/gpio-utils.h"
23 #define CONSUMER "gpio-selftest"
30 static int get_debugfs(char **path)
32 struct libmnt_context *cxt;
33 struct libmnt_table *tb;
34 struct libmnt_iter *itr = NULL;
38 cxt = mnt_new_context();
40 err(EXIT_FAILURE, "libmount context allocation failed");
42 itr = mnt_new_iter(MNT_ITER_FORWARD);
44 err(EXIT_FAILURE, "failed to initialize libmount iterator");
46 if (mnt_context_get_mtab(cxt, &tb))
47 err(EXIT_FAILURE, "failed to read mtab");
49 while (mnt_table_next_fs(tb, itr, &fs) == 0) {
50 const char *type = mnt_fs_get_fstype(fs);
52 if (!strcmp(type, "debugfs")) {
58 ret = asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
60 err(EXIT_FAILURE, "failed to format string");
64 mnt_free_context(cxt);
72 static int gpio_debugfs_get(const char *consumer, int *dir, int *value)
81 if (get_debugfs(&debugfs) != 0)
82 err(EXIT_FAILURE, "debugfs is not mounted");
84 f = fopen(debugfs, "r");
86 err(EXIT_FAILURE, "read from gpio debugfs failed");
89 * gpio-2 ( |gpio-selftest ) in lo
91 while (getline(&line, &len, f) != -1) {
92 cur = strstr(line, consumer);
96 cur = strchr(line, ')');
101 if (!strncmp(cur, "out", 3)) {
104 } else if (!strncmp(cur, "in", 2)) {
109 if (!strncmp(cur, "hi", 2))
111 else if (!strncmp(cur, "lo", 2))
127 static struct gpiochip_info *list_gpiochip(const char *gpiochip_name, int *ret)
129 struct gpiochip_info *cinfo;
130 struct gpiochip_info *current;
131 const struct dirent *ent;
137 cinfo = calloc(sizeof(struct gpiochip_info) * 4, GC_NUM + 1);
139 err(EXIT_FAILURE, "gpiochip_info allocation failed");
142 dp = opendir("/dev");
150 while (ent = readdir(dp), ent) {
151 if (check_prefix(ent->d_name, "gpiochip")) {
152 *ret = asprintf(&chrdev_name, "/dev/%s", ent->d_name);
156 fd = open(chrdev_name, 0);
159 fprintf(stderr, "Failed to open %s\n",
161 goto error_close_dir;
163 *ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, current);
165 perror("Failed to issue CHIPINFO IOCTL\n");
166 goto error_close_dir;
169 if (strcmp(current->label, gpiochip_name) == 0
170 || check_prefix(current->label, gpiochip_name)) {
178 if ((!*ret && i == 0) || *ret < 0) {
182 if (!*ret && i > 0) {
183 cinfo = realloc(cinfo, sizeof(struct gpiochip_info) * 4 * i);
191 err(EXIT_FAILURE, "list gpiochip failed: %s", strerror(*ret));
196 int gpio_pin_test(struct gpiochip_info *cinfo, int line, int flag, int value)
198 struct gpiohandle_data data;
199 unsigned int lines[] = {line};
201 int debugfs_dir = IN;
202 int debugfs_value = 0;
205 data.values[0] = value;
206 ret = gpiotools_request_linehandle(cinfo->name, lines, 1, flag, &data,
213 ret = gpio_debugfs_get(CONSUMER, &debugfs_dir, &debugfs_value);
218 if (flag & GPIOHANDLE_REQUEST_INPUT) {
219 if (debugfs_dir != IN) {
223 } else if (flag & GPIOHANDLE_REQUEST_OUTPUT) {
224 if (flag & GPIOHANDLE_REQUEST_ACTIVE_LOW)
225 debugfs_value = !debugfs_value;
227 if (!(debugfs_dir == OUT && value == debugfs_value)) {
232 gpiotools_release_linehandle(fd);
236 err(EXIT_FAILURE, "gpio<%s> line<%d> test flag<0x%x> value<%d>",
237 cinfo->name, line, flag, value);
242 void gpio_pin_tests(struct gpiochip_info *cinfo, unsigned int line)
244 printf("line<%d>", line);
245 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 0);
247 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_OUTPUT, 1);
249 gpio_pin_test(cinfo, line,
250 GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
253 gpio_pin_test(cinfo, line,
254 GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW,
257 gpio_pin_test(cinfo, line, GPIOHANDLE_REQUEST_INPUT, 0);
262 * ./gpio-mockup-chardev gpio_chip_name_prefix is_valid_gpio_chip
263 * Return 0 if successful or exit with EXIT_FAILURE if test failed.
264 * gpio_chip_name_prefix: The prefix of gpiochip you want to test. E.g.
266 * is_valid_gpio_chip: Whether the gpio_chip is valid. 1 means valid,
267 * 0 means invalid which could not be found by
270 int main(int argc, char *argv[])
274 struct gpiochip_info *cinfo;
275 struct gpiochip_info *current;
280 printf("Usage: %s prefix is_valid", argv[0]);
285 valid = strcmp(argv[2], "true") == 0 ? 1 : 0;
287 printf("Test gpiochip %s: ", prefix);
288 cinfo = list_gpiochip(prefix, &ret);
290 if (!valid && ret == 0) {
291 printf("Invalid test successful\n");
298 } else if (cinfo && !valid) {
303 for (i = 0; i < ret; i++) {
304 gpio_pin_tests(current, 0);
305 gpio_pin_tests(current, current->lines - 1);
306 gpio_pin_tests(current, random() % current->lines);
310 printf("successful\n");
314 fprintf(stderr, "gpio<%s> test failed\n", prefix);