1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * lsgpio - example on how to list the GPIO lines on a system 4 * 5 * Copyright (C) 2015 Linus Walleij 6 * 7 * Usage: 8 * lsgpio <-n device-name> 9 */ 10 11 #include <unistd.h> 12 #include <stdlib.h> 13 #include <stdbool.h> 14 #include <stdio.h> 15 #include <dirent.h> 16 #include <errno.h> 17 #include <string.h> 18 #include <poll.h> 19 #include <fcntl.h> 20 #include <getopt.h> 21 #include <sys/ioctl.h> 22 #include <linux/gpio.h> 23 24 #include "gpio-utils.h" 25 26 struct gpio_flag { 27 char *name; 28 unsigned long mask; 29 }; 30 31 struct gpio_flag flagnames[] = { 32 { 33 .name = "kernel", 34 .mask = GPIOLINE_FLAG_KERNEL, 35 }, 36 { 37 .name = "output", 38 .mask = GPIOLINE_FLAG_IS_OUT, 39 }, 40 { 41 .name = "active-low", 42 .mask = GPIOLINE_FLAG_ACTIVE_LOW, 43 }, 44 { 45 .name = "open-drain", 46 .mask = GPIOLINE_FLAG_OPEN_DRAIN, 47 }, 48 { 49 .name = "open-source", 50 .mask = GPIOLINE_FLAG_OPEN_SOURCE, 51 }, 52 { 53 .name = "pull-up", 54 .mask = GPIOLINE_FLAG_BIAS_PULL_UP, 55 }, 56 { 57 .name = "pull-down", 58 .mask = GPIOLINE_FLAG_BIAS_PULL_DOWN, 59 }, 60 { 61 .name = "bias-disabled", 62 .mask = GPIOLINE_FLAG_BIAS_DISABLE, 63 }, 64 }; 65 66 void print_flags(unsigned long flags) 67 { 68 int i; 69 int printed = 0; 70 71 for (i = 0; i < ARRAY_SIZE(flagnames); i++) { 72 if (flags & flagnames[i].mask) { 73 if (printed) 74 fprintf(stdout, " "); 75 fprintf(stdout, "%s", flagnames[i].name); 76 printed++; 77 } 78 } 79 } 80 81 int list_device(const char *device_name) 82 { 83 struct gpiochip_info cinfo; 84 char *chrdev_name; 85 int fd; 86 int ret; 87 int i; 88 89 ret = asprintf(&chrdev_name, "/dev/%s", device_name); 90 if (ret < 0) 91 return -ENOMEM; 92 93 fd = open(chrdev_name, 0); 94 if (fd == -1) { 95 ret = -errno; 96 fprintf(stderr, "Failed to open %s\n", chrdev_name); 97 goto exit_close_error; 98 } 99 100 /* Inspect this GPIO chip */ 101 ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo); 102 if (ret == -1) { 103 ret = -errno; 104 perror("Failed to issue CHIPINFO IOCTL\n"); 105 goto exit_close_error; 106 } 107 fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n", 108 cinfo.name, cinfo.label, cinfo.lines); 109 110 /* Loop over the lines and print info */ 111 for (i = 0; i < cinfo.lines; i++) { 112 struct gpioline_info linfo; 113 114 memset(&linfo, 0, sizeof(linfo)); 115 linfo.line_offset = i; 116 117 ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo); 118 if (ret == -1) { 119 ret = -errno; 120 perror("Failed to issue LINEINFO IOCTL\n"); 121 goto exit_close_error; 122 } 123 fprintf(stdout, "\tline %2d:", linfo.line_offset); 124 if (linfo.name[0]) 125 fprintf(stdout, " \"%s\"", linfo.name); 126 else 127 fprintf(stdout, " unnamed"); 128 if (linfo.consumer[0]) 129 fprintf(stdout, " \"%s\"", linfo.consumer); 130 else 131 fprintf(stdout, " unused"); 132 if (linfo.flags) { 133 fprintf(stdout, " ["); 134 print_flags(linfo.flags); 135 fprintf(stdout, "]"); 136 } 137 fprintf(stdout, "\n"); 138 139 } 140 141 exit_close_error: 142 if (close(fd) == -1) 143 perror("Failed to close GPIO character device file"); 144 free(chrdev_name); 145 return ret; 146 } 147 148 void print_usage(void) 149 { 150 fprintf(stderr, "Usage: lsgpio [options]...\n" 151 "List GPIO chips, lines and states\n" 152 " -n <name> List GPIOs on a named device\n" 153 " -? This helptext\n" 154 ); 155 } 156 157 int main(int argc, char **argv) 158 { 159 const char *device_name = NULL; 160 int ret; 161 int c; 162 163 while ((c = getopt(argc, argv, "n:")) != -1) { 164 switch (c) { 165 case 'n': 166 device_name = optarg; 167 break; 168 case '?': 169 print_usage(); 170 return -1; 171 } 172 } 173 174 if (device_name) 175 ret = list_device(device_name); 176 else { 177 const struct dirent *ent; 178 DIR *dp; 179 180 /* List all GPIO devices one at a time */ 181 dp = opendir("/dev"); 182 if (!dp) { 183 ret = -errno; 184 goto error_out; 185 } 186 187 ret = -ENOENT; 188 while (ent = readdir(dp), ent) { 189 if (check_prefix(ent->d_name, "gpiochip")) { 190 ret = list_device(ent->d_name); 191 if (ret) 192 break; 193 } 194 } 195 196 ret = 0; 197 if (closedir(dp) == -1) { 198 perror("scanning devices: Failed to close directory"); 199 ret = -errno; 200 } 201 } 202 error_out: 203 return ret; 204 } 205