Blame view

tools/gpio/lsgpio.c 4.42 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
6d591c46b   Linus Walleij   tools/gpio: creat...
2
3
4
5
6
  /*
   * lsgpio - example on how to list the GPIO lines on a system
   *
   * Copyright (C) 2015 Linus Walleij
   *
6d591c46b   Linus Walleij   tools/gpio: creat...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   * Usage:
   *	lsgpio <-n device-name>
   */
  
  #include <unistd.h>
  #include <stdlib.h>
  #include <stdbool.h>
  #include <stdio.h>
  #include <dirent.h>
  #include <errno.h>
  #include <string.h>
  #include <poll.h>
  #include <fcntl.h>
  #include <getopt.h>
  #include <sys/ioctl.h>
  #include <linux/gpio.h>
  
  #include "gpio-utils.h"
521a2ad6f   Linus Walleij   gpio: add userspa...
25
26
  struct gpio_flag {
  	char *name;
3c333c470   Kent Gibson   tools: gpio: port...
27
  	unsigned long long mask;
521a2ad6f   Linus Walleij   gpio: add userspa...
28
29
30
31
  };
  
  struct gpio_flag flagnames[] = {
  	{
3c333c470   Kent Gibson   tools: gpio: port...
32
33
34
35
36
37
  		.name = "used",
  		.mask = GPIO_V2_LINE_FLAG_USED,
  	},
  	{
  		.name = "input",
  		.mask = GPIO_V2_LINE_FLAG_INPUT,
521a2ad6f   Linus Walleij   gpio: add userspa...
38
39
40
  	},
  	{
  		.name = "output",
3c333c470   Kent Gibson   tools: gpio: port...
41
  		.mask = GPIO_V2_LINE_FLAG_OUTPUT,
521a2ad6f   Linus Walleij   gpio: add userspa...
42
43
44
  	},
  	{
  		.name = "active-low",
3c333c470   Kent Gibson   tools: gpio: port...
45
  		.mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW,
521a2ad6f   Linus Walleij   gpio: add userspa...
46
47
48
  	},
  	{
  		.name = "open-drain",
3c333c470   Kent Gibson   tools: gpio: port...
49
  		.mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN,
521a2ad6f   Linus Walleij   gpio: add userspa...
50
51
52
  	},
  	{
  		.name = "open-source",
3c333c470   Kent Gibson   tools: gpio: port...
53
  		.mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE,
521a2ad6f   Linus Walleij   gpio: add userspa...
54
  	},
3831c051d   Kent Gibson   tools: gpio: add ...
55
56
  	{
  		.name = "pull-up",
3c333c470   Kent Gibson   tools: gpio: port...
57
  		.mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP,
3831c051d   Kent Gibson   tools: gpio: add ...
58
59
60
  	},
  	{
  		.name = "pull-down",
3c333c470   Kent Gibson   tools: gpio: port...
61
  		.mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN,
3831c051d   Kent Gibson   tools: gpio: add ...
62
63
64
  	},
  	{
  		.name = "bias-disabled",
3c333c470   Kent Gibson   tools: gpio: port...
65
  		.mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED,
3831c051d   Kent Gibson   tools: gpio: add ...
66
  	},
521a2ad6f   Linus Walleij   gpio: add userspa...
67
  };
3c333c470   Kent Gibson   tools: gpio: port...
68
  static void print_attributes(struct gpio_v2_line_info *info)
521a2ad6f   Linus Walleij   gpio: add userspa...
69
70
  {
  	int i;
3c333c470   Kent Gibson   tools: gpio: port...
71
  	const char *field_format = "%s";
521a2ad6f   Linus Walleij   gpio: add userspa...
72
73
  
  	for (i = 0; i < ARRAY_SIZE(flagnames); i++) {
3c333c470   Kent Gibson   tools: gpio: port...
74
75
76
  		if (info->flags & flagnames[i].mask) {
  			fprintf(stdout, field_format, flagnames[i].name);
  			field_format = ", %s";
521a2ad6f   Linus Walleij   gpio: add userspa...
77
78
  		}
  	}
3c333c470   Kent Gibson   tools: gpio: port...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  
  	if ((info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING) &&
  	    (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING))
  		fprintf(stdout, field_format, "both-edges");
  	else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_RISING)
  		fprintf(stdout, field_format, "rising-edge");
  	else if (info->flags & GPIO_V2_LINE_FLAG_EDGE_FALLING)
  		fprintf(stdout, field_format, "falling-edge");
  
  	for (i = 0; i < info->num_attrs; i++) {
  		if (info->attrs[i].id == GPIO_V2_LINE_ATTR_ID_DEBOUNCE)
  			fprintf(stdout, ", debounce_period=%dusec",
  				info->attrs[0].debounce_period_us);
  	}
521a2ad6f   Linus Walleij   gpio: add userspa...
93
  }
