0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <unistd.h>
0012 #include <stdlib.h>
0013 #include <stdbool.h>
0014 #include <stdio.h>
0015 #include <dirent.h>
0016 #include <errno.h>
0017 #include <string.h>
0018 #include <poll.h>
0019 #include <fcntl.h>
0020 #include <getopt.h>
0021 #include <sys/ioctl.h>
0022 #include <linux/gpio.h>
0023
0024 #include "gpio-utils.h"
0025
0026 struct gpio_flag {
0027 char *name;
0028 unsigned long long mask;
0029 };
0030
0031 struct gpio_flag flagnames[] = {
0032 {
0033 .name = "used",
0034 .mask = GPIO_V2_LINE_FLAG_USED,
0035 },
0036 {
0037 .name = "input",
0038 .mask = GPIO_V2_LINE_FLAG_INPUT,
0039 },
0040 {
0041 .name = "output",
0042 .mask = GPIO_V2_LINE_FLAG_OUTPUT,
0043 },
0044 {
0045 .name = "active-low",
0046 .mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW,
0047 },
0048 {
0049 .name = "open-drain",
0050 .mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN,
0051 },
0052 {
0053 .name = "open-source",
0054 .mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE,
0055 },
0056 {
0057 .name = "pull-up",
0058 .mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP,
0059 },
0060 {
0061 .name = "pull-down",
0062 .mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN,
0063 },
0064 {
0065 .name = "bias-disabled",
0066 .mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED,
0067 },
0068 {
0069 .name = "clock-realtime",
0070 .mask = GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME,
0071 },
0072 };
0073
0074 static void print_attributes(struct gpio_v2_line_info *info)
0075 {
0076 int i;
0077 const char *field_format = "%s";
0078
0079 for (i = 0; i < ARRAY_SIZE(flagnames); i++) {
0080 if (info->flags & flagnames[i].mask) {
0081 fprintf(stdout, field_format, flagnames[i].name);
0082 field_format = ", %s";
0083 }
0084 }
0085
0086 if ((info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) &&
0087 (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING))
0088 fprintf(stdout, field_format, "both-edges");
0089 else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING)
0090 fprintf(stdout, field_format, "rising-edge");
0091 else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING)
0092 fprintf(stdout, field_format, "falling-edge");
0093
0094 for (i = 0; i < info->num_attrs; i++) {
0095 if (info->attrs[i].id == GPIO_V2_LINE_ATTR_ID_DEBOUNCE)
0096 fprintf(stdout, ", debounce_period=%dusec",
0097 info->attrs[0].debounce_period_us);
0098 }
0099 }
0100
0101 int list_device(const char *device_name)
0102 {
0103 struct gpiochip_info cinfo;
0104 char *chrdev_name;
0105 int fd;
0106 int ret;
0107 int i;
0108
0109 ret = asprintf(&chrdev_name, "/dev/%s", device_name);
0110 if (ret < 0)
0111 return -ENOMEM;
0112
0113 fd = open(chrdev_name, 0);
0114 if (fd == -1) {
0115 ret = -errno;
0116 fprintf(stderr, "Failed to open %s\n", chrdev_name);
0117 goto exit_free_name;
0118 }
0119
0120
0121 ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);
0122 if (ret == -1) {
0123 ret = -errno;
0124 perror("Failed to issue CHIPINFO IOCTL\n");
0125 goto exit_close_error;
0126 }
0127 fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n",
0128 cinfo.name, cinfo.label, cinfo.lines);
0129
0130
0131 for (i = 0; i < cinfo.lines; i++) {
0132 struct gpio_v2_line_info linfo;
0133
0134 memset(&linfo, 0, sizeof(linfo));
0135 linfo.offset = i;
0136
0137 ret = ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &linfo);
0138 if (ret == -1) {
0139 ret = -errno;
0140 perror("Failed to issue LINEINFO IOCTL\n");
0141 goto exit_close_error;
0142 }
0143 fprintf(stdout, "\tline %2d:", linfo.offset);
0144 if (linfo.name[0])
0145 fprintf(stdout, " \"%s\"", linfo.name);
0146 else
0147 fprintf(stdout, " unnamed");
0148 if (linfo.consumer[0])
0149 fprintf(stdout, " \"%s\"", linfo.consumer);
0150 else
0151 fprintf(stdout, " unused");
0152 if (linfo.flags) {
0153 fprintf(stdout, " [");
0154 print_attributes(&linfo);
0155 fprintf(stdout, "]");
0156 }
0157 fprintf(stdout, "\n");
0158
0159 }
0160
0161 exit_close_error:
0162 if (close(fd) == -1)
0163 perror("Failed to close GPIO character device file");
0164 exit_free_name:
0165 free(chrdev_name);
0166 return ret;
0167 }
0168
0169 void print_usage(void)
0170 {
0171 fprintf(stderr, "Usage: lsgpio [options]...\n"
0172 "List GPIO chips, lines and states\n"
0173 " -n <name> List GPIOs on a named device\n"
0174 " -? This helptext\n"
0175 );
0176 }
0177
0178 int main(int argc, char **argv)
0179 {
0180 const char *device_name = NULL;
0181 int ret;
0182 int c;
0183
0184 while ((c = getopt(argc, argv, "n:")) != -1) {
0185 switch (c) {
0186 case 'n':
0187 device_name = optarg;
0188 break;
0189 case '?':
0190 print_usage();
0191 return -1;
0192 }
0193 }
0194
0195 if (device_name)
0196 ret = list_device(device_name);
0197 else {
0198 const struct dirent *ent;
0199 DIR *dp;
0200
0201
0202 dp = opendir("/dev");
0203 if (!dp) {
0204 ret = -errno;
0205 goto error_out;
0206 }
0207
0208 ret = -ENOENT;
0209 while (ent = readdir(dp), ent) {
0210 if (check_prefix(ent->d_name, "gpiochip")) {
0211 ret = list_device(ent->d_name);
0212 if (ret)
0213 break;
0214 }
0215 }
0216
0217 ret = 0;
0218 if (closedir(dp) == -1) {
0219 perror("scanning devices: Failed to close directory");
0220 ret = -errno;
0221 }
0222 }
0223 error_out:
0224 return ret;
0225 }