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