From: Kent Gibson <warthog618@gmail.com>
To: linux-gpio@vger.kernel.org, bgolaszewski@baylibre.com
Cc: Kent Gibson <warthog618@gmail.com>
Subject: [libgpiod][PATCH v3 07/14] core: add support for SET_CONFIG
Date: Mon, 25 Nov 2019 22:31:50 +0800 [thread overview]
Message-ID: <20191125143157.26154-8-warthog618@gmail.com> (raw)
In-Reply-To: <20191125143157.26154-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 | 187 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 307 insertions(+), 3 deletions(-)
diff --git a/include/gpiod.h b/include/gpiod.h
index 86c3ea9..185e2f4 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -1246,6 +1246,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.
@@ -1296,6 +1305,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.
*
@@ -1305,6 +1315,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..71bb4fb 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 (!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;
@@ -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;
@@ -512,7 +563,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 ==
@@ -536,8 +586,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 +637,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);
@@ -686,6 +741,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;
@@ -766,9 +826,130 @@ 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-11-25 14:32 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-25 14:31 [libgpiod][PATCH v3 00/14] Add support for bias flags and SET_CONFIG Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 01/14] core: add support for bias flags Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 02/14] tests: add tests " Kent Gibson
2019-11-28 10:28 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 03/14] bindings: cxx: add support " Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 04/14] bindings: cxx: tests: add tests " Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 05/14] bindings: python: add support " Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 06/14] bindings: python: tests: add tests " Kent Gibson
2019-11-25 14:31 ` Kent Gibson [this message]
2019-11-28 10:29 ` [libgpiod][PATCH v3 07/14] core: add support for SET_CONFIG Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 08/14] tests: add tests " Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 09/14] bindings: cxx: add support " Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 10/14] bindings: cxx: tests: add tests for SET_CONFIG methods Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 11/14] bindings: python: add support for SET_CONFIG Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 12/14] bindings: python: tests: add tests for SET_CONFIG methods Kent Gibson
2019-11-25 14:31 ` [libgpiod][PATCH v3 13/14] tools: add support for bias flags Kent Gibson
2019-11-28 10:29 ` Bartosz Golaszewski
2019-11-25 14:31 ` [libgpiod][PATCH v3 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=20191125143157.26154-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.