root/tools/testing/selftests/gpio/gpio-mockup-chardev.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_debugfs
  2. gpio_debugfs_get
  3. list_gpiochip
  4. gpio_pin_test
  5. gpio_pin_tests
  6. main

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

/* [<][>][^][v][top][bottom][index][help] */