Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * lsgpio - example on how to list the GPIO lines on a system
0004  *
0005  * Copyright (C) 2015 Linus Walleij
0006  *
0007  * Usage:
0008  *  lsgpio <-n device-name>
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     /* Inspect this GPIO chip */
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     /* Loop over the lines and print info */
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         /* List all GPIO devices one at a time */
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 }