[btrfs] fix check_direct_IO() for non-iovec iterators
[cascardo/linux.git] / tools / gpio / lsgpio.c
1 /*
2  * lsgpio - example on how to list the GPIO lines on a system
3  *
4  * Copyright (C) 2015 Linus Walleij
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by
8  * the Free Software Foundation.
9  *
10  * Usage:
11  *      lsgpio <-n device-name>
12  */
13
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <stdbool.h>
17 #include <stdio.h>
18 #include <dirent.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <poll.h>
22 #include <fcntl.h>
23 #include <getopt.h>
24 #include <sys/ioctl.h>
25 #include <linux/gpio.h>
26
27 #include "gpio-utils.h"
28
29 struct gpio_flag {
30         char *name;
31         unsigned long mask;
32 };
33
34 struct gpio_flag flagnames[] = {
35         {
36                 .name = "kernel",
37                 .mask = GPIOLINE_FLAG_KERNEL,
38         },
39         {
40                 .name = "output",
41                 .mask = GPIOLINE_FLAG_IS_OUT,
42         },
43         {
44                 .name = "active-low",
45                 .mask = GPIOLINE_FLAG_ACTIVE_LOW,
46         },
47         {
48                 .name = "open-drain",
49                 .mask = GPIOLINE_FLAG_OPEN_DRAIN,
50         },
51         {
52                 .name = "open-source",
53                 .mask = GPIOLINE_FLAG_OPEN_SOURCE,
54         },
55 };
56
57 void print_flags(unsigned long flags)
58 {
59         int i;
60         int printed = 0;
61
62         for (i = 0; i < ARRAY_SIZE(flagnames); i++) {
63                 if (flags & flagnames[i].mask) {
64                         if (printed)
65                                 fprintf(stdout, " ");
66                         fprintf(stdout, "%s", flagnames[i].name);
67                         printed++;
68                 }
69         }
70 }
71
72 int list_device(const char *device_name)
73 {
74         struct gpiochip_info cinfo;
75         char *chrdev_name;
76         int fd;
77         int ret;
78         int i;
79
80         ret = asprintf(&chrdev_name, "/dev/%s", device_name);
81         if (ret < 0)
82                 return -ENOMEM;
83
84         fd = open(chrdev_name, 0);
85         if (fd == -1) {
86                 ret = -errno;
87                 fprintf(stderr, "Failed to open %s\n", chrdev_name);
88                 goto exit_close_error;
89         }
90
91         /* Inspect this GPIO chip */
92         ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);
93         if (ret == -1) {
94                 ret = -errno;
95                 perror("Failed to issue CHIPINFO IOCTL\n");
96                 goto exit_close_error;
97         }
98         fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines\n",
99                 cinfo.name, cinfo.label, cinfo.lines);
100
101         /* Loop over the lines and print info */
102         for (i = 0; i < cinfo.lines; i++) {
103                 struct gpioline_info linfo;
104
105                 memset(&linfo, 0, sizeof(linfo));
106                 linfo.line_offset = i;
107
108                 ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &linfo);
109                 if (ret == -1) {
110                         ret = -errno;
111                         perror("Failed to issue LINEINFO IOCTL\n");
112                         goto exit_close_error;
113                 }
114                 fprintf(stdout, "\tline %2d:", linfo.line_offset);
115                 if (linfo.name[0])
116                         fprintf(stdout, " \"%s\"", linfo.name);
117                 else
118                         fprintf(stdout, " unnamed");
119                 if (linfo.consumer[0])
120                         fprintf(stdout, " \"%s\"", linfo.consumer);
121                 else
122                         fprintf(stdout, " unused");
123                 if (linfo.flags) {
124                         fprintf(stdout, " [");
125                         print_flags(linfo.flags);
126                         fprintf(stdout, "]");
127                 }
128                 fprintf(stdout, "\n");
129
130         }
131
132 exit_close_error:
133         if (close(fd) == -1)
134                 perror("Failed to close GPIO character device file");
135         free(chrdev_name);
136         return ret;
137 }
138
139 void print_usage(void)
140 {
141         fprintf(stderr, "Usage: lsgpio [options]...\n"
142                 "List GPIO chips, lines and states\n"
143                 "  -n <name>  List GPIOs on a named device\n"
144                 "  -?         This helptext\n"
145         );
146 }
147
148 int main(int argc, char **argv)
149 {
150         const char *device_name = NULL;
151         int ret;
152         int c;
153
154         while ((c = getopt(argc, argv, "n:")) != -1) {
155                 switch (c) {
156                 case 'n':
157                         device_name = optarg;
158                         break;
159                 case '?':
160                         print_usage();
161                         return -1;
162                 }
163         }
164
165         if (device_name)
166                 ret = list_device(device_name);
167         else {
168                 const struct dirent *ent;
169                 DIR *dp;
170
171                 /* List all GPIO devices one at a time */
172                 dp = opendir("/dev");
173                 if (!dp) {
174                         ret = -errno;
175                         goto error_out;
176                 }
177
178                 ret = -ENOENT;
179                 while (ent = readdir(dp), ent) {
180                         if (check_prefix(ent->d_name, "gpiochip")) {
181                                 ret = list_device(ent->d_name);
182                                 if (ret)
183                                         break;
184                         }
185                 }
186
187                 ret = 0;
188                 if (closedir(dp) == -1) {
189                         perror("scanning devices: Failed to close directory");
190                         ret = -errno;
191                 }
192         }
193 error_out:
194         return ret;
195 }