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 54 void print_flags(unsigned long flags) 55 { 56 int i; 57 int printed = 0; 58 59 for (i = 0; i < ARRAY_SIZE(flagnames); i++) { 60 if (flags & flagnames[i].mask) { 61 if (printed) 62 fprintf(stdout, " "); 63 fprintf(stdout, "%s", flagnames[i].name); 64 printed++; 65 } 66 } 67 } 68 69 int list_device(const char *device_name) 70 { 71 struct gpiochip_info cinfo; 72 char *chrdev_name; 73 int fd; 74 int ret; 75 int i; 76 77 ret = asprintf(&chrdev_name, "/dev/%s", device_name); 78 if (ret < 0) 79 return -ENOMEM; 80 81 fd = open(chrdev_name, 0); 82 if (fd == -1) { 83 ret = -errno; 84 fprintf(stderr, "Failed to open %s\n", chrdev_name); 85 goto exit_close_error; 86 } 87 88 /* Inspect this GPIO chip */ 89 ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo); 90 if (ret == -1) { 91 ret = -errno; 92 perror("Failed to issue CHIPINFO IOCTL\n"); 93 goto exit_close_error; 94 } 95 fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n", 96 cinfo.name, cinfo.label, cinfo.lines); 97 98 /* Loop over the lines and print info */ 99 for (i = 0; i < cinfo.lines; i++) { 100 struct gpioline_info linfo; 101 102 memset(&linfo, 0, sizeof(linfo)); 103 linfo.line_offset = i; 104 105 ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo); 106 if (ret == -1) { 107 ret = -errno; 108 perror("Failed to issue LINEINFO IOCTL\n"); 109 goto exit_close_error; 110 } 111 fprintf(stdout, "\tline %2d:", linfo.line_offset); 112 if (linfo.name[0]) 113 fprintf(stdout, " \"%s\"", linfo.name); 114 else 115 fprintf(stdout, " unnamed"); 116 if (linfo.consumer[0]) 117 fprintf(stdout, " \"%s\"", linfo.consumer); 118 else 119 fprintf(stdout, " unused"); 120 if (linfo.flags) { 121 fprintf(stdout, " ["); 122 print_flags(linfo.flags); 123 fprintf(stdout, "]"); 124 } 125 fprintf(stdout, "\n"); 126 127 } 128 129 exit_close_error: 130 if (close(fd) == -1) 131 perror("Failed to close GPIO character device file"); 132 free(chrdev_name); 133 return ret; 134 } 135 136 void print_usage(void) 137 { 138 fprintf(stderr, "Usage: lsgpio [options]...\n" 139 "List GPIO chips, lines and states\n" 140 " -n <name> List GPIOs on a named device\n" 141 " -? This helptext\n" 142 ); 143 } 144 145 int main(int argc, char **argv) 146 { 147 const char *device_name = NULL; 148 int ret; 149 int c; 150 151 while ((c = getopt(argc, argv, "n:")) != -1) { 152 switch (c) { 153 case 'n': 154 device_name = optarg; 155 break; 156 case '?': 157 print_usage(); 158 return -1; 159 } 160 } 161 162 if (device_name) 163 ret = list_device(device_name); 164 else { 165 const struct dirent *ent; 166 DIR *dp; 167 168 /* List all GPIO devices one at a time */ 169 dp = opendir("/dev"); 170 if (!dp) { 171 ret = -errno; 172 goto error_out; 173 } 174 175 ret = -ENOENT; 176 while (ent = readdir(dp), ent) { 177 if (check_prefix(ent->d_name, "gpiochip")) { 178 ret = list_device(ent->d_name); 179 if (ret) 180 break; 181 } 182 } 183 184 ret = 0; 185 if (closedir(dp) == -1) { 186 perror("scanning devices: Failed to close directory"); 187 ret = -errno; 188 } 189 } 190 error_out: 191 return ret; 192 } 193