brintos

brintos / linux-shallow public Read only

0
0
Text · 7.3 KiB · 4096bcd Raw
285 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * GPIO tools - helpers library for the GPIO tools4 *5 * Copyright (C) 2015 Linus Walleij6 * Copyright (C) 2016 Bamvor Jian Zhang7 */8 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>18#include "gpio-utils.h"19 20#define CONSUMER "gpio-utils"21 22/**23 * DOC: Operation of gpio24 *25 * Provide the api of gpiochip for chardev interface. There are two26 * types of api.  The first one provide as same function as each27 * ioctl, including request and release for lines of gpio, read/write28 * the value of gpio. If the user want to do lots of read and write of29 * 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 the32 * following api will request gpio lines, do the operation and then33 * release these lines.34 */35 36/**37 * gpiotools_request_line() - request gpio lines in a gpiochip38 * @device_name:	The name of gpiochip without prefix "/dev/",39 *			such as "gpiochip0"40 * @lines:		An array desired lines, specified by offset41 *			index for the associated GPIO device.42 * @num_lines:		The number of lines to request.43 * @config:		The new config for requested gpio. Reference44 *			"linux/gpio.h" for config details.45 * @consumer:		The name of consumer, such as "sysfs",46 *			"powerkey". This is useful for other users to47 *			know who is using.48 *49 * Request gpio lines through the ioctl provided by chardev. User50 * could call gpiotools_set_values() and gpiotools_get_values() to51 * read and write respectively through the returned fd. Call52 * gpiotools_release_line() to release these lines after that.53 *54 * Return:		On success return the fd;55 *			On failure return the errno.56 */57int gpiotools_request_line(const char *device_name, unsigned int *lines,58			   unsigned int num_lines,59			   struct gpio_v2_line_config *config,60			   const char *consumer)61{62	struct gpio_v2_line_request req;63	char *chrdev_name;64	int fd;65	int i;66	int ret;67 68	ret = asprintf(&chrdev_name, "/dev/%s", device_name);69	if (ret < 0)70		return -ENOMEM;71 72	fd = open(chrdev_name, 0);73	if (fd == -1) {74		ret = -errno;75		fprintf(stderr, "Failed to open %s, %s\n",76			chrdev_name, strerror(errno));77		goto exit_free_name;78	}79 80	memset(&req, 0, sizeof(req));81	for (i = 0; i < num_lines; i++)82		req.offsets[i] = lines[i];83 84	req.config = *config;85	strcpy(req.consumer, consumer);86	req.num_lines = num_lines;87 88	ret = ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req);89	if (ret == -1) {90		ret = -errno;91		fprintf(stderr, "Failed to issue %s (%d), %s\n",92			"GPIO_GET_LINE_IOCTL", ret, strerror(errno));93	}94 95	if (close(fd) == -1)96		perror("Failed to close GPIO character device file");97exit_free_name:98	free(chrdev_name);99	return ret < 0 ? ret : req.fd;100}101 102/**103 * gpiotools_set_values() - Set the value of gpio(s)104 * @fd:			The fd returned by105 *			gpiotools_request_line().106 * @values:		The array of values want to set.107 *108 * Return:		On success return 0;109 *			On failure return the errno.110 */111int gpiotools_set_values(const int fd, struct gpio_v2_line_values *values)112{113	int ret;114 115	ret = ioctl(fd, GPIO_V2_LINE_SET_VALUES_IOCTL, values);116	if (ret == -1) {117		ret = -errno;118		fprintf(stderr, "Failed to issue %s (%d), %s\n",119			"GPIOHANDLE_SET_LINE_VALUES_IOCTL", ret,120			strerror(errno));121	}122 123	return ret;124}125 126/**127 * gpiotools_get_values() - Get the value of gpio(s)128 * @fd:			The fd returned by129 *			gpiotools_request_line().130 * @values:		The array of values get from hardware.131 *132 * Return:		On success return 0;133 *			On failure return the errno.134 */135int gpiotools_get_values(const int fd, struct gpio_v2_line_values *values)136{137	int ret;138 139	ret = ioctl(fd, GPIO_V2_LINE_GET_VALUES_IOCTL, values);140	if (ret == -1) {141		ret = -errno;142		fprintf(stderr, "Failed to issue %s (%d), %s\n",143			"GPIOHANDLE_GET_LINE_VALUES_IOCTL", ret,144			strerror(errno));145	}146 147	return ret;148}149 150/**151 * gpiotools_release_line() - Release the line(s) of gpiochip152 * @fd:			The fd returned by153 *			gpiotools_request_line().154 *155 * Return:		On success return 0;156 *			On failure return the errno.157 */158int gpiotools_release_line(const int fd)159{160	int ret;161 162	ret = close(fd);163	if (ret == -1) {164		perror("Failed to close GPIO LINE device file");165		ret = -errno;166	}167 168	return ret;169}170 171/**172 * gpiotools_get() - Get value from specific line173 * @device_name:	The name of gpiochip without prefix "/dev/",174 *			such as "gpiochip0"175 * @line:		number of line, such as 2.176 *177 * Return:		On success return 0;178 *			On failure return the errno.179 */180int gpiotools_get(const char *device_name, unsigned int line)181{182	int ret;183	unsigned int value;184	unsigned int lines[] = {line};185 186	ret = gpiotools_gets(device_name, lines, 1, &value);187	if (ret)188		return ret;189	return value;190}191 192 193/**194 * gpiotools_gets() - Get values from specific lines.195 * @device_name:	The name of gpiochip without prefix "/dev/",196 *			such as "gpiochip0".197 * @lines:		An array desired lines, specified by offset198 *			index for the associated GPIO device.199 * @num_lines:		The number of lines to request.200 * @values:		The array of values get from gpiochip.201 *202 * Return:		On success return 0;203 *			On failure return the errno.204 */205int gpiotools_gets(const char *device_name, unsigned int *lines,206		   unsigned int num_lines, unsigned int *values)207{208	int fd, i;209	int ret;210	int ret_close;211	struct gpio_v2_line_config config;212	struct gpio_v2_line_values lv;213 214	memset(&config, 0, sizeof(config));215	config.flags = GPIO_V2_LINE_FLAG_INPUT;216	ret = gpiotools_request_line(device_name, lines, num_lines,217				     &config, CONSUMER);218	if (ret < 0)219		return ret;220 221	fd = ret;222	for (i = 0; i < num_lines; i++)223		gpiotools_set_bit(&lv.mask, i);224	ret = gpiotools_get_values(fd, &lv);225	if (!ret)226		for (i = 0; i < num_lines; i++)227			values[i] = gpiotools_test_bit(lv.bits, i);228	ret_close = gpiotools_release_line(fd);229	return ret < 0 ? ret : ret_close;230}231 232/**233 * gpiotools_set() - Set value to specific line234 * @device_name:	The name of gpiochip without prefix "/dev/",235 *			such as "gpiochip0"236 * @line:		number of line, such as 2.237 * @value:		The value of gpio, must be 0(low) or 1(high).238 *239 * Return:		On success return 0;240 *			On failure return the errno.241 */242int gpiotools_set(const char *device_name, unsigned int line,243		  unsigned int value)244{245	unsigned int lines[] = {line};246 247	return gpiotools_sets(device_name, lines, 1, &value);248}249 250/**251 * gpiotools_sets() - Set values to specific lines.252 * @device_name:	The name of gpiochip without prefix "/dev/",253 *			such as "gpiochip0".254 * @lines:		An array desired lines, specified by offset255 *			index for the associated GPIO device.256 * @num_lines:		The number of lines to request.257 * @values:		The array of values set to gpiochip, must be258 *			0(low) or 1(high).259 *260 * Return:		On success return 0;261 *			On failure return the errno.262 */263int gpiotools_sets(const char *device_name, unsigned int *lines,264		   unsigned int num_lines, unsigned int *values)265{266	int ret, i;267	struct gpio_v2_line_config config;268 269	memset(&config, 0, sizeof(config));270	config.flags = GPIO_V2_LINE_FLAG_OUTPUT;271	config.num_attrs = 1;272	config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES;273	for (i = 0; i < num_lines; i++) {274		gpiotools_set_bit(&config.attrs[0].mask, i);275		gpiotools_assign_bit(&config.attrs[0].attr.values,276				     i, values[i]);277	}278	ret = gpiotools_request_line(device_name, lines, num_lines,279				     &config, CONSUMER);280	if (ret < 0)281		return ret;282 283	return gpiotools_release_line(ret);284}285