Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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