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