Blame view
tools/gpio/lsgpio.c
4.42 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
6d591c46b 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 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 gpio: add userspa... |
25 26 |
struct gpio_flag { char *name; |
3c333c470 tools: gpio: port... |
27 |
unsigned long long mask; |
521a2ad6f gpio: add userspa... |
28 29 30 31 |
}; struct gpio_flag flagnames[] = { { |
3c333c470 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 gpio: add userspa... |
38 39 40 |
}, { .name = "output", |
3c333c470 tools: gpio: port... |
41 |
.mask = GPIO_V2_LINE_FLAG_OUTPUT, |
521a2ad6f gpio: add userspa... |
42 43 44 |
}, { .name = "active-low", |
3c333c470 tools: gpio: port... |
45 |
.mask = GPIO_V2_LINE_FLAG_ACTIVE_LOW, |
521a2ad6f gpio: add userspa... |
46 47 48 |
}, { .name = "open-drain", |
3c333c470 tools: gpio: port... |
49 |
.mask = GPIO_V2_LINE_FLAG_OPEN_DRAIN, |
521a2ad6f gpio: add userspa... |
50 51 52 |
}, { .name = "open-source", |
3c333c470 tools: gpio: port... |
53 |
.mask = GPIO_V2_LINE_FLAG_OPEN_SOURCE, |
521a2ad6f gpio: add userspa... |
54 |
}, |
3831c051d tools: gpio: add ... |
55 56 |
{ .name = "pull-up", |
3c333c470 tools: gpio: port... |
57 |
.mask = GPIO_V2_LINE_FLAG_BIAS_PULL_UP, |
3831c051d tools: gpio: add ... |
58 59 60 |
}, { .name = "pull-down", |
3c333c470 tools: gpio: port... |
61 |
.mask = GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN, |
3831c051d tools: gpio: add ... |
62 63 64 |
}, { .name = "bias-disabled", |
3c333c470 tools: gpio: port... |
65 |
.mask = GPIO_V2_LINE_FLAG_BIAS_DISABLED, |
3831c051d tools: gpio: add ... |
66 |
}, |
521a2ad6f gpio: add userspa... |
67 |
}; |
3c333c470 tools: gpio: port... |
68 |
static void print_attributes(struct gpio_v2_line_info *info) |
521a2ad6f gpio: add userspa... |
69 70 |
{ int i; |
3c333c470 tools: gpio: port... |
71 |
const char *field_format = "%s"; |
521a2ad6f gpio: add userspa... |
72 73 |
for (i = 0; i < ARRAY_SIZE(flagnames); i++) { |
3c333c470 tools: gpio: port... |
74 75 76 |
if (info->flags & flagnames[i].mask) { fprintf(stdout, field_format, flagnames[i].name); field_format = ", %s"; |
521a2ad6f gpio: add userspa... |
77 78 |
} } |
3c333c470 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 gpio: add userspa... |
93 |
} |
6d591c46b 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 gpio: add userspa... |
100 |
int i; |
6d591c46b 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 tools: gpio: fix ... |
111 |
goto exit_free_name; |
6d591c46b 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 gpio: add userspa... |
118 119 120 |
perror("Failed to issue CHIPINFO IOCTL "); goto exit_close_error; |
6d591c46b tools/gpio: creat... |
121 |
} |
df4878e96 gpio: store refle... |
122 123 124 |
fprintf(stdout, "GPIO chip: %s, \"%s\", %u GPIO lines ", cinfo.name, cinfo.label, cinfo.lines); |
6d591c46b tools/gpio: creat... |
125 |
|
521a2ad6f gpio: add userspa... |
126 127 |
/* Loop over the lines and print info */ for (i = 0; i < cinfo.lines; i++) { |
3c333c470 tools: gpio: port... |
128 |
struct gpio_v2_line_info linfo; |
521a2ad6f gpio: add userspa... |
129 130 |
memset(&linfo, 0, sizeof(linfo)); |
3c333c470 tools: gpio: port... |
131 |
linfo.offset = i; |
521a2ad6f gpio: add userspa... |
132 |
|
3c333c470 tools: gpio: port... |
133 |
ret = ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &linfo); |
521a2ad6f 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 tools: gpio: port... |
140 |
fprintf(stdout, "\tline %2d:", linfo.offset); |
521a2ad6f gpio: add userspa... |
141 |
if (linfo.name[0]) |
bb91d345b tools: gpio: Smal... |
142 |
fprintf(stdout, " \"%s\"", linfo.name); |
521a2ad6f gpio: add userspa... |
143 144 |
else fprintf(stdout, " unnamed"); |
214338e37 gpio: present the... |
145 146 |
if (linfo.consumer[0]) fprintf(stdout, " \"%s\"", linfo.consumer); |
521a2ad6f gpio: add userspa... |
147 |
else |
214338e37 gpio: present the... |
148 |
fprintf(stdout, " unused"); |
521a2ad6f gpio: add userspa... |
149 150 |
if (linfo.flags) { fprintf(stdout, " ["); |
3c333c470 tools: gpio: port... |
151 |
print_attributes(&linfo); |
521a2ad6f gpio: add userspa... |
152 153 154 155 |
fprintf(stdout, "]"); } fprintf(stdout, " "); |
6d591c46b tools/gpio: creat... |
156 |
} |
521a2ad6f gpio: add userspa... |
157 158 159 |
exit_close_error: if (close(fd) == -1) perror("Failed to close GPIO character device file"); |
ef3c61a08 tools: gpio: fix ... |
160 |
exit_free_name: |
6d591c46b tools/gpio: creat... |
161 |
free(chrdev_name); |
6d591c46b tools/gpio: creat... |
162 |
return ret; |
6d591c46b 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 tools/gpio: Add m... |
180 |
const char *device_name = NULL; |
6d591c46b 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; } |