6d591c46b   Linus Walleij   tools/gpio: creat...
94
95
96
97
98
99
  int list_device(const char *device_name)
  {
  	struct gpiochip_info cinfo;
  	char *chrdev_name;
  	int fd;
  	int ret;
521a2ad6f   Linus Walleij   gpio: add userspa...
100
  	int i;
6d591c46b   Linus Walleij   tools/gpio: creat...
101
102
103
104
105
106
107
108
109
110
  
  	ret = asprintf(&chrdev_name, "/dev/%s", device_name);
  	if (ret < 0)
  		return -ENOMEM;
  
  	fd = open(chrdev_name, 0);
  	if (fd == -1) {
  		ret = -errno;
  		fprintf(stderr, "Failed to open %s
  ", chrdev_name);
ef3c61a08   Kent Gibson   tools: gpio: fix ...
111
  		goto exit_free_name;
6d591c46b   Linus Walleij   tools/gpio: creat...
112
113
114
115
116
117
  	}
  
  	/* Inspect this GPIO chip */
  	ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &cinfo);
  	if (ret == -1) {
  		ret = -errno;
521a2ad6f   Linus Walleij   gpio: add userspa...
118
119
120
  		perror("Failed to issue CHIPINFO IOCTL
  ");
  		goto exit_close_error;
6d591c46b   Linus Walleij   tools/gpio: creat...
121
  	}
df4878e96   Linus Walleij   gpio: store refle...
122
123
124
  	fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines
  ",
  		cinfo.name, cinfo.label, cinfo.lines);
6d591c46b   Linus Walleij   tools/gpio: creat...
125

521a2ad6f   Linus Walleij   gpio: add userspa...
126
127
  	/* Loop over the lines and print info */
  	for (i = 0; i < cinfo.lines; i++) {
3c333c470   Kent Gibson   tools: gpio: port...
128
  		struct gpio_v2_line_info linfo;
521a2ad6f   Linus Walleij   gpio: add userspa...
129
130
  
  		memset(&linfo, 0, sizeof(linfo));
3c333c470   Kent Gibson   tools: gpio: port...
131
  		linfo.offset = i;
521a2ad6f   Linus Walleij   gpio: add userspa...
132

3c333c470   Kent Gibson   tools: gpio: port...
133
  		ret = ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &linfo);
521a2ad6f   Linus Walleij   gpio: add userspa...
134
135
136
137
138
139
  		if (ret == -1) {
  			ret = -errno;
  			perror("Failed to issue LINEINFO IOCTL
  ");
  			goto exit_close_error;
  		}
3c333c470   Kent Gibson   tools: gpio: port...
140
  		fprintf(stdout, "\tline %2d:", linfo.offset);
521a2ad6f   Linus Walleij   gpio: add userspa...
141
  		if (linfo.name[0])
bb91d345b   Markus Pargmann   tools: gpio: Smal...
142
  			fprintf(stdout, " \"%s\"", linfo.name);
521a2ad6f   Linus Walleij   gpio: add userspa...
143
144
  		else
  			fprintf(stdout, " unnamed");
214338e37   Linus Walleij   gpio: present the...
145
146
  		if (linfo.consumer[0])
  			fprintf(stdout, " \"%s\"", linfo.consumer);
521a2ad6f   Linus Walleij   gpio: add userspa...
147
  		else
214338e37   Linus Walleij   gpio: present the...
148
  			fprintf(stdout, " unused");
521a2ad6f   Linus Walleij   gpio: add userspa...
149
150
  		if (linfo.flags) {
  			fprintf(stdout, " [");
3c333c470   Kent Gibson   tools: gpio: port...
151
  			print_attributes(&linfo);
521a2ad6f   Linus Walleij   gpio: add userspa...
152
153
154
155
  			fprintf(stdout, "]");
  		}
  		fprintf(stdout, "
  ");
6d591c46b   Linus Walleij   tools/gpio: creat...
156
  	}
521a2ad6f   Linus Walleij   gpio: add userspa...
157
158
159
  exit_close_error:
  	if (close(fd) == -1)
  		perror("Failed to close GPIO character device file");
ef3c61a08   Kent Gibson   tools: gpio: fix ...
160
  exit_free_name:
6d591c46b   Linus Walleij   tools/gpio: creat...
161
  	free(chrdev_name);
6d591c46b   Linus Walleij   tools/gpio: creat...
162
  	return ret;
6d591c46b   Linus Walleij   tools/gpio: creat...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  }
  
  void print_usage(void)
  {
  	fprintf(stderr, "Usage: lsgpio [options]...
  "
  		"List GPIO chips, lines and states
  "
  		"  -n <name>  List GPIOs on a named device
  "
  		"  -?         This helptext
  "
  	);
  }
  
  int main(int argc, char **argv)
  {
691998fac   Geert Uytterhoeven   tools/gpio: Add m...
180
  	const char *device_name = NULL;
6d591c46b   Linus Walleij   tools/gpio: creat...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
  	int ret;
  	int c;
  
  	while ((c = getopt(argc, argv, "n:")) != -1) {
  		switch (c) {
  		case 'n':
  			device_name = optarg;
  			break;
  		case '?':
  			print_usage();
  			return -1;
  		}
  	}
  
  	if (device_name)
  		ret = list_device(device_name);
  	else {
  		const struct dirent *ent;
  		DIR *dp;
  
  		/* List all GPIO devices one at a time */
  		dp = opendir("/dev");
  		if (!dp) {
  			ret = -errno;
  			goto error_out;
  		}
  
  		ret = -ENOENT;
  		while (ent = readdir(dp), ent) {
  			if (check_prefix(ent->d_name, "gpiochip")) {
  				ret = list_device(ent->d_name);
  				if (ret)
  					break;
  			}
  		}
  
  		ret = 0;
  		if (closedir(dp) == -1) {
  			perror("scanning devices: Failed to close directory");
  			ret = -errno;
  		}
  	}
  error_out:
  	return ret;
  }