Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
6d591c46 LW |
2 | /* |
3 | * GPIO tools - helpers library for the GPIO tools | |
4 | * | |
5 | * Copyright (C) 2015 Linus Walleij | |
e1acec0e | 6 | * Copyright (C) 2016 Bamvor Jian Zhang |
6d591c46 LW |
7 | */ |
8 | ||
e1acec0e BJZ |
9 | #include <unistd.h> |
10 | #include <stdlib.h> | |
11 | #include <stdio.h> | |
12 | #include <errno.h> | |
13 | #include <string.h> | |
14 | #include <fcntl.h> | |
15 | #include <getopt.h> | |
16 | #include <sys/ioctl.h> | |
17 | #include <linux/gpio.h> | |
6d591c46 | 18 | #include "gpio-utils.h" |
e1acec0e BJZ |
19 | |
20 | #define COMSUMER "gpio-utils" | |
21 | ||
22 | /** | |
23 | * doc: Operation of gpio | |
24 | * | |
25 | * Provide the api of gpiochip for chardev interface. There are two | |
26 | * types of api. The first one provide as same function as each | |
27 | * ioctl, including request and release for lines of gpio, read/write | |
28 | * the value of gpio. If the user want to do lots of read and write of | |
29 | * lines of gpio, user should use this type of api. | |
30 | * | |
31 | * The second one provide the easy to use api for user. Each of the | |
32 | * following api will request gpio lines, do the operation and then | |
33 | * release these lines. | |
34 | */ | |
35 | /** | |
36 | * gpiotools_request_linehandle() - request gpio lines in a gpiochip | |
37 | * @device_name: The name of gpiochip without prefix "/dev/", | |
38 | * such as "gpiochip0" | |
39 | * @lines: An array desired lines, specified by offset | |
40 | * index for the associated GPIO device. | |
41 | * @nline: The number of lines to request. | |
42 | * @flag: The new flag for requsted gpio. Reference | |
43 | * "linux/gpio.h" for the meaning of flag. | |
44 | * @data: Default value will be set to gpio when flag is | |
45 | * GPIOHANDLE_REQUEST_OUTPUT. | |
46 | * @consumer_label: The name of consumer, such as "sysfs", | |
47 | * "powerkey". This is useful for other users to | |
48 | * know who is using. | |
49 | * | |
50 | * Request gpio lines through the ioctl provided by chardev. User | |
51 | * could call gpiotools_set_values() and gpiotools_get_values() to | |
52 | * read and write respectively through the returned fd. Call | |
53 | * gpiotools_release_linehandle() to release these lines after that. | |
54 | * | |
55 | * Return: On success return the fd; | |
56 | * On failure return the errno. | |
57 | */ | |
58 | int gpiotools_request_linehandle(const char *device_name, unsigned int *lines, | |
59 | unsigned int nlines, unsigned int flag, | |
60 | struct gpiohandle_data *data, | |
61 | const char *consumer_label) | |
62 | { | |
63 | struct gpiohandle_request req; | |
64 | char *chrdev_name; | |
65 | int fd; | |
66 | int i; | |
67 | int ret; | |
68 | ||
69 | ret = asprintf(&chrdev_name, "/dev/%s", device_name); | |
70 | if (ret < 0) | |
71 | return -ENOMEM; | |
72 | ||
73 | fd = open(chrdev_name, 0); | |
74 | if (fd == -1) { | |
75 | ret = -errno; | |
d327a224 JM |
76 | fprintf(stderr, "Failed to open %s, %s\n", |
77 | chrdev_name, strerror(errno)); | |
e1acec0e BJZ |
78 | goto exit_close_error; |
79 | } | |
80 | ||
81 | for (i = 0; i < nlines; i++) | |
82 | req.lineoffsets[i] = lines[i]; | |
83 | ||
84 | req.flags = flag; | |
85 | strcpy(req.consumer_label, consumer_label); | |
86 | req.lines = nlines; | |
87 | if (flag & GPIOHANDLE_REQUEST_OUTPUT) | |
88 | memcpy(req.default_values, data, sizeof(req.default_values)); | |
89 | ||
90 | ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); | |
91 | if (ret == -1) { | |
92 | ret = -errno; | |
d327a224 JM |
93 | fprintf(stderr, "Failed to issue %s (%d), %s\n", |
94 | "GPIO_GET_LINEHANDLE_IOCTL", ret, strerror(errno)); | |
e1acec0e BJZ |
95 | } |
96 | ||
97 | exit_close_error: | |
98 | if (close(fd) == -1) | |
99 | perror("Failed to close GPIO character device file"); | |
100 | free(chrdev_name); | |
101 | return ret < 0 ? ret : req.fd; | |
102 | } | |
103 | /** | |
104 | * gpiotools_set_values(): Set the value of gpio(s) | |
105 | * @fd: The fd returned by | |
106 | * gpiotools_request_linehandle(). | |
107 | * @data: The array of values want to set. | |
108 | * | |
109 | * Return: On success return 0; | |
110 | * On failure return the errno. | |
111 | */ | |
112 | int gpiotools_set_values(const int fd, struct gpiohandle_data *data) | |
113 | { | |
114 | int ret; | |
115 | ||
116 | ret = ioctl(fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, data); | |
117 | if (ret == -1) { | |
118 | ret = -errno; | |
d327a224 JM |
119 | fprintf(stderr, "Failed to issue %s (%d), %s\n", |
120 | "GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret, | |
121 | strerror(errno)); | |
e1acec0e BJZ |
122 | } |
123 | ||
124 | return ret; | |
125 | } | |
126 | ||
127 | /** | |
128 | * gpiotools_get_values(): Get the value of gpio(s) | |
129 | * @fd: The fd returned by | |
130 | * gpiotools_request_linehandle(). | |
131 | * @data: The array of values get from hardware. | |
132 | * | |
133 | * Return: On success return 0; | |
134 | * On failure return the errno. | |
135 | */ | |
136 | int gpiotools_get_values(const int fd, struct gpiohandle_data *data) | |
137 | { | |
138 | int ret; | |
139 | ||
140 | ret = ioctl(fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, data); | |
141 | if (ret == -1) { | |
142 | ret = -errno; | |
d327a224 JM |
143 | fprintf(stderr, "Failed to issue %s (%d), %s\n", |
144 | "GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret, | |
145 | strerror(errno)); | |
e1acec0e BJZ |
146 | } |
147 | ||
148 | return ret; | |
149 | } | |
150 | ||
151 | /** | |
152 | * gpiotools_release_linehandle(): Release the line(s) of gpiochip | |
153 | * @fd: The fd returned by | |
154 | * gpiotools_request_linehandle(). | |
155 | * | |
156 | * Return: On success return 0; | |
157 | * On failure return the errno. | |
158 | */ | |
159 | int gpiotools_release_linehandle(const int fd) | |
160 | { | |
161 | int ret; | |
162 | ||
163 | ret = close(fd); | |
164 | if (ret == -1) { | |
165 | perror("Failed to close GPIO LINEHANDLE device file"); | |
166 | ret = -errno; | |
167 | } | |
168 | ||
169 | return ret; | |
170 | } | |
171 | ||
172 | /** | |
173 | * gpiotools_get(): Get value from specific line | |
174 | * @device_name: The name of gpiochip without prefix "/dev/", | |
175 | * such as "gpiochip0" | |
176 | * @line: number of line, such as 2. | |
177 | * | |
178 | * Return: On success return 0; | |
179 | * On failure return the errno. | |
180 | */ | |
181 | int gpiotools_get(const char *device_name, unsigned int line) | |
182 | { | |
183 | struct gpiohandle_data data; | |
184 | unsigned int lines[] = {line}; | |
185 | ||
186 | gpiotools_gets(device_name, lines, 1, &data); | |
187 | return data.values[0]; | |
188 | } | |
189 | ||
190 | ||
191 | /** | |
192 | * gpiotools_gets(): Get values from specific lines. | |
193 | * @device_name: The name of gpiochip without prefix "/dev/", | |
194 | * such as "gpiochip0". | |
195 | * @lines: An array desired lines, specified by offset | |
196 | * index for the associated GPIO device. | |
197 | * @nline: The number of lines to request. | |
198 | * @data: The array of values get from gpiochip. | |
199 | * | |
200 | * Return: On success return 0; | |
201 | * On failure return the errno. | |
202 | */ | |
203 | int gpiotools_gets(const char *device_name, unsigned int *lines, | |
204 | unsigned int nlines, struct gpiohandle_data *data) | |
205 | { | |
206 | int fd; | |
207 | int ret; | |
208 | int ret_close; | |
209 | ||
210 | ret = gpiotools_request_linehandle(device_name, lines, nlines, | |
211 | GPIOHANDLE_REQUEST_INPUT, data, | |
212 | COMSUMER); | |
213 | if (ret < 0) | |
214 | return ret; | |
215 | ||
216 | fd = ret; | |
217 | ret = gpiotools_get_values(fd, data); | |
218 | ret_close = gpiotools_release_linehandle(fd); | |
219 | return ret < 0 ? ret : ret_close; | |
220 | } | |
221 | ||
222 | /** | |
223 | * gpiotools_set(): Set value to specific line | |
224 | * @device_name: The name of gpiochip without prefix "/dev/", | |
225 | * such as "gpiochip0" | |
226 | * @line: number of line, such as 2. | |
227 | * @value: The value of gpio, must be 0(low) or 1(high). | |
228 | * | |
229 | * Return: On success return 0; | |
230 | * On failure return the errno. | |
231 | */ | |
232 | int gpiotools_set(const char *device_name, unsigned int line, | |
233 | unsigned int value) | |
234 | { | |
235 | struct gpiohandle_data data; | |
236 | unsigned int lines[] = {line}; | |
237 | ||
238 | data.values[0] = value; | |
239 | return gpiotools_sets(device_name, lines, 1, &data); | |
240 | } | |
241 | ||
242 | /** | |
243 | * gpiotools_sets(): Set values to specific lines. | |
244 | * @device_name: The name of gpiochip without prefix "/dev/", | |
245 | * such as "gpiochip0". | |
246 | * @lines: An array desired lines, specified by offset | |
247 | * index for the associated GPIO device. | |
248 | * @nline: The number of lines to request. | |
249 | * @data: The array of values set to gpiochip, must be | |
250 | * 0(low) or 1(high). | |
251 | * | |
252 | * Return: On success return 0; | |
253 | * On failure return the errno. | |
254 | */ | |
255 | int gpiotools_sets(const char *device_name, unsigned int *lines, | |
256 | unsigned int nlines, struct gpiohandle_data *data) | |
257 | { | |
258 | int ret; | |
259 | ||
260 | ret = gpiotools_request_linehandle(device_name, lines, nlines, | |
261 | GPIOHANDLE_REQUEST_OUTPUT, data, | |
262 | COMSUMER); | |
263 | if (ret < 0) | |
264 | return ret; | |
265 | ||
266 | return gpiotools_release_linehandle(ret); | |
267 | } |