From: Kent Gibson <warthog618@gmail.com>
To: linux-gpio@vger.kernel.org, bgolaszewski@baylibre.com
Cc: Kent Gibson <warthog618@gmail.com>
Subject: [libgpiod][PATCH v2 07/14] core: add support for SET_CONFIG
Date: Thu, 21 Nov 2019 08:35:49 +0800 [thread overview]
Message-ID: <20191121003556.9020-8-warthog618@gmail.com> (raw)
In-Reply-To: <20191121003556.9020-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.
Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
include/gpiod.h | 123 +++++++++++++++++++++++++++++++
lib/core.c | 188 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 308 insertions(+), 3 deletions(-)
diff --git a/include/gpiod.h b/include/gpiod.h
index cdf0435..f86c70e 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -1251,6 +1251,15 @@ void gpiod_line_release_bulk(struct gpiod_line_bulk *bulk) GPIOD_API;
*/
bool gpiod_line_is_requested(struct gpiod_line *line) GPIOD_API;
+/**
+ * @brief Check if the calling user has ownership of this line for values,
+ * not events.
+ * @param line GPIO line object.
+ * @return True if given line was requested for reading/setting values,
+ * false otherwise.
+ */
+bool gpiod_line_is_requested_values(struct gpiod_line *line) GPIOD_API;
+
/**
* @brief Check if the calling user has neither requested ownership of this
* line nor configured any event notifications.
@@ -1301,6 +1310,7 @@ int gpiod_line_set_value(struct gpiod_line *line, int value) GPIOD_API;
* @brief Set the values of a set of GPIO lines.
* @param bulk Set of GPIO lines to reserve.
* @param values An array holding line_bulk->num_lines new 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.
*
@@ -1310,6 +1320,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 ece3b13..9511a22 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;
bool needs_update;
@@ -457,6 +473,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 (!gpiod_line_is_requested_values(line)) {
+ errno = EPERM;
+ return false;
+ }
+ }
+
+ return true;
+}
+
static bool line_bulk_all_free(struct gpiod_line_bulk *bulk)
{
struct gpiod_line *line, **lineptr;
@@ -471,6 +501,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;
@@ -495,7 +546,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;
@@ -524,7 +575,6 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
else if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
req.flags |= GPIOHANDLE_REQUEST_OUTPUT;
-
gpiod_line_bulk_foreach_line_off(bulk, line, i) {
req.lineoffsets[i] = gpiod_line_offset(line);
if (config->request_type ==
@@ -548,8 +598,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);
line_maybe_update(line);
}
@@ -590,6 +644,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);
line_maybe_update(line);
@@ -688,6 +743,11 @@ bool gpiod_line_is_requested(struct gpiod_line *line)
line->state == LINE_REQUESTED_EVENTS);
}
+bool gpiod_line_is_requested_values(struct gpiod_line *line)
+{
+ return (line->state == LINE_REQUESTED_VALUES);
+}
+
bool gpiod_line_is_free(struct gpiod_line *line)
{
return line->state == LINE_FREE;
@@ -768,9 +828,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];
+ line_maybe_update(line);
+ }
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->needs_update) {
+ errno = EPERM;
+ return -1;
+ }
+ 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-11-21 0:36 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-21 0:35 [libgpiod][PATCH v2 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 01/14] core: add support for bias flags Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 02/14] tests: add tests " Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 03/14] bindings: cxx: add support " Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 04/14] bindings: cxx: tests: add tests " Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 05/14] bindings: python: add support " Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 06/14] bindings: python: tests: add tests " Kent Gibson
2019-11-21 0:35 ` Kent Gibson [this message]
2019-11-21 0:35 ` [libgpiod] [PATCH v2 08/14] tests: add tests for SET_CONFIG Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 09/14] bindings: cxx: add support " Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 10/14] bindings: cxx: tests: add tests for SET_CONFIG methods Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 11/14] bindings: python: add support for SET_CONFIG Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 12/14] bindings: python: tests: add tests for SET_CONFIG methods Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 13/14] tools: add support for bias flags Kent Gibson
2019-11-21 0:35 ` [libgpiod] [PATCH v2 14/14] tools: add tests for bias and drive flags Kent Gibson
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=20191121003556.9020-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).