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