From: Kent Gibson <warthog618@gmail.com>
To: linux-gpio@vger.kernel.org, bgolaszewski@baylibre.com
Cc: Kent Gibson <warthog618@gmail.com>
Subject: [libgpiod][PATCH v4 07/20] core: add support for SET_CONFIG
Date: Sun, 1 Dec 2019 11:23:54 +0800 [thread overview]
Message-ID: <20191201032407.23589-8-warthog618@gmail.com> (raw)
In-Reply-To: <20191201032407.23589-1-warthog618@gmail.com>
Extend the libgpiod API to support the setting line configuration using the
GPIO GPIOHANDLE_SET_CONFIG_IOCTL uAPI ioctl.
The core change is the addition of gpiod_line_set_config, which provides a
low level wrapper around the ioctl.
Additionally, higher level helper functions, gpiod_line_set_flags,
gpiod_line_set_direction_input, and gpiod_line_set_direction_output provide
slightly simplified APIs for common use cases.
Bulk forms of all functions are also provided.
Documented the fields of gpiod_line to better identify the purpose of
each where the field name alone is not sufficiently clear, and to
indicate which flags are applicable to each field.
Implementation includes a few helper functions that serve to keep the
code tidier and are consistent with similar helper functions already
present.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
include/gpiod.h | 113 ++++++++++++++++++++++++++++++
lib/core.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 293 insertions(+), 2 deletions(-)
diff --git a/include/gpiod.h b/include/gpiod.h
index 86c3ea9..41527d3 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -1305,6 +1305,119 @@ int gpiod_line_set_value(struct gpiod_line *line, int value) GPIOD_API;
int gpiod_line_set_value_bulk(struct gpiod_line_bulk *bulk,
const int *values) GPIOD_API;
+/**
+ * @}
+ *
+ * @defgroup __line_config__ Setting line configuration
+ * @{
+ */
+
+/**
+ * @brief Update the configuration of a single GPIO line.
+ * @param line GPIO line object.
+ * @param direction Updated direction which may be one of
+ * GPIOD_LINE_REQUEST_DIRECTION_AS_IS,
+ * GPIOD_LINE_REQUEST_DIRECTION_INPUT, or
+ * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
+ * @param flags Replacement flags.
+ * @param value The new output value for the line when direction is
+ * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ */
+int gpiod_line_set_config(struct gpiod_line *line, int direction,
+ int flags, int value) GPIOD_API;
+
+/**
+ * @brief Update the configuration of a set of GPIO lines.
+ * @param bulk Set of GPIO lines.
+ * @param direction Updated direction which may be one of
+ * GPIOD_LINE_REQUEST_DIRECTION_AS_IS,
+ * GPIOD_LINE_REQUEST_DIRECTION_INPUT, or
+ * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
+ * @param flags Replacement flags.
+ * @param values An array holding line_bulk->num_lines new logical values
+ * for lines when direction is
+ * GPIOD_LINE_REQUEST_DIRECTION_OUTPUT.
+ * A NULL pointer is interpreted as a logical low for all lines.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ *
+ * If the lines were not previously requested together, the behavior is
+ * undefined.
+ */
+int gpiod_line_set_config_bulk(struct gpiod_line_bulk *bulk,
+ int direction, int flags,
+ const int *values) GPIOD_API;
+
+
+/**
+ * @brief Update the configuration flags of a single GPIO line.
+ * @param line GPIO line object.
+ * @param flags Replacement flags.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ */
+int gpiod_line_set_flags(struct gpiod_line *line, int flags) GPIOD_API;
+
+/**
+ * @brief Update the configuration flags of a set of GPIO lines.
+ * @param bulk Set of GPIO lines.
+ * @param flags Replacement flags.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ *
+ * If the lines were not previously requested together, the behavior is
+ * undefined.
+ */
+int gpiod_line_set_flags_bulk(struct gpiod_line_bulk *bulk,
+ int flags) GPIOD_API;
+
+/**
+ * @brief Set the direction of a single GPIO line to input.
+ * @param line GPIO line object.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ */
+int gpiod_line_set_direction_input(struct gpiod_line *line) GPIOD_API;
+
+/**
+ * @brief Set the direction of a set of GPIO lines to input.
+ * @param bulk Set of GPIO lines.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ *
+ * If the lines were not previously requested together, the behavior is
+ * undefined.
+ */
+int gpiod_line_set_direction_input_bulk(struct gpiod_line_bulk *bulk
+ ) GPIOD_API;
+
+/**
+ * @brief Set the direction of a single GPIO line to output.
+ * @param line GPIO line object.
+ * @param value The logical value output on the line.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ */
+int gpiod_line_set_direction_output(struct gpiod_line *line,
+ int value) GPIOD_API;
+
+/**
+ * @brief Set the direction of a set of GPIO lines to output.
+ * @param bulk Set of GPIO lines.
+ * @param values An array holding line_bulk->num_lines new logical values
+ * for lines. A NULL pointer is interpreted as a logical low
+ * for all lines.
+ * @return 0 is the operation succeeds. In case of an error this routine
+ * returns -1 and sets the last error number.
+ *
+ * If the lines were not previously requested together, the behavior is
+ * undefined.
+ */
+int gpiod_line_set_direction_output_bulk(struct gpiod_line_bulk *bulk,
+ const int *values) GPIOD_API;
+
/**
* @}
*
diff --git a/lib/core.c b/lib/core.c
index 0465de9..8966e7d 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -34,10 +34,26 @@ struct line_fd_handle {
struct gpiod_line {
unsigned int offset;
+
+ /* The GPIOD_LINE_DIRECTION */
int direction;
+
+ /* The GPIOD_LINE_ACTIVE_STATE */
int active_state;
+
+ /* The logical value last written to the line. */
+ int output_value;
+
+ /* The GPIOLINE_FLAGs returned by GPIO_GET_LINEINFO_IOCTL */
__u32 info_flags;
+ /* The GPIOD_LINE_REQUEST_FLAGs provided to request the line. */
+ __u32 req_flags;
+
+ /*
+ * Indicator of LINE_FREE, LINE_REQUESTED_VALUES or
+ * LINE_REQUESTED_EVENTS
+ */
int state;
struct gpiod_chip *chip;
@@ -445,6 +461,20 @@ static bool line_bulk_all_requested(struct gpiod_line_bulk *bulk)
return true;
}
+static bool line_bulk_all_requested_values(struct gpiod_line_bulk *bulk)
+{
+ struct gpiod_line *line, **lineptr;
+
+ gpiod_line_bulk_foreach_line(bulk, line, lineptr) {
+ if (line->state != LINE_REQUESTED_VALUES) {
+ errno = EPERM;
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool line_bulk_all_free(struct gpiod_line_bulk *bulk)
{
struct gpiod_line *line, **lineptr;
@@ -459,6 +489,27 @@ static bool line_bulk_all_free(struct gpiod_line_bulk *bulk)
return true;
}
+static bool line_request_direction_is_valid(int direction)
+{
+ if ((direction == GPIOD_LINE_REQUEST_DIRECTION_AS_IS) ||
+ (direction == GPIOD_LINE_REQUEST_DIRECTION_INPUT) ||
+ (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT))
+ return true;
+
+ errno = EINVAL;
+ return false;
+}
+
+static __u32 line_request_direction_to_gpio_handleflag(int direction)
+{
+ if (direction == GPIOD_LINE_REQUEST_DIRECTION_INPUT)
+ return GPIOHANDLE_REQUEST_INPUT;
+ if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+ return GPIOHANDLE_REQUEST_OUTPUT;
+
+ return 0;
+}
+
static __u32 line_request_flag_to_gpio_handleflag(int flags)
{
int hflags = 0;
@@ -483,7 +534,7 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
const struct gpiod_line_request_config *config,
const int *default_vals)
{
- struct gpiod_line *line, **lineptr;
+ struct gpiod_line *line;
struct line_fd_handle *line_fd;
struct gpiohandle_request req;
unsigned int i;
@@ -536,8 +587,12 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
if (!line_fd)
return -1;
- gpiod_line_bulk_foreach_line(bulk, line, lineptr) {
+ gpiod_line_bulk_foreach_line_off(bulk, line, i) {
line->state = LINE_REQUESTED_VALUES;
+ line->req_flags = config->flags;
+ if (config->request_type ==
+ GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+ line->output_value = req.default_values[i];
line_set_fd(line, line_fd);
rv = gpiod_line_update(line);
@@ -583,6 +638,7 @@ static int line_request_event_single(struct gpiod_line *line,
return -1;
line->state = LINE_REQUESTED_EVENTS;
+ line->req_flags = config->flags;
line_set_fd(line, line_fd);
rv = gpiod_line_update(line);
@@ -766,9 +822,131 @@ int gpiod_line_set_value_bulk(struct gpiod_line_bulk *bulk, const int *values)
if (rv < 0)
return -1;
+ gpiod_line_bulk_foreach_line_off(bulk, line, i)
+ line->output_value = data.values[i];
+
+ return 0;
+}
+
+int gpiod_line_set_config(struct gpiod_line *line, int direction,
+ int flags, int value)
+{
+ struct gpiod_line_bulk bulk;
+
+ gpiod_line_bulk_init(&bulk);
+ gpiod_line_bulk_add(&bulk, line);
+
+ return gpiod_line_set_config_bulk(&bulk, direction, flags, &value);
+}
+
+int gpiod_line_set_config_bulk(struct gpiod_line_bulk *bulk,
+ int direction, int flags,
+ const int *values)
+{
+ struct gpiohandle_config hcfg;
+ struct gpiod_line *line;
+ unsigned int i;
+ int rv, fd;
+
+ if (!line_bulk_same_chip(bulk) ||
+ !line_bulk_all_requested_values(bulk))
+ return -1;
+
+ if (!line_request_direction_is_valid(direction))
+ return -1;
+
+ memset(&hcfg, 0, sizeof(hcfg));
+
+ hcfg.flags = line_request_flag_to_gpio_handleflag(flags);
+ hcfg.flags |= line_request_direction_to_gpio_handleflag(direction);
+ if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT && values) {
+ for (i = 0; i < gpiod_line_bulk_num_lines(bulk); i++)
+ hcfg.default_values[i] = (uint8_t)!!values[i];
+ }
+
+ line = gpiod_line_bulk_get_line(bulk, 0);
+ fd = line_get_fd(line);
+
+ rv = ioctl(fd, GPIOHANDLE_SET_CONFIG_IOCTL, &hcfg);
+ if (rv < 0)
+ return -1;
+
+ gpiod_line_bulk_foreach_line_off(bulk, line, i) {
+ line->req_flags = flags;
+ if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+ line->output_value = hcfg.default_values[i];
+
+ rv = gpiod_line_update(line);
+ if (rv < 0)
+ return rv;
+ }
return 0;
}
+int gpiod_line_set_flags(struct gpiod_line *line, int flags)
+{
+ struct gpiod_line_bulk bulk;
+
+ gpiod_line_bulk_init(&bulk);
+ gpiod_line_bulk_add(&bulk, line);
+
+ return gpiod_line_set_flags_bulk(&bulk, flags);
+}
+
+int gpiod_line_set_flags_bulk(struct gpiod_line_bulk *bulk, int flags)
+{
+ struct gpiod_line *line;
+ int values[GPIOD_LINE_BULK_MAX_LINES];
+ unsigned int i;
+ int direction;
+
+ line = gpiod_line_bulk_get_line(bulk, 0);
+ if (line->direction == GPIOD_LINE_DIRECTION_OUTPUT) {
+ gpiod_line_bulk_foreach_line_off(bulk, line, i)
+ values[i] = line->output_value;
+
+ direction = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
+ } else {
+ direction = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
+ }
+
+ return gpiod_line_set_config_bulk(bulk, direction,
+ flags, values);
+}
+
+int gpiod_line_set_direction_input(struct gpiod_line *line)
+{
+ return gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_INPUT,
+ line->req_flags, 0);
+}
+
+int gpiod_line_set_direction_input_bulk(struct gpiod_line_bulk *bulk)
+{
+ struct gpiod_line *line;
+
+ line = gpiod_line_bulk_get_line(bulk, 0);
+ return gpiod_line_set_config_bulk(bulk,
+ GPIOD_LINE_REQUEST_DIRECTION_INPUT,
+ line->req_flags, NULL);
+}
+
+int gpiod_line_set_direction_output(struct gpiod_line *line, int value)
+{
+ return gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+ line->req_flags, value);
+}
+
+int gpiod_line_set_direction_output_bulk(struct gpiod_line_bulk *bulk,
+ const int *values)
+{
+ struct gpiod_line *line;
+
+ line = gpiod_line_bulk_get_line(bulk, 0);
+ return gpiod_line_set_config_bulk(bulk,
+ GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+ line->req_flags, values);
+}
+
int gpiod_line_event_wait(struct gpiod_line *line,
const struct timespec *timeout)
{
--
2.24.0
next prev parent reply other threads:[~2019-12-01 3:25 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-12-01 3:23 [libgpiod][PATCH v4 00/20] Add support for bias flags and SET_CONFIG Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 01/20] core: add support for bias flags Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 02/20] tests: add tests " Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 03/20] bindings: cxx: add support " Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 04/20] bindings: cxx: tests: add tests " Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 05/20] bindings: python: add support " Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 06/20] bindings: python: tests: add tests " Kent Gibson
2019-12-01 3:23 ` Kent Gibson [this message]
2019-12-01 3:23 ` [libgpiod][PATCH v4 08/20] tests: add tests for SET_CONFIG Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 09/20] bindings: cxx: add support " Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 10/20] bindings: cxx: tests: add tests for SET_CONFIG methods Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 11/20] bindings: python: move tuple to int array conversion into helper function Kent Gibson
2019-12-01 3:23 ` [libgpiod][PATCH v4 12/20] bindings: python: add support for SET_CONFIG Kent Gibson
2019-12-01 3:24 ` [libgpiod][PATCH v4 13/20] bindings: python: tests: add tests for SET_CONFIG methods Kent Gibson
2019-12-01 3:24 ` [libgpiod][PATCH v4 14/20] tools: add support for bias flags Kent Gibson
2019-12-01 3:24 ` [libgpiod][PATCH v4 15/20] tools: add tests " Kent Gibson
2019-12-01 3:24 ` [libgpiod][PATCH v4 16/20] tools: gpioset: add support for drive flags Kent Gibson
2019-12-01 3:24 ` [libgpiod][PATCH v4 17/20] tools: add tests " Kent Gibson
2019-12-01 3:24 ` [libgpiod][PATCH v4 18/20] core: document gpiod_line_set_value_bulk NULL values behaviour Kent Gibson
2019-12-01 3:24 ` [libgpiod][PATCH v4 19/20] bindings: cxx: fix indentation of wrapped field descriptions Kent Gibson
2019-12-01 3:24 ` [libgpiod][PATCH v4 20/20] bindings: python: make vals in gpiod_Line_set_value consistent with other functions Kent Gibson
2019-12-10 16:06 ` [libgpiod][PATCH v4 00/20] Add support for bias flags and SET_CONFIG Bartosz Golaszewski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20191201032407.23589-8-warthog618@gmail.com \
--to=warthog618@gmail.com \
--cc=bgolaszewski@baylibre.com \
--cc=linux-gpio@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).