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