Merge tag 'xfs-5.6-merge-6' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[sfrench/cifs-2.6.git] / tools / gpio / lsgpio.c
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 }