.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * GPIO tools - helpers library for the GPIO tools |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2015 Linus Walleij |
---|
5 | 6 | * Copyright (C) 2016 Bamvor Jian Zhang |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify it |
---|
8 | | - * under the terms of the GNU General Public License version 2 as published by |
---|
9 | | - * the Free Software Foundation. |
---|
10 | 7 | */ |
---|
11 | 8 | |
---|
12 | 9 | #include <unistd.h> |
---|
.. | .. |
---|
20 | 17 | #include <linux/gpio.h> |
---|
21 | 18 | #include "gpio-utils.h" |
---|
22 | 19 | |
---|
23 | | -#define COMSUMER "gpio-utils" |
---|
| 20 | +#define CONSUMER "gpio-utils" |
---|
24 | 21 | |
---|
25 | 22 | /** |
---|
26 | 23 | * doc: Operation of gpio |
---|
.. | .. |
---|
41 | 38 | * such as "gpiochip0" |
---|
42 | 39 | * @lines: An array desired lines, specified by offset |
---|
43 | 40 | * index for the associated GPIO device. |
---|
44 | | - * @nline: The number of lines to request. |
---|
| 41 | + * @num_lines: The number of lines to request. |
---|
45 | 42 | * @flag: The new flag for requsted gpio. Reference |
---|
46 | 43 | * "linux/gpio.h" for the meaning of flag. |
---|
47 | 44 | * @data: Default value will be set to gpio when flag is |
---|
.. | .. |
---|
59 | 56 | * On failure return the errno. |
---|
60 | 57 | */ |
---|
61 | 58 | int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, |
---|
62 | | - unsigned int nlines, unsigned int flag, |
---|
| 59 | + unsigned int num_lines, unsigned int flag, |
---|
63 | 60 | struct gpiohandle_data *data, |
---|
64 | 61 | const char *consumer_label) |
---|
65 | 62 | { |
---|
.. | .. |
---|
78 | 75 | ret = -errno; |
---|
79 | 76 | fprintf(stderr, "Failed to open %s, %s\n", |
---|
80 | 77 | chrdev_name, strerror(errno)); |
---|
81 | | - goto exit_close_error; |
---|
| 78 | + goto exit_free_name; |
---|
82 | 79 | } |
---|
83 | 80 | |
---|
84 | | - for (i = 0; i < nlines; i++) |
---|
| 81 | + for (i = 0; i < num_lines; i++) |
---|
85 | 82 | req.lineoffsets[i] = lines[i]; |
---|
86 | 83 | |
---|
87 | 84 | req.flags = flag; |
---|
88 | 85 | strcpy(req.consumer_label, consumer_label); |
---|
89 | | - req.lines = nlines; |
---|
| 86 | + req.lines = num_lines; |
---|
90 | 87 | if (flag & GPIOHANDLE_REQUEST_OUTPUT) |
---|
91 | 88 | memcpy(req.default_values, data, sizeof(req.default_values)); |
---|
92 | 89 | |
---|
.. | .. |
---|
97 | 94 | "GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno)); |
---|
98 | 95 | } |
---|
99 | 96 | |
---|
100 | | -exit_close_error: |
---|
101 | 97 | if (close(fd) == -1) |
---|
102 | 98 | perror("Failed to close GPIO character device file"); |
---|
| 99 | +exit_free_name: |
---|
103 | 100 | free(chrdev_name); |
---|
104 | 101 | return ret < 0 ? ret : req.fd; |
---|
105 | 102 | } |
---|
| 103 | + |
---|
| 104 | +/** |
---|
| 105 | + * gpiotools_request_line() - request gpio lines in a gpiochip |
---|
| 106 | + * @device_name: The name of gpiochip without prefix "/dev/", |
---|
| 107 | + * such as "gpiochip0" |
---|
| 108 | + * @lines: An array desired lines, specified by offset |
---|
| 109 | + * index for the associated GPIO device. |
---|
| 110 | + * @num_lines: The number of lines to request. |
---|
| 111 | + * @config: The new config for requested gpio. Reference |
---|
| 112 | + * "linux/gpio.h" for config details. |
---|
| 113 | + * @consumer: The name of consumer, such as "sysfs", |
---|
| 114 | + * "powerkey". This is useful for other users to |
---|
| 115 | + * know who is using. |
---|
| 116 | + * |
---|
| 117 | + * Request gpio lines through the ioctl provided by chardev. User |
---|
| 118 | + * could call gpiotools_set_values() and gpiotools_get_values() to |
---|
| 119 | + * read and write respectively through the returned fd. Call |
---|
| 120 | + * gpiotools_release_line() to release these lines after that. |
---|
| 121 | + * |
---|
| 122 | + * Return: On success return the fd; |
---|
| 123 | + * On failure return the errno. |
---|
| 124 | + */ |
---|
| 125 | +int gpiotools_request_line(const char *device_name, unsigned int *lines, |
---|
| 126 | + unsigned int num_lines, |
---|
| 127 | + struct gpio_v2_line_config *config, |
---|
| 128 | + const char *consumer) |
---|
| 129 | +{ |
---|
| 130 | + struct gpio_v2_line_request req; |
---|
| 131 | + char *chrdev_name; |
---|
| 132 | + int fd; |
---|
| 133 | + int i; |
---|
| 134 | + int ret; |
---|
| 135 | + |
---|
| 136 | + ret = asprintf(&chrdev_name, "/dev/%s", device_name); |
---|
| 137 | + if (ret < 0) |
---|
| 138 | + return -ENOMEM; |
---|
| 139 | + |
---|
| 140 | + fd = open(chrdev_name, 0); |
---|
| 141 | + if (fd == -1) { |
---|
| 142 | + ret = -errno; |
---|
| 143 | + fprintf(stderr, "Failed to open %s, %s\n", |
---|
| 144 | + chrdev_name, strerror(errno)); |
---|
| 145 | + goto exit_free_name; |
---|
| 146 | + } |
---|
| 147 | + |
---|
| 148 | + memset(&req, 0, sizeof(req)); |
---|
| 149 | + for (i = 0; i < num_lines; i++) |
---|
| 150 | + req.offsets[i] = lines[i]; |
---|
| 151 | + |
---|
| 152 | + req.config = *config; |
---|
| 153 | + strcpy(req.consumer, consumer); |
---|
| 154 | + req.num_lines = num_lines; |
---|
| 155 | + |
---|
| 156 | + ret = ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req); |
---|
| 157 | + if (ret == -1) { |
---|
| 158 | + ret = -errno; |
---|
| 159 | + fprintf(stderr, "Failed to issue %s (%d), %s\n", |
---|
| 160 | + "GPIO_GET_LINE_IOCTL", ret, strerror(errno)); |
---|
| 161 | + } |
---|
| 162 | + |
---|
| 163 | + if (close(fd) == -1) |
---|
| 164 | + perror("Failed to close GPIO character device file"); |
---|
| 165 | +exit_free_name: |
---|
| 166 | + free(chrdev_name); |
---|
| 167 | + return ret < 0 ? ret : req.fd; |
---|
| 168 | +} |
---|
| 169 | + |
---|
106 | 170 | /** |
---|
107 | 171 | * gpiotools_set_values(): Set the value of gpio(s) |
---|
108 | 172 | * @fd: The fd returned by |
---|
109 | | - * gpiotools_request_linehandle(). |
---|
110 | | - * @data: The array of values want to set. |
---|
| 173 | + * gpiotools_request_line(). |
---|
| 174 | + * @values: The array of values want to set. |
---|
111 | 175 | * |
---|
112 | 176 | * Return: On success return 0; |
---|
113 | 177 | * On failure return the errno. |
---|
114 | 178 | */ |
---|
115 | | -int gpiotools_set_values(const int fd, struct gpiohandle_data *data) |
---|
| 179 | +int gpiotools_set_values(const int fd, struct gpio_v2_line_values *values) |
---|
116 | 180 | { |
---|
117 | 181 | int ret; |
---|
118 | 182 | |
---|
119 | | - ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data); |
---|
| 183 | + ret = ioctl(fd, GPIO_V2_LINE_SET_VALUES_IOCTL, values); |
---|
120 | 184 | if (ret == -1) { |
---|
121 | 185 | ret = -errno; |
---|
122 | 186 | fprintf(stderr, "Failed to issue %s (%d), %s\n", |
---|
.. | .. |
---|
130 | 194 | /** |
---|
131 | 195 | * gpiotools_get_values(): Get the value of gpio(s) |
---|
132 | 196 | * @fd: The fd returned by |
---|
133 | | - * gpiotools_request_linehandle(). |
---|
134 | | - * @data: The array of values get from hardware. |
---|
| 197 | + * gpiotools_request_line(). |
---|
| 198 | + * @values: The array of values get from hardware. |
---|
135 | 199 | * |
---|
136 | 200 | * Return: On success return 0; |
---|
137 | 201 | * On failure return the errno. |
---|
138 | 202 | */ |
---|
139 | | -int gpiotools_get_values(const int fd, struct gpiohandle_data *data) |
---|
| 203 | +int gpiotools_get_values(const int fd, struct gpio_v2_line_values *values) |
---|
140 | 204 | { |
---|
141 | 205 | int ret; |
---|
142 | 206 | |
---|
143 | | - ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data); |
---|
| 207 | + ret = ioctl(fd, GPIO_V2_LINE_GET_VALUES_IOCTL, values); |
---|
144 | 208 | if (ret == -1) { |
---|
145 | 209 | ret = -errno; |
---|
146 | 210 | fprintf(stderr, "Failed to issue %s (%d), %s\n", |
---|
.. | .. |
---|
173 | 237 | } |
---|
174 | 238 | |
---|
175 | 239 | /** |
---|
| 240 | + * gpiotools_release_line(): Release the line(s) of gpiochip |
---|
| 241 | + * @fd: The fd returned by |
---|
| 242 | + * gpiotools_request_line(). |
---|
| 243 | + * |
---|
| 244 | + * Return: On success return 0; |
---|
| 245 | + * On failure return the errno. |
---|
| 246 | + */ |
---|
| 247 | +int gpiotools_release_line(const int fd) |
---|
| 248 | +{ |
---|
| 249 | + int ret; |
---|
| 250 | + |
---|
| 251 | + ret = close(fd); |
---|
| 252 | + if (ret == -1) { |
---|
| 253 | + perror("Failed to close GPIO LINE device file"); |
---|
| 254 | + ret = -errno; |
---|
| 255 | + } |
---|
| 256 | + |
---|
| 257 | + return ret; |
---|
| 258 | +} |
---|
| 259 | + |
---|
| 260 | +/** |
---|
176 | 261 | * gpiotools_get(): Get value from specific line |
---|
177 | 262 | * @device_name: The name of gpiochip without prefix "/dev/", |
---|
178 | 263 | * such as "gpiochip0" |
---|
.. | .. |
---|
183 | 268 | */ |
---|
184 | 269 | int gpiotools_get(const char *device_name, unsigned int line) |
---|
185 | 270 | { |
---|
186 | | - struct gpiohandle_data data; |
---|
| 271 | + int ret; |
---|
| 272 | + unsigned int value; |
---|
187 | 273 | unsigned int lines[] = {line}; |
---|
188 | 274 | |
---|
189 | | - gpiotools_gets(device_name, lines, 1, &data); |
---|
190 | | - return data.values[0]; |
---|
| 275 | + ret = gpiotools_gets(device_name, lines, 1, &value); |
---|
| 276 | + if (ret) |
---|
| 277 | + return ret; |
---|
| 278 | + return value; |
---|
191 | 279 | } |
---|
192 | 280 | |
---|
193 | 281 | |
---|
.. | .. |
---|
197 | 285 | * such as "gpiochip0". |
---|
198 | 286 | * @lines: An array desired lines, specified by offset |
---|
199 | 287 | * index for the associated GPIO device. |
---|
200 | | - * @nline: The number of lines to request. |
---|
201 | | - * @data: The array of values get from gpiochip. |
---|
| 288 | + * @num_lines: The number of lines to request. |
---|
| 289 | + * @values: The array of values get from gpiochip. |
---|
202 | 290 | * |
---|
203 | 291 | * Return: On success return 0; |
---|
204 | 292 | * On failure return the errno. |
---|
205 | 293 | */ |
---|
206 | 294 | int gpiotools_gets(const char *device_name, unsigned int *lines, |
---|
207 | | - unsigned int nlines, struct gpiohandle_data *data) |
---|
| 295 | + unsigned int num_lines, unsigned int *values) |
---|
208 | 296 | { |
---|
209 | | - int fd; |
---|
| 297 | + int fd, i; |
---|
210 | 298 | int ret; |
---|
211 | 299 | int ret_close; |
---|
| 300 | + struct gpio_v2_line_config config; |
---|
| 301 | + struct gpio_v2_line_values lv; |
---|
212 | 302 | |
---|
213 | | - ret = gpiotools_request_linehandle(device_name, lines, nlines, |
---|
214 | | - GPIOHANDLE_REQUEST_INPUT, data, |
---|
215 | | - COMSUMER); |
---|
| 303 | + memset(&config, 0, sizeof(config)); |
---|
| 304 | + config.flags = GPIO_V2_LINE_FLAG_INPUT; |
---|
| 305 | + ret = gpiotools_request_line(device_name, lines, num_lines, |
---|
| 306 | + &config, CONSUMER); |
---|
216 | 307 | if (ret < 0) |
---|
217 | 308 | return ret; |
---|
218 | 309 | |
---|
219 | 310 | fd = ret; |
---|
220 | | - ret = gpiotools_get_values(fd, data); |
---|
221 | | - ret_close = gpiotools_release_linehandle(fd); |
---|
| 311 | + for (i = 0; i < num_lines; i++) |
---|
| 312 | + gpiotools_set_bit(&lv.mask, i); |
---|
| 313 | + ret = gpiotools_get_values(fd, &lv); |
---|
| 314 | + if (!ret) |
---|
| 315 | + for (i = 0; i < num_lines; i++) |
---|
| 316 | + values[i] = gpiotools_test_bit(lv.bits, i); |
---|
| 317 | + ret_close = gpiotools_release_line(fd); |
---|
222 | 318 | return ret < 0 ? ret : ret_close; |
---|
223 | 319 | } |
---|
224 | 320 | |
---|
.. | .. |
---|
235 | 331 | int gpiotools_set(const char *device_name, unsigned int line, |
---|
236 | 332 | unsigned int value) |
---|
237 | 333 | { |
---|
238 | | - struct gpiohandle_data data; |
---|
239 | 334 | unsigned int lines[] = {line}; |
---|
240 | 335 | |
---|
241 | | - data.values[0] = value; |
---|
242 | | - return gpiotools_sets(device_name, lines, 1, &data); |
---|
| 336 | + return gpiotools_sets(device_name, lines, 1, &value); |
---|
243 | 337 | } |
---|
244 | 338 | |
---|
245 | 339 | /** |
---|
.. | .. |
---|
248 | 342 | * such as "gpiochip0". |
---|
249 | 343 | * @lines: An array desired lines, specified by offset |
---|
250 | 344 | * index for the associated GPIO device. |
---|
251 | | - * @nline: The number of lines to request. |
---|
252 | | - * @data: The array of values set to gpiochip, must be |
---|
| 345 | + * @num_lines: The number of lines to request. |
---|
| 346 | + * @value: The array of values set to gpiochip, must be |
---|
253 | 347 | * 0(low) or 1(high). |
---|
254 | 348 | * |
---|
255 | 349 | * Return: On success return 0; |
---|
256 | 350 | * On failure return the errno. |
---|
257 | 351 | */ |
---|
258 | 352 | int gpiotools_sets(const char *device_name, unsigned int *lines, |
---|
259 | | - unsigned int nlines, struct gpiohandle_data *data) |
---|
| 353 | + unsigned int num_lines, unsigned int *values) |
---|
260 | 354 | { |
---|
261 | | - int ret; |
---|
| 355 | + int ret, i; |
---|
| 356 | + struct gpio_v2_line_config config; |
---|
262 | 357 | |
---|
263 | | - ret = gpiotools_request_linehandle(device_name, lines, nlines, |
---|
264 | | - GPIOHANDLE_REQUEST_OUTPUT, data, |
---|
265 | | - COMSUMER); |
---|
| 358 | + memset(&config, 0, sizeof(config)); |
---|
| 359 | + config.flags = GPIO_V2_LINE_FLAG_OUTPUT; |
---|
| 360 | + config.num_attrs = 1; |
---|
| 361 | + config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES; |
---|
| 362 | + for (i = 0; i < num_lines; i++) { |
---|
| 363 | + gpiotools_set_bit(&config.attrs[0].mask, i); |
---|
| 364 | + gpiotools_assign_bit(&config.attrs[0].attr.values, |
---|
| 365 | + i, values[i]); |
---|
| 366 | + } |
---|
| 367 | + ret = gpiotools_request_line(device_name, lines, num_lines, |
---|
| 368 | + &config, CONSUMER); |
---|
266 | 369 | if (ret < 0) |
---|
267 | 370 | return ret; |
---|
268 | 371 | |
---|
269 | | - return gpiotools_release_linehandle(ret); |
---|
| 372 | + return gpiotools_release_line(ret); |
---|
270 | 373 | } |
---|