linux/tools/gpio/lsgpio.c
<<
>>
Prefs
   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
  26struct gpio_flag {
  27        char *name;
  28        unsigned long long mask;
  29};
  30
  31struct gpio_flag flagnames[] = {
  32        {
  33                .name = "used",
  34                .mask = GPIO_V2_LINE_FLAG_USED,
  35        },
  36        {
  37                .name = "input",
  38                .mask = GPIO_V2_LINE_FLAG_INPUT,
  39        },
  40        {
  41                .name = "output",
  42                .mask = GPIO_V2_LINE_FLAG_OUTPUT,
  43        },
  44        {
  45                .name = "active-low",
  46                .mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW,
  47        },
  48        {
  49                .name = "open-drain",
  50                .mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN,
  51        },
  52        {
  53                .name = "open-source",
  54                .mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE,
  55        },
  56        {
  57                .name = "pull-up",
  58                .mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP,
  59        },
  60        {
  61                .name = "pull-down",
  62                .mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN,
  63        },
  64        {
  65                .name = "bias-disabled",
  66                .mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED,
  67        },
  68        {
  69                .name = "clock-realtime",
  70                .mask = GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME,
  71        },
  72};
  73
  74static void print_attributes(struct gpio_v2_line_info *info)
  75{
  76        int i;
  77        const char *field_format = "%s";
  78
  79        for (i = 0; i < ARRAY_SIZE(flagnames); i++) {
  80                if (info->flags & flagnames[i].mask) {
  81                        fprintf(stdout, field_format, flagnames[i].name);
  82                        field_format = ", %s";
  83                }
  84        }
  85
  86        if ((info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) &&
  87            (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING))
  88                fprintf(stdout, field_format, "both-edges");
  89        else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING)
  90                fprintf(stdout, field_format, "rising-edge");
  91        else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING)
  92                fprintf(stdout, field_format, "falling-edge");
  93
  94        for (i = 0; i < info->num_attrs; i++) {
  95                if (info->attrs[i].id == GPIO_V2_LINE_ATTR_ID_DEBOUNCE)
  96                        fprintf(stdout, ", debounce_period=%dusec",
  97                                info->attrs[0].debounce_period_us);
  98        }
  99}
 100
 101int list_device(const char *device_name)
 102{
 103        struct gpiochip_info cinfo;
 104        char *chrdev_name;
 105        int fd;
 106        int ret;
 107        int i;
 108
 109        ret = asprintf(&chrdev_name, "/dev/%s", device_name);
 110        if (ret < 0)
 111                return -ENOMEM;
 112
 113        fd = open(chrdev_name, 0);
 114        if (fd == -1) {
 115                ret = -errno;
 116                fprintf(stderr, "Failed to open %s\n", chrdev_name);
 117                goto exit_free_name;
 118        }
 119
 120        /* Inspect this GPIO chip */
 121        ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);
 122        if (ret == -1) {
 123                ret = -errno;
 124                perror("Failed to issue CHIPINFO IOCTL\n");
 125                goto exit_close_error;
 126        }
 127        fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n",
 128                cinfo.name, cinfo.label, cinfo.lines);
 129
 130        /* Loop over the lines and print info */
 131        for (i = 0; i < cinfo.lines; i++) {
 132                struct gpio_v2_line_info linfo;
 133
 134                memset(&linfo, 0, sizeof(linfo));
 135                linfo.offset = i;
 136
 137                ret = ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &linfo);
 138                if (ret == -1) {
 139                        ret = -errno;
 140                        perror("Failed to issue LINEINFO IOCTL\n");
 141                        goto exit_close_error;
 142                }
 143                fprintf(stdout, "\tline %2d:", linfo.offset);
 144                if (linfo.name[0])
 145                        fprintf(stdout, " \"%s\"", linfo.name);
 146                else
 147                        fprintf(stdout, " unnamed");
 148                if (linfo.consumer[0])
 149                        fprintf(stdout, " \"%s\"", linfo.consumer);
 150                else
 151                        fprintf(stdout, " unused");
 152                if (linfo.flags) {
 153                        fprintf(stdout, " [");
 154                        print_attributes(&linfo);
 155                        fprintf(stdout, "]");
 156                }
 157                fprintf(stdout, "\n");
 158
 159        }
 160
 161exit_close_error:
 162        if (close(fd) == -1)
 163                perror("Failed to close GPIO character device file");
 164exit_free_name:
 165        free(chrdev_name);
 166        return ret;
 167}
 168
 169void print_usage(void)
 170{
 171        fprintf(stderr, "Usage: lsgpio [options]...\n"
 172                "List GPIO chips, lines and states\n"
 173                "  -n <name>  List GPIOs on a named device\n"
 174                "  -?         This helptext\n"
 175        );
 176}
 177
 178int main(int argc, char **argv)
 179{
 180        const char *device_name = NULL;
 181        int ret;
 182        int c;
 183
 184        while ((c = getopt(argc, argv, "n:")) != -1) {
 185                switch (c) {
 186                case 'n':
 187                        device_name = optarg;
 188                        break;
 189                case '?':
 190                        print_usage();
 191                        return -1;
 192                }
 193        }
 194
 195        if (device_name)
 196                ret = list_device(device_name);
 197        else {
 198                const struct dirent *ent;
 199                DIR *dp;
 200
 201                /* List all GPIO devices one at a time */
 202                dp = opendir("/dev");
 203                if (!dp) {
 204                        ret = -errno;
 205                        goto error_out;
 206                }
 207
 208                ret = -ENOENT;
 209                while (ent = readdir(dp), ent) {
 210                        if (check_prefix(ent->d_name, "gpiochip")) {
 211                                ret = list_device(ent->d_name);
 212                                if (ret)
 213                                        break;
 214                        }
 215                }
 216
 217                ret = 0;
 218                if (closedir(dp) == -1) {
 219                        perror("scanning devices: Failed to close directory");
 220                        ret = -errno;
 221                }
 222        }
 223error_out:
 224        return ret;
 225}
 226