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