linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG
@ 2019-11-15 14:43 Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 01/19] core: move request flag to handle flag conversion into a separate function Kent Gibson
                   ` (19 more replies)
  0 siblings, 20 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

This patch series adds support for changes to the GPIO uAPI that are on
track to be included in the v5.5 kernel.  There are two components to the
uAPI changes - the addition of bias flags and a new SET_CONFIG ioctl.  This
series adds support to the libgpiod API, and to both C++ and Python
bindings, for both of those components.

The libgpiod tools are also updated, where appropriate, to support the bias
flags.

There are a few additional patches that serve to restructure the code to
simplify subsequent patches, or to fix minor problems discovered during
development. These patches are generally adjacent to the main patch most
relevant to that patch.

The series is based on the current libgpiod master@9ed02fc.

Kent Gibson (19):
  core: move request flag to handle flag conversion into a separate
    function
  API: add support for bias flags
  core: fix misspelling of parameter
  tests: add tests for bias flags
  bindings: cxx: drop noexcept from direction and active_state
  bindings: cxx: initialise bitset with integer instead of string
  bindings: cxx: add support for bias flags
  bindings: cxx: tests: add tests for bias flags
  bindings: python: add support for bias flags
  bindings: python: tests: add tests for bias flags
  API: add support for SET_CONFIG
  tests: add tests for SET_CONFIG
  core: allow gpiod_line_set_value_bulk to accept null values
  bindings: cxx: add support for SET_CONFIG
  bindings: cxx: tests: add tests for SET_CONFIG methods
  bindings: python: add support for SET_CONFIG
  bindings: python: tests: add tests for SET_CONFIG methods
  tools: add support for bias flags
  treewide: change "correspond with" to "correspond to"

 bindings/cxx/gpiod.hpp                 |  85 +++-
 bindings/cxx/line.cpp                  |  60 ++-
 bindings/cxx/line_bulk.cpp             |  95 ++++-
 bindings/cxx/tests/tests-line.cpp      | 215 ++++++++++
 bindings/python/gpiodmodule.c          | 469 +++++++++++++++++++++-
 bindings/python/tests/gpiod_py_test.py | 254 ++++++++++++
 include/gpiod.h                        | 303 +++++++++++++-
 lib/core.c                             | 250 ++++++++++--
 lib/ctxless.c                          | 115 +++++-
 tests/mockup/gpio-mockup.c             |   2 +-
 tests/tests-ctxless.c                  |  64 ++-
 tests/tests-event.c                    | 120 ++++++
 tests/tests-line.c                     | 522 ++++++++++++++++++++++++-
 tools/gpioget.c                        |  24 +-
 tools/gpiomon.c                        |  28 +-
 tools/gpioset.c                        |  26 +-
 16 files changed, 2561 insertions(+), 71 deletions(-)

-- 
2.24.0


^ permalink raw reply	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 01/19] core: move request flag to handle flag conversion into a separate function
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 02/19] API: add support for bias flags Kent Gibson
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Move common conversion code from line_request_values and
line_request_event_single into a separate function to simplify adding
additional flags.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 lib/core.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/lib/core.c b/lib/core.c
index a04514e..f05e595 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -463,6 +463,20 @@ static bool line_bulk_all_free(struct gpiod_line_bulk *bulk)
 	return true;
 }
 
+static __u32 line_request_flag_to_gpio_handleflag(int flags)
+{
+	int hflags = 0;
+
+	if (flags & GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN)
+		hflags |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
+	if (flags & GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE)
+		hflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
+	if (flags & GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW)
+		hflags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
+
+	return hflags;
+}
+
 static int line_request_values(struct gpiod_line_bulk *bulk,
 			       const struct gpiod_line_request_config *config,
 			       const int *default_vals)
@@ -488,19 +502,14 @@ static int line_request_values(struct gpiod_line_bulk *bulk,
 
 	memset(&req, 0, sizeof(req));
 
-	if (config->flags & GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN)
-		req.flags |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
-	if (config->flags & GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE)
-		req.flags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
-	if (config->flags & GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW)
-		req.flags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
+	req.lines = gpiod_line_bulk_num_lines(bulk);
+	req.flags = line_request_flag_to_gpio_handleflag(config->flags);
 
 	if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_INPUT)
 		req.flags |= GPIOHANDLE_REQUEST_INPUT;
 	else if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
 		req.flags |= GPIOHANDLE_REQUEST_OUTPUT;
 
-	req.lines = gpiod_line_bulk_num_lines(bulk);
 
 	gpiod_line_bulk_foreach_line_off(bulk, line, i) {
 		req.lineoffsets[i] = gpiod_line_offset(line);
@@ -548,15 +557,9 @@ static int line_request_event_single(struct gpiod_line *line,
 			sizeof(req.consumer_label) - 1);
 
 	req.lineoffset = gpiod_line_offset(line);
+	req.handleflags = line_request_flag_to_gpio_handleflag(config->flags);
 	req.handleflags |= GPIOHANDLE_REQUEST_INPUT;
 
-	if (config->flags & GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN)
-		req.handleflags |= GPIOHANDLE_REQUEST_OPEN_DRAIN;
-	if (config->flags & GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE)
-		req.handleflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
-	if (config->flags & GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW)
-		req.handleflags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
-
 	if (config->request_type == GPIOD_LINE_REQUEST_EVENT_RISING_EDGE)
 		req.eventflags |= GPIOEVENT_REQUEST_RISING_EDGE;
 	else if (config->request_type == GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE)
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 02/19] API: add support for bias flags
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 01/19] core: move request flag to handle flag conversion into a separate function Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-18 13:51   ` Bartosz Golaszewski
  2019-11-15 14:43 ` [libgpiod] [PATCH 03/19] core: fix misspelling of parameter Kent Gibson
                   ` (17 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Extend the libgpiod API to support the bias flags recently added to the
kernel GPIO uAPI.  The core change is the addition of
GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP
and GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN flags to be passed into
line_request functions, and the addition of gpiod_line_bias to return the
bias state of lines.

Extended variants of the ctxless functions that accept an active_low flag
are added to also accept other flags. The variant names add a "_ext"
suffix to the name of the original function.

Based on initial work by Drew Fustini <drew@pdp7.com>.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 include/gpiod.h | 184 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/core.c      |  32 ++++++---
 lib/ctxless.c   | 115 +++++++++++++++++++++++++++---
 3 files changed, 313 insertions(+), 18 deletions(-)

diff --git a/include/gpiod.h b/include/gpiod.h
index 9860ea8..0f01cab 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -84,6 +84,22 @@ struct gpiod_line_bulk;
  * the need to use the gpiod_* structures or to keep track of resources.
  */
 
+/**
+ * @brief Miscellaneous GPIO flags.
+ */
+enum {
+	GPIOD_CTXLESS_FLAG_OPEN_DRAIN		= GPIOD_BIT(0),
+	/**< The line is an open-drain port. */
+	GPIOD_CTXLESS_FLAG_OPEN_SOURCE		= GPIOD_BIT(1),
+	/**< The line is an open-source port. */
+	GPIOD_CTXLESS_FLAG_BIAS_DISABLE		= GPIOD_BIT(2),
+	/**< The line has neither either pull-up nor pull-down resistor */
+	GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN	= GPIOD_BIT(3),
+	/**< The line has pull-down resistor enabled */
+	GPIOD_CTXLESS_FLAG_BIAS_PULL_UP		= GPIOD_BIT(4),
+	/**< The line has pull-up resistor enabled */
+};
+
 /**
  * @brief Read current value from a single GPIO line.
  * @param device Name, path, number or label of the gpiochip.
@@ -95,6 +111,19 @@ struct gpiod_line_bulk;
 int gpiod_ctxless_get_value(const char *device, unsigned int offset,
 			    bool active_low, const char *consumer) GPIOD_API;
 
+/**
+ * @brief Read current value from a single GPIO line.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param offset Offset of the GPIO line.
+ * @param active_low The active state of this line - true if low.
+ * @param flags The flags for the line.
+ * @param consumer Name of the consumer.
+ * @return 0 or 1 (GPIO value) if the operation succeeds, -1 on error.
+ */
+int gpiod_ctxless_get_value_ext(const char *device, unsigned int offset,
+				bool active_low, int flags,
+				const char *consumer) GPIOD_API;
+
 /**
  * @brief Read current values from a set of GPIO lines.
  * @param device Name, path, number or label of the gpiochip.
@@ -110,6 +139,24 @@ int gpiod_ctxless_get_value_multiple(const char *device,
 				     unsigned int num_lines, bool active_low,
 				     const char *consumer) GPIOD_API;
 
+/**
+ * @brief Read current values from a set of GPIO lines.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param offsets Array of offsets of lines whose values should be read.
+ * @param values Buffer in which the values will be stored.
+ * @param num_lines Number of lines, must be > 0.
+ * @param active_low The active state of this line - true if low.
+ * @param flags The flags for the lines.
+ * @param consumer Name of the consumer.
+ * @return 0 if the operation succeeds, -1 on error.
+ */
+int gpiod_ctxless_get_value_multiple_ext(const char *device,
+					 const unsigned int *offsets,
+					 int *values,
+					 unsigned int num_lines,
+					 bool active_low, int flags,
+					 const char *consumer) GPIOD_API;
+
 /**
  * @brief Simple set value callback signature.
  */
@@ -133,6 +180,26 @@ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
 			    gpiod_ctxless_set_value_cb cb,
 			    void *data) GPIOD_API;
 
+/**
+ * @brief Set value of a single GPIO line.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param offset The offset of the GPIO line.
+ * @param value New value (0 or 1).
+ * @param active_low The active state of this line - true if low.
+ * @param flags The flags for the line.
+ * @param consumer Name of the consumer.
+ * @param cb Optional callback function that will be called right after setting
+ *           the value. Users can use this, for example, to pause the execution
+ *           after toggling a GPIO.
+ * @param data Optional user data that will be passed to the callback function.
+ * @return 0 if the operation succeeds, -1 on error.
+ */
+int gpiod_ctxless_set_value_ext(const char *device, unsigned int offset,
+				int value, bool active_low, int flags,
+				const char *consumer,
+				gpiod_ctxless_set_value_cb cb,
+				void *data) GPIOD_API;
+
 /**
  * @brief Set values of multiple GPIO lines.
  * @param device Name, path, number or label of the gpiochip.
@@ -153,6 +220,29 @@ int gpiod_ctxless_set_value_multiple(const char *device,
 				     gpiod_ctxless_set_value_cb cb,
 				     void *data) GPIOD_API;
 
+/**
+ * @brief Set values of multiple GPIO lines.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param offsets Array of offsets of lines the values of which should be set.
+ * @param values Array of integers containing new values.
+ * @param num_lines Number of lines, must be > 0.
+ * @param active_low The active state of this line - true if low.
+ * @param flags The flags for the lines.
+ * @param consumer Name of the consumer.
+ * @param cb Optional callback function that will be called right after setting
+ *           all values. Works the same as in ::gpiod_ctxless_set_value.
+ * @param data Optional user data that will be passed to the callback function.
+ * @return 0 if the operation succeeds, -1 on error.
+ */
+int gpiod_ctxless_set_value_multiple_ext(const char *device,
+					 const unsigned int *offsets,
+					 const int *values,
+					 unsigned int num_lines,
+					 bool active_low, int flags,
+					 const char *consumer,
+					 gpiod_ctxless_set_value_cb cb,
+					 void *data) GPIOD_API;
+
 /**
  * @brief Event types that the ctxless event monitor can wait for.
  */
@@ -327,6 +417,31 @@ int gpiod_ctxless_event_monitor(const char *device, int event_type,
 				gpiod_ctxless_event_handle_cb event_cb,
 				void *data) GPIOD_API;
 
+/**
+ * @brief Wait for events on a single GPIO line.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param event_type Type of events to listen for.
+ * @param offset GPIO line offset to monitor.
+ * @param active_low The active state of this line - true if low.
+ * @param flags The flags for the line.
+ * @param consumer Name of the consumer.
+ * @param timeout Maximum wait time for each iteration.
+ * @param poll_cb Callback function to call when waiting for events.
+ * @param event_cb Callback function to call for each line event.
+ * @param data User data passed to the callback.
+ * @return 0 if no errors were encountered, -1 if an error occurred.
+ * @note The way the ctxless event loop works is described in detail in
+ *       ::gpiod_ctxless_event_monitor_multiple - this is just a wrapper aound
+ *       this routine which calls it for a single GPIO line.
+ */
+int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
+				    unsigned int offset, bool active_low,
+				    int flags, const char *consumer,
+				    const struct timespec *timeout,
+				    gpiod_ctxless_event_poll_cb poll_cb,
+				    gpiod_ctxless_event_handle_cb event_cb,
+				    void *data) GPIOD_API;
+
 /**
  * @brief Wait for events on multiple GPIO lines.
  * @param device Name, path, number or label of the gpiochip.
@@ -366,6 +481,47 @@ int gpiod_ctxless_event_monitor_multiple(
 			gpiod_ctxless_event_handle_cb event_cb,
 			void *data) GPIOD_API;
 
+/**
+ * @brief Wait for events on multiple GPIO lines.
+ * @param device Name, path, number or label of the gpiochip.
+ * @param event_type Type of events to listen for.
+ * @param offsets Array of GPIO line offsets to monitor.
+ * @param num_lines Number of lines to monitor.
+ * @param active_low The active state of this line - true if low.
+ * @param flags The flags for the lines.
+ * @param consumer Name of the consumer.
+ * @param timeout Maximum wait time for each iteration.
+ * @param poll_cb Callback function to call when waiting for events. Can
+ *                be NULL.
+ * @param event_cb Callback function to call on event occurrence.
+ * @param data User data passed to the callback.
+ * @return 0 no errors were encountered, -1 if an error occurred.
+ * @note The poll callback can be NULL in which case the routine will fall
+ *       back to a basic, ppoll() based callback.
+ *
+ * Internally this routine opens the GPIO chip, requests the set of lines for
+ * the type of events specified in the event_type parameter and calls the
+ * polling callback in a loop. The role of the polling callback is to detect
+ * input events on a set of file descriptors and notify the caller about the
+ * fds ready for reading.
+ *
+ * The ctxless event loop then reads each queued event from marked descriptors
+ * and calls the event callback. Both callbacks can stop the loop at any
+ * point.
+ *
+ * The poll_cb argument can be NULL in which case the function falls back to
+ * a default, ppoll() based callback.
+ */
+int gpiod_ctxless_event_monitor_multiple_ext(
+			const char *device, int event_type,
+			const unsigned int *offsets,
+			unsigned int num_lines, bool active_low, int flags,
+			const char *consumer, const struct timespec *timeout,
+			gpiod_ctxless_event_poll_cb poll_cb,
+			gpiod_ctxless_event_handle_cb event_cb,
+			void *data) GPIOD_API;
+
+
 /**
  * @brief Determine the chip name and line offset of a line with given name.
  * @param name The name of the GPIO line to lookup.
@@ -658,6 +814,20 @@ enum {
 	/**< The active state of a GPIO is active-low. */
 };
 
+/**
+ * @brief Possible internal bias settings.
+ */
+enum {
+	GPIOD_LINE_BIAS_AS_IS = 1,
+	/**< The internal bias state is unknown. */
+	GPIOD_LINE_BIAS_DISABLE,
+	/**< The internal bias is disabled. */
+	GPIOD_LINE_BIAS_PULL_UP,
+	/**< The internal pull-up bias is enabled. */
+	GPIOD_LINE_BIAS_PULL_DOWN,
+	/**< The internal pull-down bias is enabled. */
+};
+
 /**
  * @brief Read the GPIO line offset.
  * @param line GPIO line object.
@@ -697,6 +867,14 @@ int gpiod_line_direction(struct gpiod_line *line) GPIOD_API;
  */
 int gpiod_line_active_state(struct gpiod_line *line) GPIOD_API;
 
+/**
+ * @brief Read the GPIO line bias setting.
+ * @param line GPIO line object.
+ * @return Returns GPIOD_LINE_BIAS_PULL_UP, GPIOD_LINE_BIAS_PULL_DOWN,
+ *         GPIOD_LINE_BIAS_DISABLE or GPIOD_LINE_BIAS_AS_IS.
+ */
+int gpiod_line_bias(struct gpiod_line *line) GPIOD_API;
+
 /**
  * @brief Check if the line is currently in use.
  * @param line GPIO line object.
@@ -792,6 +970,12 @@ enum {
 	/**< The line is an open-source port. */
 	GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW	= GPIOD_BIT(2),
 	/**< The active state of the line is low (high is the default). */
+	GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE	= GPIOD_BIT(3),
+	/**< The line has neither either pull-up nor pull-down resistor */
+	GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN	= GPIOD_BIT(4),
+	/**< The line has pull-down resistor enabled */
+	GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP	= GPIOD_BIT(5),
+	/**< The line has pull-up resistor enabled */
 };
 
 /**
diff --git a/lib/core.c b/lib/core.c
index f05e595..9b7d88f 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -36,9 +36,7 @@ struct gpiod_line {
 	unsigned int offset;
 	int direction;
 	int active_state;
-	bool used;
-	bool open_source;
-	bool open_drain;
+	__u32 flags;
 
 	int state;
 	bool needs_update;
@@ -359,19 +357,31 @@ int gpiod_line_active_state(struct gpiod_line *line)
 	return line->active_state;
 }
 
+int gpiod_line_bias(struct gpiod_line *line)
+{
+	if (line->flags & GPIOLINE_FLAG_BIAS_DISABLE)
+		return GPIOD_LINE_BIAS_DISABLE;
+	if (line->flags & GPIOLINE_FLAG_BIAS_PULL_UP)
+		return GPIOD_LINE_BIAS_PULL_UP;
+	if (line->flags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
+		return GPIOD_LINE_BIAS_PULL_DOWN;
+
+	return GPIOD_LINE_BIAS_AS_IS;
+}
+
 bool gpiod_line_is_used(struct gpiod_line *line)
 {
-	return line->used;
+	return line->flags & GPIOLINE_FLAG_KERNEL;
 }
 
 bool gpiod_line_is_open_drain(struct gpiod_line *line)
 {
-	return line->open_drain;
+	return line->flags & GPIOLINE_FLAG_OPEN_DRAIN;
 }
 
 bool gpiod_line_is_open_source(struct gpiod_line *line)
 {
-	return line->open_source;
+	return line->flags & GPIOLINE_FLAG_OPEN_SOURCE;
 }
 
 bool gpiod_line_needs_update(struct gpiod_line *line)
@@ -398,9 +408,7 @@ int gpiod_line_update(struct gpiod_line *line)
 						? GPIOD_LINE_ACTIVE_STATE_LOW
 						: GPIOD_LINE_ACTIVE_STATE_HIGH;
 
-	line->used = info.flags & GPIOLINE_FLAG_KERNEL;
-	line->open_drain = info.flags & GPIOLINE_FLAG_OPEN_DRAIN;
-	line->open_source = info.flags & GPIOLINE_FLAG_OPEN_SOURCE;
+	line->flags = info.flags;
 
 	strncpy(line->name, info.name, sizeof(line->name));
 	strncpy(line->consumer, info.consumer, sizeof(line->consumer));
@@ -473,6 +481,12 @@ static __u32 line_request_flag_to_gpio_handleflag(int flags)
 		hflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
 	if (flags & GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW)
 		hflags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
+	if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE)
+		hflags |= GPIOHANDLE_REQUEST_BIAS_DISABLE;
+	if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN)
+		hflags |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN;
+	if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP)
+		hflags |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;
 
 	return hflags;
 }
diff --git a/lib/ctxless.c b/lib/ctxless.c
index ba85018..44f1872 100644
--- a/lib/ctxless.c
+++ b/lib/ctxless.c
@@ -14,6 +14,26 @@
 #include <stdio.h>
 #include <string.h>
 
+static int ctxless_flags_to_line_request_flags(bool active_low, int flags)
+{
+	int lflags = 0;
+
+	if (active_low)
+		lflags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
+	if (flags & GPIOD_CTXLESS_FLAG_OPEN_DRAIN)
+		lflags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN;
+	if (flags & GPIOD_CTXLESS_FLAG_OPEN_SOURCE)
+		lflags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
+	if (flags & GPIOD_CTXLESS_FLAG_BIAS_DISABLE)
+		lflags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
+	if (flags & GPIOD_CTXLESS_FLAG_BIAS_PULL_UP)
+		lflags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
+	if (flags & GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN)
+		lflags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
+
+	return lflags;
+}
+
 int gpiod_ctxless_get_value(const char *device, unsigned int offset,
 			    bool active_low, const char *consumer)
 {
@@ -27,16 +47,45 @@ int gpiod_ctxless_get_value(const char *device, unsigned int offset,
 	return value;
 }
 
+int gpiod_ctxless_get_value_ext(const char *device, unsigned int offset,
+				bool active_low, int flags,
+				const char *consumer)
+{
+	int value, rv;
+
+	rv = gpiod_ctxless_get_value_multiple_ext(device, &offset, &value, 1,
+						  active_low, flags, consumer);
+	if (rv < 0)
+		return rv;
+
+	return value;
+}
+
 int gpiod_ctxless_get_value_multiple(const char *device,
 				     const unsigned int *offsets, int *values,
 				     unsigned int num_lines, bool active_low,
 				     const char *consumer)
+{
+	int rv;
+
+	rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
+						  num_lines, active_low, 0,
+						  consumer);
+	return rv;
+}
+
+int gpiod_ctxless_get_value_multiple_ext(const char *device,
+					 const unsigned int *offsets,
+					 int *values,
+					 unsigned int num_lines,
+					 bool active_low, int flags,
+					 const char *consumer)
 {
 	struct gpiod_line_bulk bulk;
 	struct gpiod_chip *chip;
 	struct gpiod_line *line;
 	unsigned int i;
-	int rv, flags;
+	int rv, lflags;
 
 	if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
 		errno = EINVAL;
@@ -59,9 +108,8 @@ int gpiod_ctxless_get_value_multiple(const char *device,
 		gpiod_line_bulk_add(&bulk, line);
 	}
 
-	flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
-
-	rv = gpiod_line_request_bulk_input_flags(&bulk, consumer, flags);
+	lflags = ctxless_flags_to_line_request_flags(active_low, flags);
+	rv = gpiod_line_request_bulk_input_flags(&bulk, consumer, lflags);
 	if (rv < 0) {
 		gpiod_chip_close(chip);
 		return -1;
@@ -83,17 +131,39 @@ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
 						active_low, consumer, cb, data);
 }
 
+int gpiod_ctxless_set_value_ext(const char *device, unsigned int offset,
+				int value, bool active_low, int flags,
+				const char *consumer,
+				gpiod_ctxless_set_value_cb cb, void *data)
+{
+	return gpiod_ctxless_set_value_multiple_ext(device, &offset, &value,
+						    1, active_low, flags,
+						    consumer, cb, data);
+}
+
 int gpiod_ctxless_set_value_multiple(const char *device,
 				     const unsigned int *offsets,
 				     const int *values, unsigned int num_lines,
 				     bool active_low, const char *consumer,
 				     gpiod_ctxless_set_value_cb cb, void *data)
+{
+	return gpiod_ctxless_set_value_multiple_ext(device, offsets, values,
+						    num_lines, active_low,
+						    0, consumer, cb, data);
+}
+
+int gpiod_ctxless_set_value_multiple_ext(
+			const char *device,
+			const unsigned int *offsets,
+			const int *values, unsigned int num_lines,
+			bool active_low, int flags, const char *consumer,
+			gpiod_ctxless_set_value_cb cb, void *data)
 {
 	struct gpiod_line_bulk bulk;
 	struct gpiod_chip *chip;
 	struct gpiod_line *line;
 	unsigned int i;
-	int rv, flags;
+	int rv, lflags;
 
 	if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
 		errno = EINVAL;
@@ -116,10 +186,9 @@ int gpiod_ctxless_set_value_multiple(const char *device,
 		gpiod_line_bulk_add(&bulk, line);
 	}
 
-	flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
-
+	lflags = ctxless_flags_to_line_request_flags(active_low, flags);
 	rv = gpiod_line_request_bulk_output_flags(&bulk, consumer,
-						  flags, values);
+						  lflags, values);
 	if (rv < 0) {
 		gpiod_chip_close(chip);
 		return -1;
@@ -216,6 +285,19 @@ int gpiod_ctxless_event_monitor(const char *device, int event_type,
 						    poll_cb, event_cb, data);
 }
 
+int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
+				    unsigned int offset, bool active_low,
+				    int flags, const char *consumer,
+				    const struct timespec *timeout,
+				    gpiod_ctxless_event_poll_cb poll_cb,
+				    gpiod_ctxless_event_handle_cb event_cb,
+				    void *data)
+{
+	return gpiod_ctxless_event_monitor_multiple_ext(
+			device, event_type, &offset, 1, active_low,
+			flags, consumer, timeout, poll_cb, event_cb, data);
+}
+
 int gpiod_ctxless_event_monitor_multiple(
 			const char *device, int event_type,
 			const unsigned int *offsets,
@@ -225,6 +307,21 @@ int gpiod_ctxless_event_monitor_multiple(
 			gpiod_ctxless_event_poll_cb poll_cb,
 			gpiod_ctxless_event_handle_cb event_cb,
 			void *data)
+{
+	return gpiod_ctxless_event_monitor_multiple_ext(
+			device, event_type, offsets,
+			num_lines, active_low, 0, consumer, timeout,
+			poll_cb, event_cb, data);
+}
+
+int gpiod_ctxless_event_monitor_multiple_ext(
+			const char *device, int event_type,
+			const unsigned int *offsets,
+			unsigned int num_lines, bool active_low, int flags,
+			const char *consumer, const struct timespec *timeout,
+			gpiod_ctxless_event_poll_cb poll_cb,
+			gpiod_ctxless_event_handle_cb event_cb,
+			void *data)
 {
 	struct gpiod_ctxless_event_poll_fd fds[GPIOD_LINE_BULK_MAX_LINES];
 	struct gpiod_line_request_config conf;
@@ -259,7 +356,7 @@ int gpiod_ctxless_event_monitor_multiple(
 		gpiod_line_bulk_add(&bulk, line);
 	}
 
-	conf.flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
+	conf.flags = ctxless_flags_to_line_request_flags(active_low, flags);
 	conf.consumer = consumer;
 
 	if (event_type == GPIOD_CTXLESS_EVENT_RISING_EDGE) {
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 03/19] core: fix misspelling of parameter
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 01/19] core: move request flag to handle flag conversion into a separate function Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 02/19] API: add support for bias flags Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 04/19] tests: add tests for bias flags Kent Gibson
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Trivial fix to bring gpiod_ctxless_event_monitor_multiple documentation
into line with gpiod_ctxless_event_monitor_multiple_ext.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 include/gpiod.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/gpiod.h b/include/gpiod.h
index 0f01cab..159d745 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -460,7 +460,7 @@ int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
  *       back to a basic, ppoll() based callback.
  *
  * Internally this routine opens the GPIO chip, requests the set of lines for
- * the type of events specified in the event_type paramter and calls the
+ * the type of events specified in the event_type parameter and calls the
  * polling callback in a loop. The role of the polling callback is to detect
  * input events on a set of file descriptors and notify the caller about the
  * fds ready for reading.
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 04/19] tests: add tests for bias flags
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (2 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 03/19] core: fix misspelling of parameter Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-18 13:51   ` Bartosz Golaszewski
  2019-11-15 14:43 ` [libgpiod] [PATCH 05/19] bindings: cxx: drop noexcept from direction and active_state Kent Gibson
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Extend test coverage over the bias flags, gpiod_line_bias and the extended
ctxless functions.

Also update existing tests to check bias flags where line state is checked.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 tests/tests-ctxless.c |  64 +++++++++++++++++++++-
 tests/tests-event.c   | 120 ++++++++++++++++++++++++++++++++++++++++++
 tests/tests-line.c    |  98 ++++++++++++++++++++++++++++++++++
 3 files changed, 280 insertions(+), 2 deletions(-)

diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c
index c1e1ca6..da70587 100644
--- a/tests/tests-ctxless.c
+++ b/tests/tests-ctxless.c
@@ -26,11 +26,41 @@ GPIOD_TEST_CASE(get_value, 0, { 8 })
 	g_assert_cmpint(ret, ==, 1);
 }
 
-static void set_value_check(gpointer data G_GNUC_UNUSED)
+GPIOD_TEST_CASE(get_value_ext, 0, { 8 })
+{
+	gint ret;
+
+	ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
+				false, GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN,
+				GPIOD_TEST_CONSUMER);
+	g_assert_cmpint(ret, ==, 0);
+
+	ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
+				false, GPIOD_CTXLESS_FLAG_BIAS_PULL_UP,
+				GPIOD_TEST_CONSUMER);
+	g_assert_cmpint(ret, ==, 1);
+
+	ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
+				true, GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN,
+				GPIOD_TEST_CONSUMER);
+	g_assert_cmpint(ret, ==, 1);
+
+	ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
+				true, GPIOD_CTXLESS_FLAG_BIAS_PULL_UP,
+				GPIOD_TEST_CONSUMER);
+	g_assert_cmpint(ret, ==, 0);
+}
+
+static void set_value_check_hi(gpointer data G_GNUC_UNUSED)
 {
 	g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
 }
 
+static void set_value_check_lo(gpointer data G_GNUC_UNUSED)
+{
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
+}
+
 GPIOD_TEST_CASE(set_value, 0, { 8 })
 {
 	gint ret;
@@ -39,13 +69,43 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
 
 	ret = gpiod_ctxless_set_value(gpiod_test_chip_name(0), 3, 1,
 				      false, GPIOD_TEST_CONSUMER,
-				      set_value_check, NULL);
+				      set_value_check_hi, NULL);
 	gpiod_test_return_if_failed();
 	g_assert_cmpint(ret, ==, 0);
 
 	g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
 }
 
+GPIOD_TEST_CASE(set_value_ext, 0, { 8 })
+{
+	gint ret;
+
+	gpiod_test_chip_set_pull(0, 3, 0);
+
+	ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
+			false, 0, GPIOD_TEST_CONSUMER,
+			set_value_check_hi, NULL);
+	gpiod_test_return_if_failed();
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
+
+	// test drive flags by checking that sets are caught by emulation
+	ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
+			false, GPIOD_CTXLESS_FLAG_OPEN_DRAIN,
+			GPIOD_TEST_CONSUMER, set_value_check_lo, NULL);
+	gpiod_test_return_if_failed();
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
+
+	gpiod_test_chip_set_pull(0, 3, 1);
+	ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 0,
+			false, GPIOD_CTXLESS_FLAG_OPEN_SOURCE,
+			GPIOD_TEST_CONSUMER, set_value_check_hi, NULL);
+	gpiod_test_return_if_failed();
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
+}
+
 static const guint get_value_multiple_offsets[] = {
 	1, 3, 4, 5, 6, 7, 8, 9, 13, 14
 };
diff --git a/tests/tests-event.c b/tests/tests-event.c
index 28b77ec..d425d1a 100644
--- a/tests/tests-event.c
+++ b/tests/tests-event.c
@@ -196,6 +196,126 @@ GPIOD_TEST_CASE(both_edges_active_low, 0, { 8 })
 	g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
 }
 
+GPIOD_TEST_CASE(both_edges_bias_disable, 0, { 8 })
+{
+	g_autoptr(GpiodTestEventThread) ev_thread = NULL;
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct timespec ts = { 1, 0 };
+	struct gpiod_line_event ev;
+	struct gpiod_line *line;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 7);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	ret = gpiod_line_request_both_edges_events_flags(line,
+		GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE);
+	g_assert_cmpint(ret, ==, 0);
+
+	ev_thread = gpiod_test_start_event_thread(0, 7, 100);
+
+	ret = gpiod_line_event_wait(line, &ts);
+	g_assert_cmpint(ret, ==, 1);
+
+	ret = gpiod_line_event_read(line, &ev);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
+
+	ret = gpiod_line_event_wait(line, &ts);
+	g_assert_cmpint(ret, ==, 1);
+
+	ret = gpiod_line_event_read(line, &ev);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
+}
+
+GPIOD_TEST_CASE(both_edges_bias_pull_down, 0, { 8 })
+{
+	g_autoptr(GpiodTestEventThread) ev_thread = NULL;
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct timespec ts = { 1, 0 };
+	struct gpiod_line_event ev;
+	struct gpiod_line *line;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 7);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	ret = gpiod_line_request_both_edges_events_flags(line,
+		GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
+	g_assert_cmpint(ret, ==, 0);
+
+	ev_thread = gpiod_test_start_event_thread(0, 7, 100);
+
+	ret = gpiod_line_event_wait(line, &ts);
+	g_assert_cmpint(ret, ==, 1);
+
+	ret = gpiod_line_event_read(line, &ev);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
+
+	ret = gpiod_line_event_wait(line, &ts);
+	g_assert_cmpint(ret, ==, 1);
+
+	ret = gpiod_line_event_read(line, &ev);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
+}
+
+GPIOD_TEST_CASE(both_edges_bias_pull_up, 0, { 8 })
+{
+	g_autoptr(GpiodTestEventThread) ev_thread = NULL;
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct timespec ts = { 1, 0 };
+	struct gpiod_line_event ev;
+	struct gpiod_line *line;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 7);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	ret = gpiod_line_request_both_edges_events_flags(line,
+		GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+	g_assert_cmpint(ret, ==, 0);
+
+	ev_thread = gpiod_test_start_event_thread(0, 7, 100);
+
+	ret = gpiod_line_event_wait(line, &ts);
+	g_assert_cmpint(ret, ==, 1);
+
+	ret = gpiod_line_event_read(line, &ev);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
+
+	ret = gpiod_line_event_wait(line, &ts);
+	g_assert_cmpint(ret, ==, 1);
+
+	ret = gpiod_line_event_read(line, &ev);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
+}
+
 GPIOD_TEST_CASE(falling_edge_active_low, 0, { 8 })
 {
 	g_autoptr(GpiodTestEventThread) ev_thread = NULL;
diff --git a/tests/tests-line.c b/tests/tests-line.c
index 4792211..b4bef1a 100644
--- a/tests/tests-line.c
+++ b/tests/tests-line.c
@@ -451,6 +451,7 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
 	g_assert_false(gpiod_line_is_used(line));
 	g_assert_false(gpiod_line_is_open_drain(line));
 	g_assert_false(gpiod_line_is_open_source(line));
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
 
 	config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
 	config.consumer = GPIOD_TEST_CONSUMER;
@@ -462,6 +463,7 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
 	g_assert_true(gpiod_line_is_used(line));
 	g_assert_true(gpiod_line_is_open_drain(line));
 	g_assert_false(gpiod_line_is_open_source(line));
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
 	g_assert_cmpint(gpiod_line_direction(line), ==,
 			GPIOD_LINE_DIRECTION_OUTPUT);
 
@@ -475,8 +477,11 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
 	g_assert_true(gpiod_line_is_used(line));
 	g_assert_false(gpiod_line_is_open_drain(line));
 	g_assert_true(gpiod_line_is_open_source(line));
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
 	g_assert_cmpint(gpiod_line_direction(line), ==,
 			GPIOD_LINE_DIRECTION_OUTPUT);
+
+	gpiod_line_release(line);
 }
 
 GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
@@ -510,6 +515,7 @@ GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
 	g_assert_true(gpiod_line_is_used(line));
 	g_assert_true(gpiod_line_is_open_drain(line));
 	g_assert_false(gpiod_line_is_open_source(line));
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
 	g_assert_cmpint(gpiod_line_active_state(line), ==,
 			GPIOD_LINE_ACTIVE_STATE_LOW);
 	g_assert_cmpint(gpiod_line_direction(line), ==,
@@ -526,8 +532,59 @@ GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
 	g_assert_true(gpiod_line_is_used(line));
 	g_assert_false(gpiod_line_is_open_drain(line));
 	g_assert_true(gpiod_line_is_open_source(line));
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
 	g_assert_cmpint(gpiod_line_active_state(line), ==,
 			GPIOD_LINE_ACTIVE_STATE_LOW);
+
+	gpiod_line_release(line);
+
+	/*
+	 * Verify that pull-up/down flags work together
+	 * with active_low.
+	 */
+
+	config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
+	config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
+		       GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
+
+	ret = gpiod_line_request(line, &config, 0);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_true(gpiod_line_is_used(line));
+	g_assert_false(gpiod_line_is_open_drain(line));
+	g_assert_false(gpiod_line_is_open_source(line));
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN);
+	g_assert_cmpint(gpiod_line_active_state(line), ==,
+			GPIOD_LINE_ACTIVE_STATE_LOW);
+	g_assert_cmpint(gpiod_line_direction(line), ==,
+			GPIOD_LINE_DIRECTION_INPUT);
+
+	ret = gpiod_line_get_value(line);
+	g_assert_cmpint(ret, ==, 1);
+	g_assert_cmpint(errno, ==, 0);
+
+	gpiod_line_release(line);
+
+	config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP |
+		       GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
+
+	ret = gpiod_line_request(line, &config, 0);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_true(gpiod_line_is_used(line));
+	g_assert_false(gpiod_line_is_open_drain(line));
+	g_assert_false(gpiod_line_is_open_source(line));
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP);
+	g_assert_cmpint(gpiod_line_active_state(line), ==,
+			GPIOD_LINE_ACTIVE_STATE_LOW);
+	g_assert_cmpint(gpiod_line_direction(line), ==,
+			GPIOD_LINE_DIRECTION_INPUT);
+
+	ret = gpiod_line_get_value(line);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(errno, ==, 0);
+
+	gpiod_line_release(line);
 }
 
 GPIOD_TEST_CASE(open_source_open_drain_input_mode, 0, { 8 })
@@ -576,6 +633,47 @@ GPIOD_TEST_CASE(open_source_open_drain_simultaneously, 0, { 8 })
 	g_assert_cmpint(errno, ==, EINVAL);
 }
 
+GPIOD_TEST_CASE(multiple_bias_flags, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line *line;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 2);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
+					GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
+					GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
+	g_assert_cmpint(ret, ==, -1);
+	g_assert_cmpint(errno, ==, EINVAL);
+
+	ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
+					GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
+					GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+	g_assert_cmpint(ret, ==, -1);
+	g_assert_cmpint(errno, ==, EINVAL);
+
+	ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
+					GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
+					GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+	g_assert_cmpint(ret, ==, -1);
+	g_assert_cmpint(errno, ==, EINVAL);
+
+	ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
+					GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
+					GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
+					GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+	g_assert_cmpint(ret, ==, -1);
+	g_assert_cmpint(errno, ==, EINVAL);
+}
+
+
 /* Verify that the reference counting of the line fd handle works correctly. */
 GPIOD_TEST_CASE(release_one_use_another, 0, { 8 })
 {
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 05/19] bindings: cxx: drop noexcept from direction and active_state
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (3 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 04/19] tests: add tests for bias flags Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 06/19] bindings: cxx: initialise bitset with integer instead of string Kent Gibson
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Both direction and active_state methods can throw and so should not be
declared as noexcept.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/cxx/gpiod.hpp | 4 ++--
 bindings/cxx/line.cpp  | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp
index 13b4d5b..b5a9401 100644
--- a/bindings/cxx/gpiod.hpp
+++ b/bindings/cxx/gpiod.hpp
@@ -312,13 +312,13 @@ public:
 	 * @brief Get current direction of this line.
 	 * @return Current direction setting.
 	 */
-	GPIOD_API int direction(void) const noexcept;
+	GPIOD_API int direction(void) const;
 
 	/**
 	 * @brief Get current active state of this line.
 	 * @return Current active state setting.
 	 */
-	GPIOD_API int active_state(void) const noexcept;
+	GPIOD_API int active_state(void) const;
 
 	/**
 	 * @brief Check if this line is used by the kernel or other user space
diff --git a/bindings/cxx/line.cpp b/bindings/cxx/line.cpp
index b698960..df6eada 100644
--- a/bindings/cxx/line.cpp
+++ b/bindings/cxx/line.cpp
@@ -49,7 +49,7 @@ unsigned int line::offset(void) const
 	return consumer ? ::std::string(consumer) : ::std::string();
 }
 
-int line::direction(void) const noexcept
+int line::direction(void) const
 {
 	this->throw_if_null();
 
@@ -58,7 +58,7 @@ int line::direction(void) const noexcept
 	return dir == GPIOD_LINE_DIRECTION_INPUT ? DIRECTION_INPUT : DIRECTION_OUTPUT;
 }
 
-int line::active_state(void) const noexcept
+int line::active_state(void) const
 {
 	this->throw_if_null();
 
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 06/19] bindings: cxx: initialise bitset with integer instead of string
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (4 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 05/19] bindings: cxx: drop noexcept from direction and active_state Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-18 13:51   ` Bartosz Golaszewski
  2019-11-15 14:43 ` [libgpiod] [PATCH 07/19] bindings: cxx: add support for bias flags Kent Gibson
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Initialising bitsets with string is inefficient and confusing.
Initialise them with the corresponding int instead.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/cxx/line_bulk.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp
index 8369930..c708c8b 100644
--- a/bindings/cxx/line_bulk.cpp
+++ b/bindings/cxx/line_bulk.cpp
@@ -11,9 +11,9 @@
 
 namespace gpiod {
 
-const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW("001");
-const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE("010");
-const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN("100");
+const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW(GPIOD_BIT(0));
+const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE(GPIOD_BIT(1));
+const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN(GPIOD_BIT(2));
 
 namespace {
 
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 07/19] bindings: cxx: add support for bias flags
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (5 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 06/19] bindings: cxx: initialise bitset with integer instead of string Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 08/19] bindings: cxx: tests: add tests " Kent Gibson
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Add support for bias flags in line requests and returning the line bias
setting via a bias accessor.

Based on initial work by Drew Fustini <drew@pdp7.com>.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/cxx/gpiod.hpp     | 26 ++++++++++++++++++++++++++
 bindings/cxx/line.cpp      | 19 +++++++++++++++++++
 bindings/cxx/line_bulk.cpp |  6 ++++++
 3 files changed, 51 insertions(+)

diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp
index b5a9401..2b1a6ab 100644
--- a/bindings/cxx/gpiod.hpp
+++ b/bindings/cxx/gpiod.hpp
@@ -233,6 +233,12 @@ struct line_request
 	/**< The line is an open-source port. */
 	GPIOD_API static const ::std::bitset<32> FLAG_OPEN_DRAIN;
 	/**< The line is an open-drain port. */
+	GPIOD_API static const ::std::bitset<32> FLAG_BIAS_DISABLE;
+	/**< The line has neither pull-up nor pull-down resistor enabled */
+	GPIOD_API static const ::std::bitset<32> FLAG_BIAS_PULL_DOWN;
+	/**< The line has a configurable pull-down resistor enabled */
+	GPIOD_API static const ::std::bitset<32> FLAG_BIAS_PULL_UP;
+	/**< The line has a configurable pull-up resistor enabled */
 
 	::std::string consumer;
 	/**< Consumer name to pass to the request. */
@@ -320,6 +326,12 @@ public:
 	 */
 	GPIOD_API int active_state(void) const;
 
+	/**
+	 * @brief Get current bias of this line.
+	 * @return Current bias setting.
+	 */
+	GPIOD_API int bias(void) const;
+
 	/**
 	 * @brief Check if this line is used by the kernel or other user space
 	 *        process.
@@ -456,6 +468,20 @@ public:
 		/**< Line's active state is high. */
 	};
 
+	/**
+	 * @brief Possible bias settings.
+	 */
+	enum : int {
+		BIAS_AS_IS = 1,
+		/**< Line's bias state is unknown. */
+		BIAS_DISABLE,
+		/**< Line's internal bias is disabled. */
+		BIAS_PULL_UP,
+		/**< Line's internal pull-up bias is enabled. */
+		BIAS_PULL_DOWN,
+		/**< Line's internal pull-down bias is enabled. */
+	};
+
 private:
 
 	line(::gpiod_line* line, const chip& owner);
diff --git a/bindings/cxx/line.cpp b/bindings/cxx/line.cpp
index df6eada..dd6bb6a 100644
--- a/bindings/cxx/line.cpp
+++ b/bindings/cxx/line.cpp
@@ -67,6 +67,25 @@ int line::active_state(void) const
 	return active == GPIOD_LINE_ACTIVE_STATE_HIGH ? ACTIVE_HIGH : ACTIVE_LOW;
 }
 
+int line::bias(void) const
+{
+	this->throw_if_null();
+
+	int bias = ::gpiod_line_bias(this->_m_line);
+
+	switch (bias) {
+	case GPIOD_LINE_BIAS_PULL_UP:
+		return BIAS_PULL_UP;
+	case GPIOD_LINE_BIAS_PULL_DOWN:
+		return BIAS_PULL_DOWN;
+	case GPIOD_LINE_BIAS_DISABLE:
+		return BIAS_DISABLE;
+	case GPIOD_LINE_BIAS_AS_IS:
+	default:
+		return BIAS_AS_IS;
+	}
+}
+
 bool line::is_used(void) const
 {
 	this->throw_if_null();
diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp
index c708c8b..5f1cac4 100644
--- a/bindings/cxx/line_bulk.cpp
+++ b/bindings/cxx/line_bulk.cpp
@@ -14,6 +14,9 @@ namespace gpiod {
 const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW(GPIOD_BIT(0));
 const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE(GPIOD_BIT(1));
 const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN(GPIOD_BIT(2));
+const ::std::bitset<32> line_request::FLAG_BIAS_DISABLE(GPIOD_BIT(3));
+const ::std::bitset<32> line_request::FLAG_BIAS_PULL_DOWN(GPIOD_BIT(4));
+const ::std::bitset<32> line_request::FLAG_BIAS_PULL_UP(GPIOD_BIT(5));
 
 namespace {
 
@@ -38,6 +41,9 @@ const ::std::map<::std::bitset<32>, int, bitset_cmp> reqflag_mapping = {
 	{ line_request::FLAG_ACTIVE_LOW,	GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, },
 	{ line_request::FLAG_OPEN_DRAIN,	GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, },
 	{ line_request::FLAG_OPEN_SOURCE,	GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE, },
+	{ line_request::FLAG_BIAS_DISABLE,	GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE, },
+	{ line_request::FLAG_BIAS_PULL_DOWN,	GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN, },
+	{ line_request::FLAG_BIAS_PULL_UP,	GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP, },
 };
 
 } /* namespace */
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 08/19] bindings: cxx: tests: add tests for bias flags
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (6 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 07/19] bindings: cxx: add support for bias flags Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 09/19] bindings: python: add support " Kent Gibson
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Extend test coverage over the bias flags in requests and the bias setting
returned by line.bias().

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/cxx/tests/tests-line.cpp | 87 +++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/bindings/cxx/tests/tests-line.cpp b/bindings/cxx/tests/tests-line.cpp
index 3ba2fc2..ef314b9 100644
--- a/bindings/cxx/tests/tests-line.cpp
+++ b/bindings/cxx/tests/tests-line.cpp
@@ -52,6 +52,9 @@ TEST_CASE("Line information can be correctly retrieved", "[line]")
 		REQUIRE(line.consumer().empty());
 		REQUIRE_FALSE(line.is_requested());
 		REQUIRE_FALSE(line.is_used());
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+		REQUIRE(line.bias() == ::gpiod::line::BIAS_AS_IS);
 	}
 
 	SECTION("exported line")
@@ -68,6 +71,9 @@ TEST_CASE("Line information can be correctly retrieved", "[line]")
 		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
 		REQUIRE(line.is_requested());
 		REQUIRE(line.is_used());
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+		REQUIRE(line.bias() == ::gpiod::line::BIAS_AS_IS);
 	}
 
 	SECTION("exported line with flags")
@@ -88,6 +94,87 @@ TEST_CASE("Line information can be correctly retrieved", "[line]")
 		REQUIRE(line.is_used());
 		REQUIRE(line.is_open_drain());
 		REQUIRE_FALSE(line.is_open_source());
+		REQUIRE(line.bias() == ::gpiod::line::BIAS_AS_IS);
+	}
+
+	SECTION("exported open source line")
+	{
+		::gpiod::line_request config;
+
+		config.consumer = consumer.c_str();
+		config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+		config.flags = ::gpiod::line_request::FLAG_OPEN_SOURCE;
+		line.request(config);
+
+		REQUIRE(line.offset() == 4);
+		REQUIRE(line.name() == "gpio-mockup-A-4");
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+		REQUIRE(line.is_requested());
+		REQUIRE(line.is_used());
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE(line.is_open_source());
+		REQUIRE(line.bias() == ::gpiod::line::BIAS_AS_IS);
+	}
+
+	SECTION("exported bias disable line")
+	{
+		::gpiod::line_request config;
+
+		config.consumer = consumer.c_str();
+		config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+		config.flags = ::gpiod::line_request::FLAG_BIAS_DISABLE;
+		line.request(config);
+
+		REQUIRE(line.offset() == 4);
+		REQUIRE(line.name() == "gpio-mockup-A-4");
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+		REQUIRE(line.is_requested());
+		REQUIRE(line.is_used());
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+		REQUIRE(line.bias() == ::gpiod::line::BIAS_DISABLE);
+	}
+
+	SECTION("exported pull-down line")
+	{
+		::gpiod::line_request config;
+
+		config.consumer = consumer.c_str();
+		config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+		config.flags = ::gpiod::line_request::FLAG_BIAS_PULL_DOWN;
+		line.request(config);
+
+		REQUIRE(line.offset() == 4);
+		REQUIRE(line.name() == "gpio-mockup-A-4");
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+		REQUIRE(line.is_requested());
+		REQUIRE(line.is_used());
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+		REQUIRE(line.bias() == ::gpiod::line::BIAS_PULL_DOWN);
+	}
+
+	SECTION("exported pull-up line")
+	{
+		::gpiod::line_request config;
+
+		config.consumer = consumer.c_str();
+		config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+		config.flags = ::gpiod::line_request::FLAG_BIAS_PULL_UP;
+		line.request(config);
+
+		REQUIRE(line.offset() == 4);
+		REQUIRE(line.name() == "gpio-mockup-A-4");
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+		REQUIRE(line.is_requested());
+		REQUIRE(line.is_used());
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+		REQUIRE(line.bias() == ::gpiod::line::BIAS_PULL_UP);
 	}
 
 	SECTION("update line info")
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 09/19] bindings: python: add support for bias flags
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (7 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 08/19] bindings: cxx: tests: add tests " Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 10/19] bindings: python: tests: add tests " Kent Gibson
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Add support for bias flags in line requests and returning the line bias
setting via a bias accessor.

Based on initial work by Drew Fustini <drew@pdp7.com>.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/python/gpiodmodule.c | 82 +++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c
index d3c15ad..de8d6d1 100644
--- a/bindings/python/gpiodmodule.c
+++ b/bindings/python/gpiodmodule.c
@@ -60,6 +60,9 @@ enum {
 	gpiod_LINE_REQ_FLAG_OPEN_DRAIN		= GPIOD_BIT(0),
 	gpiod_LINE_REQ_FLAG_OPEN_SOURCE		= GPIOD_BIT(1),
 	gpiod_LINE_REQ_FLAG_ACTIVE_LOW		= GPIOD_BIT(2),
+	gpiod_LINE_REQ_FLAG_BIAS_DISABLE	= GPIOD_BIT(3),
+	gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN	= GPIOD_BIT(4),
+	gpiod_LINE_REQ_FLAG_BIAS_PULL_UP	= GPIOD_BIT(5),
 };
 
 enum {
@@ -72,6 +75,13 @@ enum {
 	gpiod_ACTIVE_LOW,
 };
 
+enum {
+	gpiod_BIAS_AS_IS = 1,
+	gpiod_BIAS_DISABLE,
+	gpiod_BIAS_PULL_UP,
+	gpiod_BIAS_PULL_DOWN,
+};
+
 enum {
 	gpiod_RISING_EDGE = 1,
 	gpiod_FALLING_EDGE,
@@ -358,6 +368,34 @@ static PyObject *gpiod_Line_active_state(gpiod_LineObject *self,
 	return ret;
 }
 
+PyDoc_STRVAR(gpiod_Line_bias_doc,
+"bias() -> integer\n"
+"\n"
+"Get the bias setting of this GPIO line.");
+
+static PyObject *gpiod_Line_bias(gpiod_LineObject *self,
+				 PyObject *Py_UNUSED(ignored))
+{
+	int bias;
+
+	if (gpiod_ChipIsClosed(self->owner))
+		return NULL;
+
+	bias = gpiod_line_bias(self->line);
+
+	switch (bias) {
+	case GPIOD_LINE_BIAS_PULL_UP:
+		return Py_BuildValue("I", gpiod_BIAS_PULL_UP);
+	case GPIOD_LINE_BIAS_PULL_DOWN:
+		return Py_BuildValue("I", gpiod_BIAS_PULL_DOWN);
+	case GPIOD_LINE_BIAS_DISABLE:
+		return Py_BuildValue("I", gpiod_BIAS_DISABLE);
+	case GPIOD_LINE_BIAS_AS_IS:
+	default:
+		return Py_BuildValue("I", gpiod_BIAS_AS_IS);
+	}
+}
+
 PyDoc_STRVAR(gpiod_Line_is_used_doc,
 "is_used() -> boolean\n"
 "\n"
@@ -752,6 +790,12 @@ static PyMethodDef gpiod_Line_methods[] = {
 		.ml_flags = METH_NOARGS,
 		.ml_doc = gpiod_Line_active_state_doc,
 	},
+	{
+		.ml_name = "bias",
+		.ml_meth = (PyCFunction)gpiod_Line_bias,
+		.ml_flags = METH_NOARGS,
+		.ml_doc = gpiod_Line_bias_doc,
+	},
 	{
 		.ml_name = "is_used",
 		.ml_meth = (PyCFunction)gpiod_Line_is_used,
@@ -1030,6 +1074,12 @@ static void gpiod_MakeRequestConfig(struct gpiod_line_request_config *conf,
 		conf->flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
 	if (flags & gpiod_LINE_REQ_FLAG_ACTIVE_LOW)
 		conf->flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
+	if (flags & gpiod_LINE_REQ_FLAG_BIAS_DISABLE)
+		conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
+	if (flags & gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN)
+		conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
+	if (flags & gpiod_LINE_REQ_FLAG_BIAS_PULL_UP)
+		conf->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
 }
 
 PyDoc_STRVAR(gpiod_LineBulk_request_doc,
@@ -2313,6 +2363,26 @@ static gpiod_ConstDescr gpiod_ConstList[] = {
 		.name = "ACTIVE_LOW",
 		.val = gpiod_ACTIVE_LOW,
 	},
+	{
+		.typeobj = &gpiod_LineType,
+		.name = "BIAS_AS_IS",
+		.val = gpiod_BIAS_AS_IS,
+	},
+	{
+		.typeobj = &gpiod_LineType,
+		.name = "BIAS_DISABLE",
+		.val = gpiod_BIAS_DISABLE,
+	},
+	{
+		.typeobj = &gpiod_LineType,
+		.name = "BIAS_PULL_UP",
+		.val = gpiod_BIAS_PULL_UP,
+	},
+	{
+		.typeobj = &gpiod_LineType,
+		.name = "BIAS_PULL_DOWN",
+		.val = gpiod_BIAS_PULL_DOWN,
+	},
 	{
 		.typeobj = &gpiod_LineEventType,
 		.name = "RISING_EDGE",
@@ -2381,6 +2451,18 @@ static gpiod_ModuleConst gpiod_ModuleConsts[] = {
 		.name = "LINE_REQ_FLAG_ACTIVE_LOW",
 		.value = gpiod_LINE_REQ_FLAG_ACTIVE_LOW,
 	},
+	{
+		.name = "LINE_REQ_FLAG_BIAS_DISABLE",
+		.value = gpiod_LINE_REQ_FLAG_BIAS_DISABLE,
+	},
+	{
+		.name = "LINE_REQ_FLAG_BIAS_PULL_DOWN",
+		.value = gpiod_LINE_REQ_FLAG_BIAS_PULL_DOWN,
+	},
+	{
+		.name = "LINE_REQ_FLAG_BIAS_PULL_UP",
+		.value = gpiod_LINE_REQ_FLAG_BIAS_PULL_UP,
+	},
 	{ }
 };
 
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 10/19] bindings: python: tests: add tests for bias flags
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (8 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 09/19] bindings: python: add support " Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG Kent Gibson
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Extend test coverage to cover the bias flags in requests and the bias
setting returned by line.bias().

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/python/tests/gpiod_py_test.py | 91 ++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/bindings/python/tests/gpiod_py_test.py b/bindings/python/tests/gpiod_py_test.py
index ed31c8e..9330b43 100755
--- a/bindings/python/tests/gpiod_py_test.py
+++ b/bindings/python/tests/gpiod_py_test.py
@@ -306,6 +306,97 @@ class LineInfo(MockupTestCase):
             self.assertTrue(line.is_requested())
             self.assertTrue(line.is_open_drain())
             self.assertFalse(line.is_open_source())
+            self.assertEqual(line.bias(), gpiod.Line.BIAS_AS_IS)
+
+    def test_exported_open_drain_line(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(4)
+            flags = gpiod.LINE_REQ_FLAG_OPEN_DRAIN
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT,
+                         flags=flags)
+            self.assertEqual(line.offset(), 4)
+            self.assertEqual(line.name(), 'gpio-mockup-A-4')
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+            self.assertEqual(line.consumer(), default_consumer)
+            self.assertTrue(line.is_used())
+            self.assertTrue(line.is_requested())
+            self.assertTrue(line.is_open_drain())
+            self.assertFalse(line.is_open_source())
+            self.assertEqual(line.bias(), gpiod.Line.BIAS_AS_IS)
+
+    def test_exported_open_source_line(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(4)
+            flags = gpiod.LINE_REQ_FLAG_OPEN_SOURCE
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT,
+                         flags=flags)
+            self.assertEqual(line.offset(), 4)
+            self.assertEqual(line.name(), 'gpio-mockup-A-4')
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+            self.assertEqual(line.consumer(), default_consumer)
+            self.assertTrue(line.is_used())
+            self.assertTrue(line.is_requested())
+            self.assertFalse(line.is_open_drain())
+            self.assertTrue(line.is_open_source())
+            self.assertEqual(line.bias(), gpiod.Line.BIAS_AS_IS)
+
+    def test_exported_bias_disable_line(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(4)
+            flags = gpiod.LINE_REQ_FLAG_BIAS_DISABLE
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT,
+                         flags=flags)
+            self.assertEqual(line.offset(), 4)
+            self.assertEqual(line.name(), 'gpio-mockup-A-4')
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+            self.assertEqual(line.consumer(), default_consumer)
+            self.assertTrue(line.is_used())
+            self.assertTrue(line.is_requested())
+            self.assertFalse(line.is_open_drain())
+            self.assertFalse(line.is_open_source())
+            self.assertEqual(line.bias(), gpiod.Line.BIAS_DISABLE)
+
+    def test_exported_bias_pull_down_line(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(4)
+            flags = gpiod.LINE_REQ_FLAG_BIAS_PULL_DOWN
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT,
+                         flags=flags)
+            self.assertEqual(line.offset(), 4)
+            self.assertEqual(line.name(), 'gpio-mockup-A-4')
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+            self.assertEqual(line.consumer(), default_consumer)
+            self.assertTrue(line.is_used())
+            self.assertTrue(line.is_requested())
+            self.assertFalse(line.is_open_drain())
+            self.assertFalse(line.is_open_source())
+            self.assertEqual(line.bias(), gpiod.Line.BIAS_PULL_DOWN)
+
+    def test_exported_bias_pull_up_line(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(4)
+            flags = gpiod.LINE_REQ_FLAG_BIAS_PULL_UP
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT,
+                         flags=flags)
+            self.assertEqual(line.offset(), 4)
+            self.assertEqual(line.name(), 'gpio-mockup-A-4')
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(line.active_state(), gpiod.Line.ACTIVE_HIGH)
+            self.assertEqual(line.consumer(), default_consumer)
+            self.assertTrue(line.is_used())
+            self.assertTrue(line.is_requested())
+            self.assertFalse(line.is_open_drain())
+            self.assertFalse(line.is_open_source())
+            self.assertEqual(line.bias(), gpiod.Line.BIAS_PULL_UP)
 
     def test_update_line_info(self):
         with gpiod.Chip(mockup.chip_name(0)) as chip:
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (9 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 10/19] bindings: python: tests: add tests " Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-18 13:52   ` Bartosz Golaszewski
  2019-11-15 14:43 ` [libgpiod] [PATCH 12/19] tests: add tests " Kent Gibson
                   ` (8 subsequent siblings)
  19 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

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 | 115 ++++++++++++++++++++++++++++
 lib/core.c      | 196 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 300 insertions(+), 11 deletions(-)

diff --git a/include/gpiod.h b/include/gpiod.h
index 159d745..4053fd2 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -1252,6 +1252,14 @@ 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, 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.
@@ -1311,6 +1319,113 @@ 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.
+ * @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_bulk_input(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.
+ * @values The logical value to output for each line.
+ * @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_bulk_output(struct gpiod_line_bulk *bulk,
+					 const int *values) GPIOD_API;
+
 /**
  * @}
  *
diff --git a/lib/core.c b/lib/core.c
index 9b7d88f..c42cda5 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -36,10 +36,13 @@ struct gpiod_line {
 	unsigned int offset;
 	int direction;
 	int active_state;
-	__u32 flags;
+	int output_value;
+	__u32 lflags;
+	__u32 cflags;
 
 	int state;
 	bool needs_update;
+	bool as_is;
 
 	struct gpiod_chip *chip;
 	struct line_fd_handle *fd_handle;
@@ -359,11 +362,11 @@ int gpiod_line_active_state(struct gpiod_line *line)
 
 int gpiod_line_bias(struct gpiod_line *line)
 {
-	if (line->flags & GPIOLINE_FLAG_BIAS_DISABLE)
+	if (line->lflags & GPIOLINE_FLAG_BIAS_DISABLE)
 		return GPIOD_LINE_BIAS_DISABLE;
-	if (line->flags & GPIOLINE_FLAG_BIAS_PULL_UP)
+	if (line->lflags & GPIOLINE_FLAG_BIAS_PULL_UP)
 		return GPIOD_LINE_BIAS_PULL_UP;
-	if (line->flags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
+	if (line->lflags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
 		return GPIOD_LINE_BIAS_PULL_DOWN;
 
 	return GPIOD_LINE_BIAS_AS_IS;
@@ -371,17 +374,17 @@ int gpiod_line_bias(struct gpiod_line *line)
 
 bool gpiod_line_is_used(struct gpiod_line *line)
 {
-	return line->flags & GPIOLINE_FLAG_KERNEL;
+	return line->lflags & GPIOLINE_FLAG_KERNEL;
 }
 
 bool gpiod_line_is_open_drain(struct gpiod_line *line)
 {
-	return line->flags & GPIOLINE_FLAG_OPEN_DRAIN;
+	return line->lflags & GPIOLINE_FLAG_OPEN_DRAIN;
 }
 
 bool gpiod_line_is_open_source(struct gpiod_line *line)
 {
-	return line->flags & GPIOLINE_FLAG_OPEN_SOURCE;
+	return line->lflags & GPIOLINE_FLAG_OPEN_SOURCE;
 }
 
 bool gpiod_line_needs_update(struct gpiod_line *line)
@@ -408,7 +411,7 @@ int gpiod_line_update(struct gpiod_line *line)
 						? GPIOD_LINE_ACTIVE_STATE_LOW
 						: GPIOD_LINE_ACTIVE_STATE_HIGH;
 
-	line->flags = info.flags;
+	line->lflags = info.flags;
 
 	strncpy(line->name, info.name, sizeof(line->name));
 	strncpy(line->consumer, info.consumer, sizeof(line->consumer));
@@ -457,6 +460,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 +488,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 +533,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 +562,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 +585,14 @@ 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->cflags = config->flags;
+		if (config->request_type ==
+			GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+			line->output_value = req.default_values[i];
+		if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_AS_IS)
+			line->as_is = true;
 		line_set_fd(line, line_fd);
 		line_maybe_update(line);
 	}
@@ -590,6 +633,7 @@ static int line_request_event_single(struct gpiod_line *line,
 		return -1;
 
 	line->state = LINE_REQUESTED_EVENTS;
+	line->cflags = config->flags;
 	line_set_fd(line, line_fd);
 	line_maybe_update(line);
 
@@ -688,6 +732,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 +815,134 @@ 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;
+	bool as_is;
+
+	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;
+
+	as_is = line->as_is && direction == GPIOD_LINE_REQUEST_DIRECTION_AS_IS;
+	gpiod_line_bulk_foreach_line_off(bulk, line, i) {
+		line->cflags = flags;
+		if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
+			line->output_value = hcfg.default_values[i];
+		line->as_is = as_is;
+		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->as_is) {
+		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->cflags, 0);
+}
+
+int gpiod_line_set_direction_bulk_input(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->cflags, 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->cflags, value);
+}
+
+int gpiod_line_set_direction_bulk_output(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->cflags, values);
+}
+
 int gpiod_line_event_wait(struct gpiod_line *line,
 			  const struct timespec *timeout)
 {
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 12/19] tests: add tests for SET_CONFIG
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (10 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 13/19] core: allow gpiod_line_set_value_bulk to accept null values Kent Gibson
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Extend test coverage over the SET_CONFIG functions.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 tests/tests-line.c | 371 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 370 insertions(+), 1 deletion(-)

diff --git a/tests/tests-line.c b/tests/tests-line.c
index b4bef1a..e74f90f 100644
--- a/tests/tests-line.c
+++ b/tests/tests-line.c
@@ -267,6 +267,7 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
 
 	ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0);
 	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
 
 	ret = gpiod_line_set_value(line, 1);
 	g_assert_cmpint(ret, ==, 0);
@@ -276,6 +277,352 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
 	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
 }
 
+GPIOD_TEST_CASE(set_config_bulk_null_values, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER;
+	struct gpiod_line *line0, *line1, *line2;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line0 = gpiod_chip_get_line(chip, 0);
+	line1 = gpiod_chip_get_line(chip, 1);
+	line2 = gpiod_chip_get_line(chip, 2);
+
+	g_assert_nonnull(line0);
+	g_assert_nonnull(line1);
+	g_assert_nonnull(line2);
+	gpiod_test_return_if_failed();
+
+	gpiod_line_bulk_add(&bulk, line0);
+	gpiod_line_bulk_add(&bulk, line1);
+	gpiod_line_bulk_add(&bulk, line2);
+
+	ret = gpiod_line_request_bulk_output(&bulk, GPIOD_TEST_CONSUMER, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_active_state(line0), ==,
+			GPIOD_LINE_ACTIVE_STATE_HIGH);
+	g_assert_cmpint(gpiod_line_active_state(line1), ==,
+			GPIOD_LINE_ACTIVE_STATE_HIGH);
+	g_assert_cmpint(gpiod_line_active_state(line2), ==,
+			GPIOD_LINE_ACTIVE_STATE_HIGH);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_config_bulk(&bulk,
+			GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+			GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, NULL);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_active_state(line0), ==,
+			GPIOD_LINE_ACTIVE_STATE_LOW);
+	g_assert_cmpint(gpiod_line_active_state(line1), ==,
+			GPIOD_LINE_ACTIVE_STATE_LOW);
+	g_assert_cmpint(gpiod_line_active_state(line2), ==,
+			GPIOD_LINE_ACTIVE_STATE_LOW);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	ret = gpiod_line_set_config_bulk(&bulk,
+			GPIOD_LINE_REQUEST_DIRECTION_OUTPUT, 0, NULL);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_active_state(line0), ==,
+			GPIOD_LINE_ACTIVE_STATE_HIGH);
+	g_assert_cmpint(gpiod_line_active_state(line1), ==,
+			GPIOD_LINE_ACTIVE_STATE_HIGH);
+	g_assert_cmpint(gpiod_line_active_state(line2), ==,
+			GPIOD_LINE_ACTIVE_STATE_HIGH);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
+GPIOD_TEST_CASE(set_flags_active_state, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line *line;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 2);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_active_state(line), ==,
+			GPIOD_LINE_ACTIVE_STATE_HIGH);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	ret = gpiod_line_set_flags(line, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_active_state(line), ==,
+			GPIOD_LINE_ACTIVE_STATE_LOW);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_flags(line, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_active_state(line), ==,
+			GPIOD_LINE_ACTIVE_STATE_HIGH);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+}
+
+GPIOD_TEST_CASE(set_flags_bias, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line *line;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 2);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
+
+	ret = gpiod_line_set_flags(line,
+		GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_DISABLE);
+
+	ret = gpiod_line_set_flags(line,
+		GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	ret = gpiod_line_set_flags(line,
+		GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
+GPIOD_TEST_CASE(set_flags_drive, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line *line;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 2);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_is_open_drain(line), ==, false);
+	g_assert_cmpint(gpiod_line_is_open_source(line), ==, false);
+
+	ret = gpiod_line_set_flags(line,
+		GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_is_open_drain(line), ==, true);
+	g_assert_cmpint(gpiod_line_is_open_source(line), ==, false);
+
+	ret = gpiod_line_set_flags(line,
+		GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_is_open_drain(line), ==, false);
+	g_assert_cmpint(gpiod_line_is_open_source(line), ==, true);
+}
+
+GPIOD_TEST_CASE(set_direction, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line *line;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 2);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_direction(line), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_direction_input(line);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_direction(line), ==,
+			GPIOD_LINE_DIRECTION_INPUT);
+
+	ret = gpiod_line_set_direction_output(line, 1);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_direction(line), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+}
+
+GPIOD_TEST_CASE(set_direction_bulk, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER;
+	struct gpiod_line *line0, *line1, *line2;
+	int values[3];
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line0 = gpiod_chip_get_line(chip, 0);
+	line1 = gpiod_chip_get_line(chip, 1);
+	line2 = gpiod_chip_get_line(chip, 2);
+
+	g_assert_nonnull(line0);
+	g_assert_nonnull(line1);
+	g_assert_nonnull(line2);
+	gpiod_test_return_if_failed();
+
+	gpiod_line_bulk_add(&bulk, line0);
+	gpiod_line_bulk_add(&bulk, line1);
+	gpiod_line_bulk_add(&bulk, line2);
+
+	values[0] = 0;
+	values[1] = 1;
+	values[2] = 2;
+
+	ret = gpiod_line_request_bulk_output(&bulk,
+			GPIOD_TEST_CONSUMER, values);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_direction(line0), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_line_direction(line1), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_line_direction(line2), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	ret = gpiod_line_set_direction_bulk_input(&bulk);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_direction(line0), ==,
+			GPIOD_LINE_DIRECTION_INPUT);
+	g_assert_cmpint(gpiod_line_direction(line1), ==,
+			GPIOD_LINE_DIRECTION_INPUT);
+	g_assert_cmpint(gpiod_line_direction(line2), ==,
+			GPIOD_LINE_DIRECTION_INPUT);
+
+	values[0] = 2;
+	values[1] = 1;
+	values[2] = 0;
+
+	ret = gpiod_line_set_direction_bulk_output(&bulk, values);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_direction(line0), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_line_direction(line1), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_line_direction(line2), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_direction_bulk_output(&bulk, NULL);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_line_direction(line0), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_line_direction(line1), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_line_direction(line2), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
+GPIOD_TEST_CASE(output_value_caching, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line *line;
+	struct gpiod_line_bulk bulk;
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line = gpiod_chip_get_line(chip, 2);
+	g_assert_nonnull(line);
+	gpiod_test_return_if_failed();
+
+	// check cached by request...
+	ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	// ...by checking cached value applied by set_flags
+	ret = gpiod_line_set_flags(line, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	// check cached by set_value
+	ret = gpiod_line_set_value(line, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_flags(line, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_value(line, 1);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	ret = gpiod_line_set_flags(line, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	// check cached by set_config
+	ret = gpiod_line_set_config(line, GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
+				    0, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_flags(line, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	// check cached by set_value_bulk default
+	ret = gpiod_line_set_value(line, 1);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	gpiod_line_bulk_init(&bulk);
+	gpiod_line_bulk_add(&bulk, line);
+	ret = gpiod_line_set_value_bulk(&bulk, NULL);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_flags(line, 0);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
+
 GPIOD_TEST_CASE(get_value_different_chips, 0, { 8, 8 })
 {
 	g_autoptr(gpiod_chip_struct) chipA = NULL;
@@ -390,10 +737,11 @@ GPIOD_TEST_CASE(direction, 0, { 8 })
 	g_assert_nonnull(line);
 	gpiod_test_return_if_failed();
 
-	ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 0);
+	ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1);
 	g_assert_cmpint(ret, ==, 0);
 	g_assert_cmpint(gpiod_line_direction(line), ==,
 			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1);
 
 	gpiod_line_release(line);
 
@@ -431,6 +779,27 @@ GPIOD_TEST_CASE(active_state, 0, { 8 })
 
 	g_assert_cmpint(gpiod_line_direction(line), ==,
 			GPIOD_LINE_DIRECTION_INPUT);
+
+	gpiod_line_release(line);
+
+	ret = gpiod_line_request_output_flags(line, GPIOD_TEST_CONSUMER,
+			GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW, 0);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_cmpint(gpiod_line_direction(line), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1);
+
+	gpiod_line_release(line);
+
+	ret = gpiod_line_request_output_flags(line,
+			GPIOD_TEST_CONSUMER, 0, 0);
+	g_assert_cmpint(ret, ==, 0);
+
+	g_assert_cmpint(gpiod_line_direction(line), ==,
+			GPIOD_LINE_DIRECTION_OUTPUT);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 0);
+
 }
 
 GPIOD_TEST_CASE(misc_flags, 0, { 8 })
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 13/19] core: allow gpiod_line_set_value_bulk to accept null values
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (11 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 12/19] tests: add tests " Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 14/19] bindings: cxx: add support for SET_CONFIG Kent Gibson
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Change gpiod_line_set_value_bulk to interpret a NULL values pointer as an
array of zero, as per gpiod_line_request_bulk, gpiod_line_set_config_bulk,
and gpiod_line_set_direction_bulk_output.

The old behaviour was to segfault.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 lib/core.c         |  5 +++--
 tests/tests-line.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/lib/core.c b/lib/core.c
index c42cda5..2e54def 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -805,8 +805,9 @@ int gpiod_line_set_value_bulk(struct gpiod_line_bulk *bulk, const int *values)
 
 	memset(&data, 0, sizeof(data));
 
-	for (i = 0; i < gpiod_line_bulk_num_lines(bulk); i++)
-		data.values[i] = (uint8_t)!!values[i];
+	if (values)
+		for (i = 0; i < gpiod_line_bulk_num_lines(bulk); i++)
+			data.values[i] = (uint8_t)!!values[i];
 
 	line = gpiod_line_bulk_get_line(bulk, 0);
 	fd = line_get_fd(line);
diff --git a/tests/tests-line.c b/tests/tests-line.c
index e74f90f..7d45603 100644
--- a/tests/tests-line.c
+++ b/tests/tests-line.c
@@ -277,6 +277,59 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
 	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
 }
 
+GPIOD_TEST_CASE(set_value_bulk, 0, { 8 })
+{
+	g_autoptr(gpiod_chip_struct) chip = NULL;
+	struct gpiod_line_bulk bulk = GPIOD_LINE_BULK_INITIALIZER;
+	struct gpiod_line *line0, *line1, *line2;
+	int values[3];
+	gint ret;
+
+	chip = gpiod_chip_open(gpiod_test_chip_path(0));
+	g_assert_nonnull(chip);
+	gpiod_test_return_if_failed();
+
+	line0 = gpiod_chip_get_line(chip, 0);
+	line1 = gpiod_chip_get_line(chip, 1);
+	line2 = gpiod_chip_get_line(chip, 2);
+
+	g_assert_nonnull(line0);
+	g_assert_nonnull(line1);
+	g_assert_nonnull(line2);
+	gpiod_test_return_if_failed();
+
+	gpiod_line_bulk_add(&bulk, line0);
+	gpiod_line_bulk_add(&bulk, line1);
+	gpiod_line_bulk_add(&bulk, line2);
+
+	values[0] = 0;
+	values[1] = 1;
+	values[2] = 2;
+
+	ret = gpiod_line_request_bulk_output(&bulk,
+			GPIOD_TEST_CONSUMER, values);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 1);
+
+	values[0] = 2;
+	values[1] = 1;
+	values[2] = 0;
+
+	ret = gpiod_line_set_value_bulk(&bulk, values);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 1);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+
+	ret = gpiod_line_set_value_bulk(&bulk, NULL);
+	g_assert_cmpint(ret, ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0);
+	g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
+}
+
 GPIOD_TEST_CASE(set_config_bulk_null_values, 0, { 8 })
 {
 	g_autoptr(gpiod_chip_struct) chip = NULL;
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 14/19] bindings: cxx: add support for SET_CONFIG
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (12 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 13/19] core: allow gpiod_line_set_value_bulk to accept null values Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 15/19] bindings: cxx: tests: add tests for SET_CONFIG methods Kent Gibson
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Add methods to support setting line configuration.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/cxx/gpiod.hpp     | 55 +++++++++++++++++++++++++
 bindings/cxx/line.cpp      | 37 +++++++++++++++++
 bindings/cxx/line_bulk.cpp | 83 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 175 insertions(+)

diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp
index 2b1a6ab..dcae431 100644
--- a/bindings/cxx/gpiod.hpp
+++ b/bindings/cxx/gpiod.hpp
@@ -381,6 +381,32 @@ public:
 	 */
 	GPIOD_API void set_value(int val) const;
 
+	/**
+	 * @brief Set configuration of this line.
+	 * @param direction New direction.
+	 * @param flags Replacement flags.
+	 * @param value New value (0 or 1) - only matters for OUTPUT direction.
+	 */
+	GPIOD_API void set_config(int direction, ::std::bitset<32> flags,
+			int value = 0) const;
+
+	/**
+	 * @brief Set configuration flags of this line.
+	 * @param flags Replacement flags.
+	 */
+	GPIOD_API void set_flags(::std::bitset<32> flags) const;
+
+	/**
+	 * @brief Change the direction this line to input.
+	 */
+	GPIOD_API void set_direction_input() const;
+
+	/**
+	 * @brief Change the direction this lines to output.
+	 * @param value New value (0 or 1).
+	 */
+	GPIOD_API void set_direction_output(int value = 0) const;
+
 	/**
 	 * @brief Wait for an event on this line.
 	 * @param timeout Time to wait before returning if no event occurred.
@@ -648,6 +674,35 @@ public:
 	 */
 	GPIOD_API void set_values(const ::std::vector<int>& values) const;
 
+	/**
+	 * @brief Set configuration of all lines held by this object.
+	 * @param direction New direction.
+	 * @param flags Replacement flags.
+	 * @param values Vector of values to set. Must be the same size as the
+	 *        number of lines held by this line_bulk.
+	 * 	  Only relevant for output direction requests.
+	 */
+	GPIOD_API void set_config(int direction, ::std::bitset<32> flags,
+			const ::std::vector<int> values = std::vector<int>()) const;
+
+	/**
+	 * @brief Set configuration flags of all lines held by this object.
+	 * @param flags Replacement flags.
+	 */
+	GPIOD_API void set_flags(::std::bitset<32> flags) const;
+
+	/**
+	 * @brief Change the direction all lines held by this object to input.
+	 */
+	GPIOD_API void set_direction_input() const;
+
+	/**
+	 * @brief Change the direction all lines held by this object to output.
+	 * @param values Vector of values to set. Must be the same size as the
+	 *        number of lines held by this line_bulk.
+	 */
+	GPIOD_API void set_direction_output(const ::std::vector<int>& values) const;
+
 	/**
 	 * @brief Poll the set of lines for line events.
 	 * @param timeout Number of nanoseconds to wait before returning an
diff --git a/bindings/cxx/line.cpp b/bindings/cxx/line.cpp
index dd6bb6a..a688b5d 100644
--- a/bindings/cxx/line.cpp
+++ b/bindings/cxx/line.cpp
@@ -158,6 +158,43 @@ void line::set_value(int val) const
 	bulk.set_values({ val });
 }
 
+void line::set_config(int direction, ::std::bitset<32> flags,
+			int value) const
+{
+	this->throw_if_null();
+
+	line_bulk bulk({ *this });
+
+	bulk.set_config(direction, flags, { value });
+}
+
+void line::set_flags(::std::bitset<32> flags) const
+{
+	this->throw_if_null();
+
+	line_bulk bulk({ *this });
+
+	bulk.set_flags(flags);
+}
+
+void line::set_direction_input() const
+{
+	this->throw_if_null();
+
+	line_bulk bulk({ *this });
+
+	bulk.set_direction_input();
+}
+
+void line::set_direction_output(int value) const
+{
+	this->throw_if_null();
+
+	line_bulk bulk({ *this });
+
+	bulk.set_direction_output({ value });
+}
+
 bool line::event_wait(const ::std::chrono::nanoseconds& timeout) const
 {
 	this->throw_if_null();
diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp
index 5f1cac4..6f7d161 100644
--- a/bindings/cxx/line_bulk.cpp
+++ b/bindings/cxx/line_bulk.cpp
@@ -176,6 +176,89 @@ void line_bulk::set_values(const ::std::vector<int>& values) const
 					  "error setting GPIO line values");
 }
 
+void line_bulk::set_config(int direction, ::std::bitset<32> flags,
+			   const ::std::vector<int> values) const
+{
+	this->throw_if_empty();
+
+	if (!values.empty() && this->_m_bulk.size() != values.size())
+		throw ::std::invalid_argument("the number of default values must correspond with the number of lines");
+
+	::gpiod_line_bulk bulk;
+	int rv, gflags;
+
+	gflags = 0;
+
+	for (auto& it: reqflag_mapping) {
+		if ((it.first & flags).to_ulong())
+			gflags |= it.second;
+	}
+
+	this->to_line_bulk(::std::addressof(bulk));
+
+	rv = ::gpiod_line_set_config_bulk(::std::addressof(bulk), direction,
+					  gflags, values.data());
+	if (rv)
+		throw ::std::system_error(errno, ::std::system_category(),
+					  "error setting GPIO line config");
+}
+
+void line_bulk::set_flags(::std::bitset<32> flags) const
+{
+	this->throw_if_empty();
+
+	::gpiod_line_bulk bulk;
+	int rv, gflags;
+
+	this->to_line_bulk(::std::addressof(bulk));
+
+	gflags = 0;
+
+	for (auto& it: reqflag_mapping) {
+		if ((it.first & flags).to_ulong())
+			gflags |= it.second;
+	}
+
+	rv = ::gpiod_line_set_flags_bulk(::std::addressof(bulk), gflags);
+	if (rv)
+		throw ::std::system_error(errno, ::std::system_category(),
+					  "error setting GPIO line flags");
+}
+
+void line_bulk::set_direction_input() const
+{
+	this->throw_if_empty();
+
+	::gpiod_line_bulk bulk;
+	int rv;
+
+	this->to_line_bulk(::std::addressof(bulk));
+
+	rv = ::gpiod_line_set_direction_bulk_input(::std::addressof(bulk));
+	if (rv)
+		throw ::std::system_error(errno, ::std::system_category(),
+			"error setting GPIO line direction to input");
+}
+
+void line_bulk::set_direction_output(const ::std::vector<int>& values) const
+{
+	this->throw_if_empty();
+
+	if (values.size() != this->_m_bulk.size())
+		throw ::std::invalid_argument("the size of values array must correspond with the number of lines");
+
+	::gpiod_line_bulk bulk;
+	int rv;
+
+	this->to_line_bulk(::std::addressof(bulk));
+
+	rv = ::gpiod_line_set_direction_bulk_output(::std::addressof(bulk),
+						    values.data());
+	if (rv)
+		throw ::std::system_error(errno, ::std::system_category(),
+			"error setting GPIO line direction to output");
+}
+
 line_bulk line_bulk::event_wait(const ::std::chrono::nanoseconds& timeout) const
 {
 	this->throw_if_empty();
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 15/19] bindings: cxx: tests: add tests for SET_CONFIG methods
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (13 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 14/19] bindings: cxx: add support for SET_CONFIG Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 16/19] bindings: python: add support for SET_CONFIG Kent Gibson
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Extend test coverage over set_config, set_flags, set_direction_input, and
set_direction_output methods.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/cxx/tests/tests-line.cpp | 128 ++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/bindings/cxx/tests/tests-line.cpp b/bindings/cxx/tests/tests-line.cpp
index ef314b9..f5b829d 100644
--- a/bindings/cxx/tests/tests-line.cpp
+++ b/bindings/cxx/tests/tests-line.cpp
@@ -324,6 +324,134 @@ TEST_CASE("Line values can be set and read", "[line]")
 	}
 }
 
+TEST_CASE("Line can be reconfigured", "[line]")
+{
+	mockup::probe_guard mockup_chips({ 8 });
+	::gpiod::chip chip(mockup::instance().chip_name(0));
+	::gpiod::line_request config;
+
+	config.consumer = consumer.c_str();
+
+	SECTION("set config (single line, active-state)")
+	{
+		auto line = chip.get_line(3);
+		config.request_type = ::gpiod::line_request::DIRECTION_INPUT;
+		config.flags = 0;
+		line.request(config);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+
+		line.set_config(::gpiod::line_request::DIRECTION_OUTPUT,
+			::gpiod::line_request::FLAG_ACTIVE_LOW,1);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_LOW);
+		REQUIRE(mockup::instance().chip_get_value(0, 3) == 0);
+		line.set_value(0);
+		REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+
+		line.set_config(::gpiod::line_request::DIRECTION_OUTPUT, 0);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+		REQUIRE(mockup::instance().chip_get_value(0, 3) == 0);
+		line.set_value(1);
+		REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+	}
+
+	SECTION("set flags (single line, active-state)")
+	{
+		auto line = chip.get_line(3);
+		config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+		config.flags = 0;
+		line.request(config,1);
+		REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+
+		line.set_flags(::gpiod::line_request::FLAG_ACTIVE_LOW);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_LOW);
+		REQUIRE(mockup::instance().chip_get_value(0, 3) == 0);
+
+		line.set_flags(0);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.active_state() == ::gpiod::line::ACTIVE_HIGH);
+		REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+	}
+
+	SECTION("set flags (single line, drive)")
+	{
+		auto line = chip.get_line(3);
+		config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+		config.flags = 0;
+		line.request(config);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+
+		line.set_flags(::gpiod::line_request::FLAG_OPEN_DRAIN);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+
+		line.set_flags(::gpiod::line_request::FLAG_OPEN_SOURCE);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE(line.is_open_source());
+
+		line.set_flags(0);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+	}
+
+	SECTION("set flags (single line, bias)")
+	{
+		auto line = chip.get_line(3);
+		config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+		config.flags = 0;
+		line.request(config);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+
+		line.set_flags(::gpiod::line_request::FLAG_OPEN_DRAIN);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+
+		line.set_flags(::gpiod::line_request::FLAG_OPEN_SOURCE);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE(line.is_open_source());
+
+		line.set_flags(0);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE_FALSE(line.is_open_drain());
+		REQUIRE_FALSE(line.is_open_source());
+	}
+
+	SECTION("set direction input (single line)")
+	{
+		auto line = chip.get_line(3);
+		config.request_type = ::gpiod::line_request::DIRECTION_OUTPUT;
+		config.flags = 0;
+		line.request(config);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		line.set_direction_input();
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT);
+	}
+
+	SECTION("set direction output (single line)")
+	{
+		auto line = chip.get_line(3);
+		config.request_type = ::gpiod::line_request::DIRECTION_INPUT;
+		config.flags = 0;
+		line.request(config);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_INPUT);
+		line.set_direction_output(1);
+		REQUIRE(line.direction() == ::gpiod::line::DIRECTION_OUTPUT);
+		REQUIRE(mockup::instance().chip_get_value(0, 3) == 1);
+	}
+}
+
 TEST_CASE("Exported line can be released", "[line]")
 {
 	mockup::probe_guard mockup_chips({ 8 });
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 16/19] bindings: python: add support for SET_CONFIG
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (14 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 15/19] bindings: cxx: tests: add tests for SET_CONFIG methods Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 17/19] bindings: python: tests: add tests for SET_CONFIG methods Kent Gibson
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Add methods to support setting line configuration.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/python/gpiodmodule.c | 381 +++++++++++++++++++++++++++++++++-
 1 file changed, 379 insertions(+), 2 deletions(-)

diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c
index de8d6d1..4949b14 100644
--- a/bindings/python/gpiodmodule.c
+++ b/bindings/python/gpiodmodule.c
@@ -585,14 +585,149 @@ static PyObject *gpiod_Line_set_value(gpiod_LineObject *self, PyObject *args)
 	if (!bulk_obj)
 		return NULL;
 
-	vals = Py_BuildValue("((O))", val);
+	vals = Py_BuildValue("(O)", val);
 	if (!vals) {
 		Py_DECREF(bulk_obj);
 		return NULL;
 	}
 
 	ret = PyObject_CallMethod((PyObject *)bulk_obj,
-				  "set_values", "O", vals);
+				  "set_values", "(O)", vals);
+	Py_DECREF(bulk_obj);
+	Py_DECREF(vals);
+
+	return ret;
+}
+
+PyDoc_STRVAR(gpiod_Line_set_config_doc,
+"set_config(direction,flags,value) -> None\n"
+"\n"
+"Set the configuration of this GPIO line.\n"
+"\n"
+"  direction\n"
+"    New direction (integer)\n"
+"  flags\n"
+"    New flags (integer)\n"
+"  value\n"
+"    New value (integer)");
+
+static PyObject *gpiod_Line_set_config(gpiod_LineObject *self, PyObject *args)
+{
+	gpiod_LineBulkObject *bulk_obj;
+	PyObject *dirn, *flags, *val, *vals, *ret;
+	int rv;
+
+	val = NULL;
+	rv = PyArg_ParseTuple(args, "OO|O", &dirn, &flags, &val);
+	if (!rv)
+		return NULL;
+
+	bulk_obj = gpiod_LineToLineBulk(self);
+	if (!bulk_obj)
+		return NULL;
+
+	if (val) {
+		vals = Py_BuildValue("(O)", val);
+		if (!vals) {
+			Py_DECREF(bulk_obj);
+			return NULL;
+		}
+		ret = PyObject_CallMethod((PyObject *)bulk_obj,
+				"set_config", "OO(O)", dirn, flags, vals);
+		Py_DECREF(vals);
+	} else
+		ret = PyObject_CallMethod((PyObject *)bulk_obj,
+				"set_config", "OO", dirn, flags);
+
+	Py_DECREF(bulk_obj);
+
+	return ret;
+}
+
+PyDoc_STRVAR(gpiod_Line_set_flags_doc,
+"set_flags(flags) -> None\n"
+"\n"
+"Set the flags of this GPIO line.\n"
+"\n"
+"  flags\n"
+"    New flags (integer)");
+
+static PyObject *gpiod_Line_set_flags(gpiod_LineObject *self, PyObject *args)
+{
+	gpiod_LineBulkObject *bulk_obj;
+	PyObject *ret;
+
+	bulk_obj = gpiod_LineToLineBulk(self);
+	if (!bulk_obj)
+		return NULL;
+
+	ret = PyObject_CallMethod((PyObject *)bulk_obj,
+				  "set_flags", "O", args);
+	Py_DECREF(bulk_obj);
+
+	return ret;
+}
+
+PyDoc_STRVAR(gpiod_Line_set_direction_input_doc,
+"set_direction_input() -> None\n"
+"\n"
+"Set the direction of this GPIO line to input.\n");
+
+static PyObject *gpiod_Line_set_direction_input(gpiod_LineObject *self,
+						PyObject *Py_UNUSED(ignored))
+{
+	gpiod_LineBulkObject *bulk_obj;
+	PyObject *ret;
+
+	bulk_obj = gpiod_LineToLineBulk(self);
+	if (!bulk_obj)
+		return NULL;
+
+	ret = PyObject_CallMethod((PyObject *)bulk_obj,
+				  "set_direction_input", "");
+	Py_DECREF(bulk_obj);
+
+	return ret;
+}
+
+PyDoc_STRVAR(gpiod_Line_set_direction_output_doc,
+"set_direction_output(value) -> None\n"
+"\n"
+"Set the direction of this GPIO line to output.\n"
+"\n"
+"  value\n"
+"    New value (integer)");
+
+static PyObject *gpiod_Line_set_direction_output(gpiod_LineObject *self,
+						 PyObject *args)
+{
+	gpiod_LineBulkObject *bulk_obj;
+	PyObject *val, *vals, *ret;
+	int rv;
+	const char *fmt;
+
+	val = NULL;
+	rv = PyArg_ParseTuple(args, "|O", &val);
+	if (!rv)
+		return NULL;
+
+	if (val) {
+		fmt = "(O)";
+		vals = Py_BuildValue(fmt, val);
+	} else {
+		vals = Py_BuildValue("()");
+		fmt = "O"; // pass empty args to bulk
+	}
+	if (!vals)
+		return NULL;
+
+	bulk_obj = gpiod_LineToLineBulk(self);
+	if (!bulk_obj)
+		return NULL;
+
+	ret = PyObject_CallMethod((PyObject *)bulk_obj,
+				  "set_direction_output", fmt, vals);
+
 	Py_DECREF(bulk_obj);
 	Py_DECREF(vals);
 
@@ -838,6 +973,30 @@ static PyMethodDef gpiod_Line_methods[] = {
 		.ml_flags = METH_VARARGS,
 		.ml_doc = gpiod_Line_set_value_doc,
 	},
+	{
+		.ml_name = "set_config",
+		.ml_meth = (PyCFunction)gpiod_Line_set_config,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = gpiod_Line_set_config_doc,
+	},
+	{
+		.ml_name = "set_flags",
+		.ml_meth = (PyCFunction)gpiod_Line_set_flags,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = gpiod_Line_set_flags_doc,
+	},
+	{
+		.ml_name = "set_direction_input",
+		.ml_meth = (PyCFunction)gpiod_Line_set_direction_input,
+		.ml_flags = METH_NOARGS,
+		.ml_doc = gpiod_Line_set_direction_input_doc,
+	},
+	{
+		.ml_name = "set_direction_output",
+		.ml_meth = (PyCFunction)gpiod_Line_set_direction_output,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = gpiod_Line_set_direction_output_doc,
+	},
 	{
 		.ml_name = "release",
 		.ml_meth = (PyCFunction)gpiod_Line_release,
@@ -1283,6 +1442,200 @@ static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,
 	Py_RETURN_NONE;
 }
 
+static int convert_values(PyObject *src, int *dst, Py_ssize_t n)
+{
+	int val;
+	Py_ssize_t num_vals, i;
+	PyObject *iter, *next;
+
+	num_vals = PyObject_Size(src);
+	if (num_vals != n) {
+		PyErr_SetString(PyExc_TypeError,
+			"Number of values must correspond to the number of lines");
+		return -1;
+	}
+	iter = PyObject_GetIter(src);
+	if (!iter)
+		return -1;
+	for (i = 0;; i++) {
+		next = PyIter_Next(iter);
+		if (!next) {
+			Py_DECREF(iter);
+			break;
+		}
+		val = PyLong_AsLong(next);
+		Py_DECREF(next);
+		if (PyErr_Occurred()) {
+			Py_DECREF(iter);
+			return -1;
+		}
+		dst[i] = (int)val;
+	}
+	return 0;
+}
+
+PyDoc_STRVAR(gpiod_LineBulk_set_config_doc,
+"set_config(direction,flags,values) -> None\n"
+"\n"
+"Set the configuration of all the lines held by this LineBulk object.\n"
+"\n"
+"  direction\n"
+"    New direction (integer)\n"
+"  flags\n"
+"    New flags (integer)\n"
+"  values\n"
+"    List of values (integers) to set when direction is output.\n"
+"\n"
+"The number of values in the list passed as argument must be the same as\n"
+"the number of lines held by this gpiod.LineBulk object. The index of each\n"
+"value corresponds to the index of each line in the object.\n");
+
+static PyObject *gpiod_LineBulk_set_config(gpiod_LineBulkObject *self,
+					   PyObject *args)
+{
+	int rv, vals[GPIOD_LINE_BULK_MAX_LINES];
+	PyObject *val_list;
+	struct gpiod_line_bulk bulk;
+	const int *valp;
+	int dirn, flags;
+
+	if (gpiod_LineBulkOwnerIsClosed(self))
+		return NULL;
+
+	gpiod_LineBulkObjToCLineBulk(self, &bulk);
+
+	val_list = NULL;
+	rv = PyArg_ParseTuple(args, "ii|(O)", &dirn, &flags, &val_list);
+	if (!rv)
+		return NULL;
+
+	if (val_list == NULL)
+		valp = NULL;
+	else {
+		memset(vals, 0, sizeof(vals));
+		rv = convert_values(val_list, vals, self->num_lines);
+		if (rv)
+			return NULL;
+		valp = vals;
+	}
+
+	Py_BEGIN_ALLOW_THREADS;
+	rv = gpiod_line_set_config_bulk(&bulk, dirn, flags, valp);
+	Py_END_ALLOW_THREADS;
+	if (rv)
+		return PyErr_SetFromErrno(PyExc_OSError);
+
+	Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(gpiod_LineBulk_set_flags_doc,
+"set_flags(flags) -> None\n"
+"\n"
+"Set the flags of all the lines held by this LineBulk object.\n"
+"\n"
+"  flags\n"
+"    New flags (integer)");
+
+static PyObject *gpiod_LineBulk_set_flags(gpiod_LineBulkObject *self,
+					  PyObject *args)
+{
+	int rv;
+	struct gpiod_line_bulk bulk;
+	int flags;
+
+	if (gpiod_LineBulkOwnerIsClosed(self))
+		return NULL;
+
+	gpiod_LineBulkObjToCLineBulk(self, &bulk);
+
+	rv = PyArg_ParseTuple(args, "i", &flags);
+	if (!rv)
+		return NULL;
+
+	Py_BEGIN_ALLOW_THREADS;
+	rv = gpiod_line_set_flags_bulk(&bulk, flags);
+	Py_END_ALLOW_THREADS;
+	if (rv)
+		return PyErr_SetFromErrno(PyExc_OSError);
+
+	Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(gpiod_LineBulk_set_direction_input_doc,
+"set_direction_input() -> None\n"
+"\n"
+"Set the direction of all the lines held by this LineBulk object to input.\n");
+
+static PyObject *gpiod_LineBulk_set_direction_input(gpiod_LineBulkObject *self,
+						PyObject *Py_UNUSED(ignored))
+{
+	struct gpiod_line_bulk bulk;
+	int rv;
+
+	if (gpiod_LineBulkOwnerIsClosed(self))
+		return NULL;
+
+	gpiod_LineBulkObjToCLineBulk(self, &bulk);
+
+	Py_BEGIN_ALLOW_THREADS;
+	rv = gpiod_line_set_direction_bulk_input(&bulk);
+	Py_END_ALLOW_THREADS;
+	if (rv)
+		return PyErr_SetFromErrno(PyExc_OSError);
+
+	Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(gpiod_LineBulk_set_direction_output_doc,
+"set_direction_output(value) -> None\n"
+"\n"
+"Set the direction of all the lines held by this LineBulk object to output.\n"
+"\n"
+"  values\n"
+"    List of values (integers) to set when direction is output.\n"
+"\n"
+"The number of values in the list passed as argument must be the same as\n"
+"the number of lines held by this gpiod.LineBulk object. The index of each\n"
+"value corresponds to the index of each line in the object.\n");
+
+static PyObject *gpiod_LineBulk_set_direction_output(
+				gpiod_LineBulkObject *self,
+				PyObject *args)
+{
+	int rv, vals[GPIOD_LINE_BULK_MAX_LINES];
+	PyObject *val_list;
+	struct gpiod_line_bulk bulk;
+	const int *valp;
+
+	if (gpiod_LineBulkOwnerIsClosed(self))
+		return NULL;
+
+	gpiod_LineBulkObjToCLineBulk(self, &bulk);
+
+	val_list = NULL;
+	rv = PyArg_ParseTuple(args, "|O", &val_list);
+	if (!rv)
+		return NULL;
+
+	if (val_list == NULL)
+		valp = NULL;
+	else {
+		memset(vals, 0, sizeof(vals));
+		rv = convert_values(val_list, vals, self->num_lines);
+		if (rv)
+			return NULL;
+		valp = vals;
+	}
+
+	Py_BEGIN_ALLOW_THREADS;
+	rv = gpiod_line_set_direction_bulk_output(&bulk, valp);
+	Py_END_ALLOW_THREADS;
+	if (rv)
+		return PyErr_SetFromErrno(PyExc_OSError);
+
+	Py_RETURN_NONE;
+}
+
 PyDoc_STRVAR(gpiod_LineBulk_release_doc,
 "release() -> None\n"
 "\n"
@@ -1431,6 +1784,30 @@ static PyMethodDef gpiod_LineBulk_methods[] = {
 		.ml_doc = gpiod_LineBulk_set_values_doc,
 		.ml_flags = METH_VARARGS,
 	},
+	{
+		.ml_name = "set_config",
+		.ml_meth = (PyCFunction)gpiod_LineBulk_set_config,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = gpiod_LineBulk_set_config_doc,
+	},
+	{
+		.ml_name = "set_flags",
+		.ml_meth = (PyCFunction)gpiod_LineBulk_set_flags,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = gpiod_LineBulk_set_flags_doc,
+	},
+	{
+		.ml_name = "set_direction_input",
+		.ml_meth = (PyCFunction)gpiod_LineBulk_set_direction_input,
+		.ml_flags = METH_NOARGS,
+		.ml_doc = gpiod_LineBulk_set_direction_input_doc,
+	},
+	{
+		.ml_name = "set_direction_output",
+		.ml_meth = (PyCFunction)gpiod_LineBulk_set_direction_output,
+		.ml_flags = METH_VARARGS,
+		.ml_doc = gpiod_LineBulk_set_direction_output_doc,
+	},
 	{
 		.ml_name = "release",
 		.ml_meth = (PyCFunction)gpiod_LineBulk_release,
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 17/19] bindings: python: tests: add tests for SET_CONFIG methods
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (15 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 16/19] bindings: python: add support for SET_CONFIG Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 18/19] tools: add support for bias flags Kent Gibson
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Extend test coverage over set_config, set_flags, set_direction_input, and
set_direction_output methods.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/python/tests/gpiod_py_test.py | 163 +++++++++++++++++++++++++
 1 file changed, 163 insertions(+)

diff --git a/bindings/python/tests/gpiod_py_test.py b/bindings/python/tests/gpiod_py_test.py
index 9330b43..704d916 100755
--- a/bindings/python/tests/gpiod_py_test.py
+++ b/bindings/python/tests/gpiod_py_test.py
@@ -493,6 +493,169 @@ class LineValues(MockupTestCase):
             line.set_value(0)
             self.assertEqual(mockup.chip_get_value(0, 3), 1)
 
+class LineConfig(MockupTestCase):
+
+    chip_sizes = ( 8, )
+
+    def test_set_config_direction(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(3)
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_IN)
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
+            line.set_config(gpiod.LINE_REQ_DIR_IN, 0, 0)
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
+            line.set_config(gpiod.LINE_REQ_DIR_OUT,0,0)
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+
+    def test_set_config_flags(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(3)
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT)
+            line.set_config(gpiod.LINE_REQ_DIR_OUT,
+                            gpiod.LINE_REQ_FLAG_ACTIVE_LOW, 0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            line.set_config(gpiod.LINE_REQ_DIR_OUT, 0, 0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+    def test_set_config_output_value(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(3)
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_IN)
+            line.set_config(gpiod.LINE_REQ_DIR_OUT,0,1)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            line.set_config(gpiod.LINE_REQ_DIR_OUT,0,0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+    def test_set_config_output_no_value(self):
+         with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(3)
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT,
+                         default_val=1)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            line.set_config(gpiod.LINE_REQ_DIR_OUT,0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+    def test_set_config_bulk_output_no_values(self):
+         with gpiod.Chip(mockup.chip_name(0)) as chip:
+            lines = chip.get_lines(( 0, 3, 4, 6 ))
+            lines.request(consumer=default_consumer,
+                          type=gpiod.LINE_REQ_DIR_OUT,
+                          default_vals=(1,1,1,1))
+            self.assertEqual(mockup.chip_get_value(0, 0), 1)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            self.assertEqual(mockup.chip_get_value(0, 4), 1)
+            self.assertEqual(mockup.chip_get_value(0, 6), 1)
+            lines.set_config(gpiod.LINE_REQ_DIR_OUT,0)
+            self.assertEqual(mockup.chip_get_value(0, 0), 0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+            self.assertEqual(mockup.chip_get_value(0, 4), 0)
+            self.assertEqual(mockup.chip_get_value(0, 6), 0)
+
+class LineFlags(MockupTestCase):
+
+    chip_sizes = ( 8, )
+
+    def test_set_flags(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(3)
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT,
+                         default_val=1)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            line.set_flags(gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+            line.set_flags(0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+
+    def test_set_flags_bulk(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            lines = chip.get_lines(( 0, 3, 4, 6 ))
+            lines.request(consumer=default_consumer,
+                          type=gpiod.LINE_REQ_DIR_OUT,
+                          default_vals=(1,1,1,1))
+            self.assertEqual(mockup.chip_get_value(0, 0), 1)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            self.assertEqual(mockup.chip_get_value(0, 4), 1)
+            self.assertEqual(mockup.chip_get_value(0, 6), 1)
+            lines.set_flags(gpiod.LINE_REQ_FLAG_ACTIVE_LOW)
+            self.assertEqual(mockup.chip_get_value(0, 0), 0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+            self.assertEqual(mockup.chip_get_value(0, 4), 0)
+            self.assertEqual(mockup.chip_get_value(0, 6), 0)
+            lines.set_flags(0)
+            self.assertEqual(mockup.chip_get_value(0, 0), 1)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            self.assertEqual(mockup.chip_get_value(0, 4), 1)
+            self.assertEqual(mockup.chip_get_value(0, 6), 1)
+
+class LineDirection(MockupTestCase):
+
+    chip_sizes = ( 8, )
+
+    def test_set_direction(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            line = chip.get_line(3)
+            line.request(consumer=default_consumer,
+                         type=gpiod.LINE_REQ_DIR_OUT)
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            line.set_direction_input()
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_INPUT)
+            line.set_direction_output(0)
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+            line.set_direction_output(1)
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            line.set_direction_output()
+            self.assertEqual(line.direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+
+    def test_set_direction_bulk(self):
+        with gpiod.Chip(mockup.chip_name(0)) as chip:
+            lines = chip.get_lines(( 0, 3, 4, 6 ))
+            lines.request(consumer=default_consumer,
+                          type=gpiod.LINE_REQ_DIR_OUT)
+            self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            lines.set_direction_input()
+            self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_INPUT)
+            self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_INPUT)
+            self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_INPUT)
+            self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_INPUT)
+            lines.set_direction_output((0,0,1,0))
+            self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(mockup.chip_get_value(0, 0), 0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+            self.assertEqual(mockup.chip_get_value(0, 4), 1)
+            self.assertEqual(mockup.chip_get_value(0, 6), 0)
+            lines.set_direction_output((1,1,1,0))
+            self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(mockup.chip_get_value(0, 0), 1)
+            self.assertEqual(mockup.chip_get_value(0, 3), 1)
+            self.assertEqual(mockup.chip_get_value(0, 4), 1)
+            self.assertEqual(mockup.chip_get_value(0, 6), 0)
+            lines.set_direction_output()
+            self.assertEqual(lines.to_list()[0].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[1].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[2].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(lines.to_list()[3].direction(), gpiod.Line.DIRECTION_OUTPUT)
+            self.assertEqual(mockup.chip_get_value(0, 0), 0)
+            self.assertEqual(mockup.chip_get_value(0, 3), 0)
+            self.assertEqual(mockup.chip_get_value(0, 4), 0)
+            self.assertEqual(mockup.chip_get_value(0, 6), 0)
+
 class LineRequestBehavior(MockupTestCase):
 
     chip_sizes = ( 8, )
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 18/19] tools: add support for bias flags
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (16 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 17/19] bindings: python: tests: add tests for SET_CONFIG methods Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-16 15:40   ` Kent Gibson
  2019-11-15 14:43 ` [libgpiod] [PATCH 19/19] treewide: change "correspond with" to "correspond to" Kent Gibson
  2019-11-18 13:50 ` [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Bartosz Golaszewski
  19 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Add support for bias flags to applicable tools - gpioget, gpioset, and
gpiomon.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 tools/gpioget.c | 24 ++++++++++++++++++++----
 tools/gpiomon.c | 28 ++++++++++++++++++++++------
 tools/gpioset.c | 26 +++++++++++++++++++++-----
 3 files changed, 63 insertions(+), 15 deletions(-)

diff --git a/tools/gpioget.c b/tools/gpioget.c
index 196ebeb..025811a 100644
--- a/tools/gpioget.c
+++ b/tools/gpioget.c
@@ -17,10 +17,13 @@ static const struct option longopts[] = {
 	{ "help",	no_argument,	NULL,	'h' },
 	{ "version",	no_argument,	NULL,	'v' },
 	{ "active-low",	no_argument,	NULL,	'l' },
+	{ "pull-down",	no_argument,	NULL,	'D' },
+	{ "pull-up",	no_argument,	NULL,	'U' },
+	{ "bias-disable", no_argument,	NULL,	'B' },
 	{ GETOPT_NULL_LONGOPT },
 };
 
-static const char *const shortopts = "+hvl";
+static const char *const shortopts = "+hvlDUB";
 
 static void print_help(void)
 {
@@ -32,6 +35,9 @@ static void print_help(void)
 	printf("  -h, --help:\t\tdisplay this message and exit\n");
 	printf("  -v, --version:\tdisplay the version and exit\n");
 	printf("  -l, --active-low:\tset the line active state to low\n");
+	printf("  -D, --pull-down:\tenable internal pull-down\n");
+	printf("  -U, --pull-up:\tenable internal pull-up\n");
+	printf("  -B, --bias-disable:\tdisable internal bias\n");
 }
 
 int main(int argc, char **argv)
@@ -39,6 +45,7 @@ int main(int argc, char **argv)
 	unsigned int *offsets, i, num_lines;
 	int *values, optc, opti, rv;
 	bool active_low = false;
+	int flags = 0;
 	char *device, *end;
 
 	for (;;) {
@@ -56,6 +63,15 @@ int main(int argc, char **argv)
 		case 'l':
 			active_low = true;
 			break;
+		case 'D':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
+			break;
+		case 'U':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
+			break;
+		case 'B':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
+			break;
 		case '?':
 			die("try %s --help", get_progname());
 		default:
@@ -86,9 +102,9 @@ int main(int argc, char **argv)
 			die("invalid GPIO offset: %s", argv[i + 1]);
 	}
 
-	rv = gpiod_ctxless_get_value_multiple(device, offsets, values,
-					      num_lines, active_low,
-					      "gpioget");
+	rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
+						  num_lines, active_low, flags,
+						  "gpioget");
 	if (rv < 0)
 		die_perror("error reading GPIO values");
 
diff --git a/tools/gpiomon.c b/tools/gpiomon.c
index 9a1843b..5779718 100644
--- a/tools/gpiomon.c
+++ b/tools/gpiomon.c
@@ -26,12 +26,15 @@ static const struct option longopts[] = {
 	{ "silent",		no_argument,		NULL,	's' },
 	{ "rising-edge",	no_argument,		NULL,	'r' },
 	{ "falling-edge",	no_argument,		NULL,	'f' },
+	{ "pull-down",		no_argument,		NULL,	'D' },
+	{ "pull-up",		no_argument,		NULL,	'U' },
+	{ "bias-disable",	no_argument,		NULL,	'B' },
 	{ "line-buffered",	no_argument,		NULL,	'b' },
 	{ "format",		required_argument,	NULL,	'F' },
 	{ GETOPT_NULL_LONGOPT },
 };
 
-static const char *const shortopts = "+hvln:srfbF:";
+static const char *const shortopts = "+hvln:srfDUBbF:";
 
 static void print_help(void)
 {
@@ -47,6 +50,9 @@ static void print_help(void)
 	printf("  -s, --silent:\t\tdon't print event info\n");
 	printf("  -r, --rising-edge:\tonly process rising edge events\n");
 	printf("  -f, --falling-edge:\tonly process falling edge events\n");
+	printf("  -D, --pull-down:\tenable internal pull-down\n");
+	printf("  -U, --pull-up:\tenable internal pull-up\n");
+	printf("  -B, --bias-disable:\tdisable internal bias\n");
 	printf("  -b, --line-buffered:\tset standard output as line buffered\n");
 	printf("  -F, --format=FMT\tspecify custom output format\n");
 	printf("\n");
@@ -244,6 +250,7 @@ int main(int argc, char **argv)
 {
 	unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES], num_lines = 0, offset;
 	bool active_low = false, watch_rising = false, watch_falling = false;
+	int flags = 0;
 	struct timespec timeout = { 10, 0 };
 	int optc, opti, rv, i, event_type;
 	struct mon_ctx ctx;
@@ -266,6 +273,15 @@ int main(int argc, char **argv)
 		case 'l':
 			active_low = true;
 			break;
+		case 'D':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
+			break;
+		case 'U':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
+			break;
+		case 'B':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
+			break;
 		case 'n':
 			ctx.events_wanted = strtoul(optarg, &end, 10);
 			if (*end != '\0')
@@ -320,11 +336,11 @@ int main(int argc, char **argv)
 
 	ctx.sigfd = make_signalfd();
 
-	rv = gpiod_ctxless_event_monitor_multiple(argv[0], event_type,
-						  offsets, num_lines,
-						  active_low, "gpiomon",
-						  &timeout, poll_callback,
-						  event_callback, &ctx);
+	rv = gpiod_ctxless_event_monitor_multiple_ext(
+				argv[0], event_type, offsets,
+				num_lines, active_low, flags, "gpiomon",
+				&timeout, poll_callback,
+				event_callback, &ctx);
 	if (rv)
 		die_perror("error waiting for events");
 
diff --git a/tools/gpioset.c b/tools/gpioset.c
index d9977a7..8855eb0 100644
--- a/tools/gpioset.c
+++ b/tools/gpioset.c
@@ -27,10 +27,13 @@ static const struct option longopts[] = {
 	{ "sec",		required_argument,	NULL,	's' },
 	{ "usec",		required_argument,	NULL,	'u' },
 	{ "background",		no_argument,		NULL,	'b' },
+	{ "pull-down",		no_argument,		NULL,	'D' },
+	{ "pull-up",		no_argument,		NULL,	'U' },
+	{ "bias-disable",	no_argument,		NULL,	'B' },
 	{ GETOPT_NULL_LONGOPT },
 };
 
-static const char *const shortopts = "+hvlm:s:u:b";
+static const char *const shortopts = "+hvlm:s:u:bDUB";
 
 static void print_help(void)
 {
@@ -42,6 +45,9 @@ static void print_help(void)
 	printf("  -h, --help:\t\tdisplay this message and exit\n");
 	printf("  -v, --version:\tdisplay the version and exit\n");
 	printf("  -l, --active-low:\tset the line active state to low\n");
+	printf("  -D, --pull-down:\tenable internal pull-down\n");
+	printf("  -U, --pull-up:\tenable internal pull-up\n");
+	printf("  -B, --bias-disable:\tdisable internal bias\n");
 	printf("  -m, --mode=[exit|wait|time|signal] (defaults to 'exit'):\n");
 	printf("		tell the program what to do after setting values\n");
 	printf("  -s, --sec=SEC:\tspecify the number of seconds to wait (only valid for --mode=time)\n");
@@ -182,7 +188,7 @@ int main(int argc, char **argv)
 {
 	const struct mode_mapping *mode = &modes[MODE_EXIT];
 	unsigned int *offsets, num_lines, i;
-	int *values, rv, optc, opti;
+	int *values, rv, optc, opti, flags = 0;
 	struct callback_data cbdata;
 	bool active_low = false;
 	char *device, *end;
@@ -204,6 +210,15 @@ int main(int argc, char **argv)
 		case 'l':
 			active_low = true;
 			break;
+		case 'D':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
+			break;
+		case 'U':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
+			break;
+		case 'B':
+			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
+			break;
 		case 'm':
 			mode = parse_mode(optarg);
 			if (!mode)
@@ -268,9 +283,10 @@ int main(int argc, char **argv)
 			die("invalid offset: %s", argv[i + 1]);
 	}
 
-	rv = gpiod_ctxless_set_value_multiple(device, offsets, values,
-					      num_lines, active_low, "gpioset",
-					      mode->callback, &cbdata);
+	rv = gpiod_ctxless_set_value_multiple_ext(
+				device, offsets, values,
+				num_lines, active_low, flags, "gpioset",
+				mode->callback, &cbdata);
 	if (rv < 0)
 		die_perror("error setting the GPIO line values");
 
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [libgpiod] [PATCH 19/19] treewide: change "correspond with" to "correspond to"
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (17 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 18/19] tools: add support for bias flags Kent Gibson
@ 2019-11-15 14:43 ` Kent Gibson
  2019-11-18 13:52   ` Bartosz Golaszewski
  2019-11-18 13:50 ` [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Bartosz Golaszewski
  19 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-15 14:43 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski; +Cc: Kent Gibson

Trivial grammar fix. "correspond with" can mean either being in agreement
with, happening at the same time, or communication between parties.
"correspond to" is used to mean equivalance, which is the intended use
throughout the documentation.

Signed-off-by: Kent Gibson <warthog618@gmail.com>
---
 bindings/python/gpiodmodule.c | 6 +++---
 include/gpiod.h               | 2 +-
 lib/core.c                    | 2 +-
 tests/mockup/gpio-mockup.c    | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c
index 4949b14..74fbea3 100644
--- a/bindings/python/gpiodmodule.c
+++ b/bindings/python/gpiodmodule.c
@@ -1330,7 +1330,7 @@ PyDoc_STRVAR(gpiod_LineBulk_get_values_doc,
 "get_values() -> list of integers\n"
 "\n"
 "Read the values of all the lines held by this LineBulk object. The index\n"
-"of each value in the returned list corresponds with the index of the line\n"
+"of each value in the returned list corresponds to the index of the line\n"
 "in this gpiod.LineBulk object.");
 
 static PyObject *gpiod_LineBulk_get_values(gpiod_LineBulkObject *self,
@@ -1385,7 +1385,7 @@ PyDoc_STRVAR(gpiod_LineBulk_set_values_doc,
 "\n"
 "The number of values in the list passed as argument must be the same as\n"
 "the number of lines held by this gpiod.LineBulk object. The index of each\n"
-"value corresponds with the index of each line in the object.\n");
+"value corresponds to the index of each line in the object.\n");
 
 static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,
 					   PyObject *args)
@@ -1408,7 +1408,7 @@ static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,
 	num_vals = PyObject_Size(val_list);
 	if (self->num_lines != num_vals) {
 		PyErr_SetString(PyExc_TypeError,
-				"Number of values must correspond with the number of lines");
+				"Number of values must correspond to the number of lines");
 		return NULL;
 	}
 
diff --git a/include/gpiod.h b/include/gpiod.h
index 4053fd2..6776852 100644
--- a/include/gpiod.h
+++ b/include/gpiod.h
@@ -779,7 +779,7 @@ gpiod_line_bulk_num_lines(struct gpiod_line_bulk *bulk)
  *
  * This is a variant of ::gpiod_line_bulk_foreach_line which uses an integer
  * variable (either signed or unsigned) to store the loop state. This offset
- * variable is guaranteed to correspond with the offset of the current line in
+ * variable is guaranteed to correspond to the offset of the current line in
  * the bulk->lines array.
  */
 #define gpiod_line_bulk_foreach_line_off(bulk, line, offset)		\
diff --git a/lib/core.c b/lib/core.c
index 2e54def..54ae09c 100644
--- a/lib/core.c
+++ b/lib/core.c
@@ -111,7 +111,7 @@ static bool is_gpiochip_cdev(const char *path)
 
 	/*
 	 * Make sure the major and minor numbers of the character device
-	 * correspond with the ones in the dev attribute in sysfs.
+	 * correspond to the ones in the dev attribute in sysfs.
 	 */
 	snprintf(devstr, sizeof(devstr), "%u:%u",
 		 major(statbuf.st_rdev), minor(statbuf.st_rdev));
diff --git a/tests/mockup/gpio-mockup.c b/tests/mockup/gpio-mockup.c
index e3a53da..fa27bd7 100644
--- a/tests/mockup/gpio-mockup.c
+++ b/tests/mockup/gpio-mockup.c
@@ -333,7 +333,7 @@ EXPORT int gpio_mockup_probe(struct gpio_mockup *ctx, unsigned int num_chips,
 	/*
 	 * We can't assume that the order in which the mockup gpiochip
 	 * devices are created will be deterministic, yet we want the
-	 * index passed to the test_chip_*() functions to correspond with the
+	 * index passed to the test_chip_*() functions to correspond to the
 	 * order in which the chips were defined in the TEST_DEFINE()
 	 * macro.
 	 *
-- 
2.24.0


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 18/19] tools: add support for bias flags
  2019-11-15 14:43 ` [libgpiod] [PATCH 18/19] tools: add support for bias flags Kent Gibson
@ 2019-11-16 15:40   ` Kent Gibson
  2019-11-17 12:18     ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-16 15:40 UTC (permalink / raw)
  To: linux-gpio, bgolaszewski

On Fri, Nov 15, 2019 at 10:43:54PM +0800, Kent Gibson wrote:
> Add support for bias flags to applicable tools - gpioget, gpioset, and
> gpiomon.
> 
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
>  tools/gpioget.c | 24 ++++++++++++++++++++----
>  tools/gpiomon.c | 28 ++++++++++++++++++++++------
>  tools/gpioset.c | 26 +++++++++++++++++++++-----
>  3 files changed, 63 insertions(+), 15 deletions(-)
> 
> diff --git a/tools/gpioget.c b/tools/gpioget.c
> index 196ebeb..025811a 100644
> --- a/tools/gpioget.c
> +++ b/tools/gpioget.c
> @@ -17,10 +17,13 @@ static const struct option longopts[] = {
>  	{ "help",	no_argument,	NULL,	'h' },
>  	{ "version",	no_argument,	NULL,	'v' },
>  	{ "active-low",	no_argument,	NULL,	'l' },
> +	{ "pull-down",	no_argument,	NULL,	'D' },
> +	{ "pull-up",	no_argument,	NULL,	'U' },
> +	{ "bias-disable", no_argument,	NULL,	'B' },
>  	{ GETOPT_NULL_LONGOPT },
>  };
>  
> -static const char *const shortopts = "+hvl";
> +static const char *const shortopts = "+hvlDUB";
>  
>  static void print_help(void)
>  {
> @@ -32,6 +35,9 @@ static void print_help(void)
>  	printf("  -h, --help:\t\tdisplay this message and exit\n");
>  	printf("  -v, --version:\tdisplay the version and exit\n");
>  	printf("  -l, --active-low:\tset the line active state to low\n");
> +	printf("  -D, --pull-down:\tenable internal pull-down\n");
> +	printf("  -U, --pull-up:\tenable internal pull-up\n");
> +	printf("  -B, --bias-disable:\tdisable internal bias\n");
>  }
>  
>  int main(int argc, char **argv)
> @@ -39,6 +45,7 @@ int main(int argc, char **argv)
>  	unsigned int *offsets, i, num_lines;
>  	int *values, optc, opti, rv;
>  	bool active_low = false;
> +	int flags = 0;
>  	char *device, *end;
>  
>  	for (;;) {
> @@ -56,6 +63,15 @@ int main(int argc, char **argv)
>  		case 'l':
>  			active_low = true;
>  			break;
> +		case 'D':
> +			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
> +			break;
> +		case 'U':
> +			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
> +			break;
> +		case 'B':
> +			flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
> +			break;
>  		case '?':
>  			die("try %s --help", get_progname());
>  		default:
> @@ -86,9 +102,9 @@ int main(int argc, char **argv)
>  			die("invalid GPIO offset: %s", argv[i + 1]);
>  	}
>  

Nuts - this is wrong - it should be using the CTXLESS flags, not the 
LINE_REQUEST flags.  That applies to all three of the tools changed.
I forgot to propagate the last minute CTXLESS changes to the tools.
And unfortunately we don't have test cases for the tools :-(.
I've got a fix in my github branch that I will incorporate into v2.

I'm also wondering if it would be preferable to replace the individual
bias command line flags with a single bias parameter, e.g. --bias=pull-up
I've coded that in my github branch as well, if you would care to
compare.

Let me know if you'd like a v2, otherwise I'll hold off for a few days
in case something else crops up.

Cheers,
Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 18/19] tools: add support for bias flags
  2019-11-16 15:40   ` Kent Gibson
@ 2019-11-17 12:18     ` Bartosz Golaszewski
  2019-11-17 12:28       ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-17 12:18 UTC (permalink / raw)
  To: Kent Gibson; +Cc: linux-gpio

sob., 16 lis 2019 o 16:40 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Fri, Nov 15, 2019 at 10:43:54PM +0800, Kent Gibson wrote:
> > Add support for bias flags to applicable tools - gpioget, gpioset, and
> > gpiomon.
> >
> > Signed-off-by: Kent Gibson <warthog618@gmail.com>
> > ---
> >  tools/gpioget.c | 24 ++++++++++++++++++++----
> >  tools/gpiomon.c | 28 ++++++++++++++++++++++------
> >  tools/gpioset.c | 26 +++++++++++++++++++++-----
> >  3 files changed, 63 insertions(+), 15 deletions(-)
> >
> > diff --git a/tools/gpioget.c b/tools/gpioget.c
> > index 196ebeb..025811a 100644
> > --- a/tools/gpioget.c
> > +++ b/tools/gpioget.c
> > @@ -17,10 +17,13 @@ static const struct option longopts[] = {
> >       { "help",       no_argument,    NULL,   'h' },
> >       { "version",    no_argument,    NULL,   'v' },
> >       { "active-low", no_argument,    NULL,   'l' },
> > +     { "pull-down",  no_argument,    NULL,   'D' },
> > +     { "pull-up",    no_argument,    NULL,   'U' },
> > +     { "bias-disable", no_argument,  NULL,   'B' },
> >       { GETOPT_NULL_LONGOPT },
> >  };
> >
> > -static const char *const shortopts = "+hvl";
> > +static const char *const shortopts = "+hvlDUB";
> >
> >  static void print_help(void)
> >  {
> > @@ -32,6 +35,9 @@ static void print_help(void)
> >       printf("  -h, --help:\t\tdisplay this message and exit\n");
> >       printf("  -v, --version:\tdisplay the version and exit\n");
> >       printf("  -l, --active-low:\tset the line active state to low\n");
> > +     printf("  -D, --pull-down:\tenable internal pull-down\n");
> > +     printf("  -U, --pull-up:\tenable internal pull-up\n");
> > +     printf("  -B, --bias-disable:\tdisable internal bias\n");
> >  }
> >
> >  int main(int argc, char **argv)
> > @@ -39,6 +45,7 @@ int main(int argc, char **argv)
> >       unsigned int *offsets, i, num_lines;
> >       int *values, optc, opti, rv;
> >       bool active_low = false;
> > +     int flags = 0;
> >       char *device, *end;
> >
> >       for (;;) {
> > @@ -56,6 +63,15 @@ int main(int argc, char **argv)
> >               case 'l':
> >                       active_low = true;
> >                       break;
> > +             case 'D':
> > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
> > +                     break;
> > +             case 'U':
> > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
> > +                     break;
> > +             case 'B':
> > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
> > +                     break;
> >               case '?':
> >                       die("try %s --help", get_progname());
> >               default:
> > @@ -86,9 +102,9 @@ int main(int argc, char **argv)
> >                       die("invalid GPIO offset: %s", argv[i + 1]);
> >       }
> >
>
> Nuts - this is wrong - it should be using the CTXLESS flags, not the
> LINE_REQUEST flags.  That applies to all three of the tools changed.
> I forgot to propagate the last minute CTXLESS changes to the tools.
> And unfortunately we don't have test cases for the tools :-(.

But we do![1]

> I've got a fix in my github branch that I will incorporate into v2.
>
> I'm also wondering if it would be preferable to replace the individual
> bias command line flags with a single bias parameter, e.g. --bias=pull-up
> I've coded that in my github branch as well, if you would care to
> compare.
>
> Let me know if you'd like a v2, otherwise I'll hold off for a few days
> in case something else crops up.

Let me review the rest before that, I'll do this tomorrow.

Bart

>
> Cheers,
> Kent.

[1] https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/tools/gpio-tools-test.bats

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 18/19] tools: add support for bias flags
  2019-11-17 12:18     ` Bartosz Golaszewski
@ 2019-11-17 12:28       ` Kent Gibson
  2019-11-17 13:12         ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-17 12:28 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Sun, Nov 17, 2019 at 01:18:26PM +0100, Bartosz Golaszewski wrote:
> sob., 16 lis 2019 o 16:40 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Fri, Nov 15, 2019 at 10:43:54PM +0800, Kent Gibson wrote:
> > > Add support for bias flags to applicable tools - gpioget, gpioset, and
> > > gpiomon.
> > >
> > > Signed-off-by: Kent Gibson <warthog618@gmail.com>
> > > ---
> > >  tools/gpioget.c | 24 ++++++++++++++++++++----
> > >  tools/gpiomon.c | 28 ++++++++++++++++++++++------
> > >  tools/gpioset.c | 26 +++++++++++++++++++++-----
> > >  3 files changed, 63 insertions(+), 15 deletions(-)
> > >
> > > diff --git a/tools/gpioget.c b/tools/gpioget.c
> > > index 196ebeb..025811a 100644
> > > --- a/tools/gpioget.c
> > > +++ b/tools/gpioget.c
> > > @@ -17,10 +17,13 @@ static const struct option longopts[] = {
> > >       { "help",       no_argument,    NULL,   'h' },
> > >       { "version",    no_argument,    NULL,   'v' },
> > >       { "active-low", no_argument,    NULL,   'l' },
> > > +     { "pull-down",  no_argument,    NULL,   'D' },
> > > +     { "pull-up",    no_argument,    NULL,   'U' },
> > > +     { "bias-disable", no_argument,  NULL,   'B' },
> > >       { GETOPT_NULL_LONGOPT },
> > >  };
> > >
> > > -static const char *const shortopts = "+hvl";
> > > +static const char *const shortopts = "+hvlDUB";
> > >
> > >  static void print_help(void)
> > >  {
> > > @@ -32,6 +35,9 @@ static void print_help(void)
> > >       printf("  -h, --help:\t\tdisplay this message and exit\n");
> > >       printf("  -v, --version:\tdisplay the version and exit\n");
> > >       printf("  -l, --active-low:\tset the line active state to low\n");
> > > +     printf("  -D, --pull-down:\tenable internal pull-down\n");
> > > +     printf("  -U, --pull-up:\tenable internal pull-up\n");
> > > +     printf("  -B, --bias-disable:\tdisable internal bias\n");
> > >  }
> > >
> > >  int main(int argc, char **argv)
> > > @@ -39,6 +45,7 @@ int main(int argc, char **argv)
> > >       unsigned int *offsets, i, num_lines;
> > >       int *values, optc, opti, rv;
> > >       bool active_low = false;
> > > +     int flags = 0;
> > >       char *device, *end;
> > >
> > >       for (;;) {
> > > @@ -56,6 +63,15 @@ int main(int argc, char **argv)
> > >               case 'l':
> > >                       active_low = true;
> > >                       break;
> > > +             case 'D':
> > > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
> > > +                     break;
> > > +             case 'U':
> > > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
> > > +                     break;
> > > +             case 'B':
> > > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
> > > +                     break;
> > >               case '?':
> > >                       die("try %s --help", get_progname());
> > >               default:
> > > @@ -86,9 +102,9 @@ int main(int argc, char **argv)
> > >                       die("invalid GPIO offset: %s", argv[i + 1]);
> > >       }
> > >
> >
> > Nuts - this is wrong - it should be using the CTXLESS flags, not the
> > LINE_REQUEST flags.  That applies to all three of the tools changed.
> > I forgot to propagate the last minute CTXLESS changes to the tools.
> > And unfortunately we don't have test cases for the tools :-(.
> 
> But we do![1]
> 

Damn - I missed that.  I'll see about adding some cases for the bias
flags for v2.

Kent.

> > I've got a fix in my github branch that I will incorporate into v2.
> >
> > I'm also wondering if it would be preferable to replace the individual
> > bias command line flags with a single bias parameter, e.g. --bias=pull-up
> > I've coded that in my github branch as well, if you would care to
> > compare.
> >
> > Let me know if you'd like a v2, otherwise I'll hold off for a few days
> > in case something else crops up.
> 
> Let me review the rest before that, I'll do this tomorrow.
> 
> Bart
> 
> >
> > Cheers,
> > Kent.
> 
> [1] https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/tools/gpio-tools-test.bats

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 18/19] tools: add support for bias flags
  2019-11-17 12:28       ` Kent Gibson
@ 2019-11-17 13:12         ` Kent Gibson
  0 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-17 13:12 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Sun, Nov 17, 2019 at 08:28:01PM +0800, Kent Gibson wrote:
> On Sun, Nov 17, 2019 at 01:18:26PM +0100, Bartosz Golaszewski wrote:
> > sob., 16 lis 2019 o 16:40 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Fri, Nov 15, 2019 at 10:43:54PM +0800, Kent Gibson wrote:
> > > > Add support for bias flags to applicable tools - gpioget, gpioset, and
> > > > gpiomon.
> > > >
> > > > Signed-off-by: Kent Gibson <warthog618@gmail.com>
> > > > ---
> > > >  tools/gpioget.c | 24 ++++++++++++++++++++----
> > > >  tools/gpiomon.c | 28 ++++++++++++++++++++++------
> > > >  tools/gpioset.c | 26 +++++++++++++++++++++-----
> > > >  3 files changed, 63 insertions(+), 15 deletions(-)
> > > >
> > > > diff --git a/tools/gpioget.c b/tools/gpioget.c
> > > > index 196ebeb..025811a 100644
> > > > --- a/tools/gpioget.c
> > > > +++ b/tools/gpioget.c
> > > > @@ -17,10 +17,13 @@ static const struct option longopts[] = {
> > > >       { "help",       no_argument,    NULL,   'h' },
> > > >       { "version",    no_argument,    NULL,   'v' },
> > > >       { "active-low", no_argument,    NULL,   'l' },
> > > > +     { "pull-down",  no_argument,    NULL,   'D' },
> > > > +     { "pull-up",    no_argument,    NULL,   'U' },
> > > > +     { "bias-disable", no_argument,  NULL,   'B' },
> > > >       { GETOPT_NULL_LONGOPT },
> > > >  };
> > > >
> > > > -static const char *const shortopts = "+hvl";
> > > > +static const char *const shortopts = "+hvlDUB";
> > > >
> > > >  static void print_help(void)
> > > >  {
> > > > @@ -32,6 +35,9 @@ static void print_help(void)
> > > >       printf("  -h, --help:\t\tdisplay this message and exit\n");
> > > >       printf("  -v, --version:\tdisplay the version and exit\n");
> > > >       printf("  -l, --active-low:\tset the line active state to low\n");
> > > > +     printf("  -D, --pull-down:\tenable internal pull-down\n");
> > > > +     printf("  -U, --pull-up:\tenable internal pull-up\n");
> > > > +     printf("  -B, --bias-disable:\tdisable internal bias\n");
> > > >  }
> > > >
> > > >  int main(int argc, char **argv)
> > > > @@ -39,6 +45,7 @@ int main(int argc, char **argv)
> > > >       unsigned int *offsets, i, num_lines;
> > > >       int *values, optc, opti, rv;
> > > >       bool active_low = false;
> > > > +     int flags = 0;
> > > >       char *device, *end;
> > > >
> > > >       for (;;) {
> > > > @@ -56,6 +63,15 @@ int main(int argc, char **argv)
> > > >               case 'l':
> > > >                       active_low = true;
> > > >                       break;
> > > > +             case 'D':
> > > > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
> > > > +                     break;
> > > > +             case 'U':
> > > > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
> > > > +                     break;
> > > > +             case 'B':
> > > > +                     flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
> > > > +                     break;
> > > >               case '?':
> > > >                       die("try %s --help", get_progname());
> > > >               default:
> > > > @@ -86,9 +102,9 @@ int main(int argc, char **argv)
> > > >                       die("invalid GPIO offset: %s", argv[i + 1]);
> > > >       }
> > > >
> > >
> > > Nuts - this is wrong - it should be using the CTXLESS flags, not the
> > > LINE_REQUEST flags.  That applies to all three of the tools changed.
> > > I forgot to propagate the last minute CTXLESS changes to the tools.
> > > And unfortunately we don't have test cases for the tools :-(.
> > 
> > But we do![1]
> > 
> 
> Damn - I missed that.  I'll see about adding some cases for the bias
> flags for v2.
> 

I've pushed some tests for the tools bias and drive options to my github
branch.  I will include them in v2.
They use the --bias/--drive forms as that is what is currently at the HEAD,
but it is trivial to change them to the distinct flag versions if you
prefer that.

Cheers,
Kent.

> 
> > > I've got a fix in my github branch that I will incorporate into v2.
> > >
> > > I'm also wondering if it would be preferable to replace the individual
> > > bias command line flags with a single bias parameter, e.g. --bias=pull-up
> > > I've coded that in my github branch as well, if you would care to
> > > compare.
> > >
> > > Let me know if you'd like a v2, otherwise I'll hold off for a few days
> > > in case something else crops up.
> > 
> > Let me review the rest before that, I'll do this tomorrow.
> > 
> > Bart
> > 
> > >
> > > Cheers,
> > > Kent.
> > 
> > [1] https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/tree/tools/gpio-tools-test.bats

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG
  2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
                   ` (18 preceding siblings ...)
  2019-11-15 14:43 ` [libgpiod] [PATCH 19/19] treewide: change "correspond with" to "correspond to" Kent Gibson
@ 2019-11-18 13:50 ` Bartosz Golaszewski
  2019-11-18 14:09   ` Kent Gibson
  19 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-18 13:50 UTC (permalink / raw)
  To: Kent Gibson; +Cc: linux-gpio

pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> This patch series adds support for changes to the GPIO uAPI that are on
> track to be included in the v5.5 kernel.  There are two components to the
> uAPI changes - the addition of bias flags and a new SET_CONFIG ioctl.  This
> series adds support to the libgpiod API, and to both C++ and Python
> bindings, for both of those components.
>
> The libgpiod tools are also updated, where appropriate, to support the bias
> flags.
>
> There are a few additional patches that serve to restructure the code to
> simplify subsequent patches, or to fix minor problems discovered during
> development. These patches are generally adjacent to the main patch most
> relevant to that patch.
>
> The series is based on the current libgpiod master@9ed02fc.
>
> Kent Gibson (19):
>   core: move request flag to handle flag conversion into a separate
>     function
>   API: add support for bias flags
>   core: fix misspelling of parameter
>   tests: add tests for bias flags
>   bindings: cxx: drop noexcept from direction and active_state
>   bindings: cxx: initialise bitset with integer instead of string
>   bindings: cxx: add support for bias flags
>   bindings: cxx: tests: add tests for bias flags
>   bindings: python: add support for bias flags
>   bindings: python: tests: add tests for bias flags
>   API: add support for SET_CONFIG
>   tests: add tests for SET_CONFIG
>   core: allow gpiod_line_set_value_bulk to accept null values
>   bindings: cxx: add support for SET_CONFIG
>   bindings: cxx: tests: add tests for SET_CONFIG methods
>   bindings: python: add support for SET_CONFIG
>   bindings: python: tests: add tests for SET_CONFIG methods
>   tools: add support for bias flags
>   treewide: change "correspond with" to "correspond to"
>
>  bindings/cxx/gpiod.hpp                 |  85 +++-
>  bindings/cxx/line.cpp                  |  60 ++-
>  bindings/cxx/line_bulk.cpp             |  95 ++++-
>  bindings/cxx/tests/tests-line.cpp      | 215 ++++++++++
>  bindings/python/gpiodmodule.c          | 469 +++++++++++++++++++++-
>  bindings/python/tests/gpiod_py_test.py | 254 ++++++++++++
>  include/gpiod.h                        | 303 +++++++++++++-
>  lib/core.c                             | 250 ++++++++++--
>  lib/ctxless.c                          | 115 +++++-
>  tests/mockup/gpio-mockup.c             |   2 +-
>  tests/tests-ctxless.c                  |  64 ++-
>  tests/tests-event.c                    | 120 ++++++
>  tests/tests-line.c                     | 522 ++++++++++++++++++++++++-
>  tools/gpioget.c                        |  24 +-
>  tools/gpiomon.c                        |  28 +-
>  tools/gpioset.c                        |  26 +-
>  16 files changed, 2561 insertions(+), 71 deletions(-)
>
> --
> 2.24.0
>

Hi Kent,

the series looks quite good. I addressed some obvious things. I'll
review v2 more in detail, but honestly, I don't think there'll be a
lot of issues.

Would you mind if I applied patches 1, 3, 5, 6, 13 & 19 right away?
They fix existing problems, so there's no need to carry them over to
subsequent iterations of the series.

Bart

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 02/19] API: add support for bias flags
  2019-11-15 14:43 ` [libgpiod] [PATCH 02/19] API: add support for bias flags Kent Gibson
@ 2019-11-18 13:51   ` Bartosz Golaszewski
  2019-11-18 14:12     ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-18 13:51 UTC (permalink / raw)
  To: Kent Gibson; +Cc: linux-gpio

pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Extend the libgpiod API to support the bias flags recently added to the
> kernel GPIO uAPI.  The core change is the addition of
> GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP
> and GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN flags to be passed into
> line_request functions, and the addition of gpiod_line_bias to return the
> bias state of lines.
>
> Extended variants of the ctxless functions that accept an active_low flag
> are added to also accept other flags. The variant names add a "_ext"
> suffix to the name of the original function.
>
> Based on initial work by Drew Fustini <drew@pdp7.com>.
>
> Signed-off-by: Kent Gibson <warthog618@gmail.com>

Hi Kent,

this looks good, just a couple nits. I'd change the subject line to
"core: add support for bias flags". Also: how about moving the flags
argument to the last position in all the ctxless extended variants, so
that they keep the same signature *except* for the appended new
argument?

Bart



> ---
>  include/gpiod.h | 184 ++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/core.c      |  32 ++++++---
>  lib/ctxless.c   | 115 +++++++++++++++++++++++++++---
>  3 files changed, 313 insertions(+), 18 deletions(-)
>
> diff --git a/include/gpiod.h b/include/gpiod.h
> index 9860ea8..0f01cab 100644
> --- a/include/gpiod.h
> +++ b/include/gpiod.h
> @@ -84,6 +84,22 @@ struct gpiod_line_bulk;
>   * the need to use the gpiod_* structures or to keep track of resources.
>   */
>
> +/**
> + * @brief Miscellaneous GPIO flags.
> + */
> +enum {
> +       GPIOD_CTXLESS_FLAG_OPEN_DRAIN           = GPIOD_BIT(0),
> +       /**< The line is an open-drain port. */
> +       GPIOD_CTXLESS_FLAG_OPEN_SOURCE          = GPIOD_BIT(1),
> +       /**< The line is an open-source port. */
> +       GPIOD_CTXLESS_FLAG_BIAS_DISABLE         = GPIOD_BIT(2),
> +       /**< The line has neither either pull-up nor pull-down resistor */
> +       GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN       = GPIOD_BIT(3),
> +       /**< The line has pull-down resistor enabled */
> +       GPIOD_CTXLESS_FLAG_BIAS_PULL_UP         = GPIOD_BIT(4),
> +       /**< The line has pull-up resistor enabled */
> +};
> +
>  /**
>   * @brief Read current value from a single GPIO line.
>   * @param device Name, path, number or label of the gpiochip.
> @@ -95,6 +111,19 @@ struct gpiod_line_bulk;
>  int gpiod_ctxless_get_value(const char *device, unsigned int offset,
>                             bool active_low, const char *consumer) GPIOD_API;
>
> +/**
> + * @brief Read current value from a single GPIO line.
> + * @param device Name, path, number or label of the gpiochip.
> + * @param offset Offset of the GPIO line.
> + * @param active_low The active state of this line - true if low.
> + * @param flags The flags for the line.
> + * @param consumer Name of the consumer.
> + * @return 0 or 1 (GPIO value) if the operation succeeds, -1 on error.
> + */
> +int gpiod_ctxless_get_value_ext(const char *device, unsigned int offset,
> +                               bool active_low, int flags,
> +                               const char *consumer) GPIOD_API;
> +
>  /**
>   * @brief Read current values from a set of GPIO lines.
>   * @param device Name, path, number or label of the gpiochip.
> @@ -110,6 +139,24 @@ int gpiod_ctxless_get_value_multiple(const char *device,
>                                      unsigned int num_lines, bool active_low,
>                                      const char *consumer) GPIOD_API;
>
> +/**
> + * @brief Read current values from a set of GPIO lines.
> + * @param device Name, path, number or label of the gpiochip.
> + * @param offsets Array of offsets of lines whose values should be read.
> + * @param values Buffer in which the values will be stored.
> + * @param num_lines Number of lines, must be > 0.
> + * @param active_low The active state of this line - true if low.
> + * @param flags The flags for the lines.
> + * @param consumer Name of the consumer.
> + * @return 0 if the operation succeeds, -1 on error.
> + */
> +int gpiod_ctxless_get_value_multiple_ext(const char *device,
> +                                        const unsigned int *offsets,
> +                                        int *values,
> +                                        unsigned int num_lines,
> +                                        bool active_low, int flags,
> +                                        const char *consumer) GPIOD_API;
> +
>  /**
>   * @brief Simple set value callback signature.
>   */
> @@ -133,6 +180,26 @@ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
>                             gpiod_ctxless_set_value_cb cb,
>                             void *data) GPIOD_API;
>
> +/**
> + * @brief Set value of a single GPIO line.
> + * @param device Name, path, number or label of the gpiochip.
> + * @param offset The offset of the GPIO line.
> + * @param value New value (0 or 1).
> + * @param active_low The active state of this line - true if low.
> + * @param flags The flags for the line.
> + * @param consumer Name of the consumer.
> + * @param cb Optional callback function that will be called right after setting
> + *           the value. Users can use this, for example, to pause the execution
> + *           after toggling a GPIO.
> + * @param data Optional user data that will be passed to the callback function.
> + * @return 0 if the operation succeeds, -1 on error.
> + */
> +int gpiod_ctxless_set_value_ext(const char *device, unsigned int offset,
> +                               int value, bool active_low, int flags,
> +                               const char *consumer,
> +                               gpiod_ctxless_set_value_cb cb,
> +                               void *data) GPIOD_API;
> +
>  /**
>   * @brief Set values of multiple GPIO lines.
>   * @param device Name, path, number or label of the gpiochip.
> @@ -153,6 +220,29 @@ int gpiod_ctxless_set_value_multiple(const char *device,
>                                      gpiod_ctxless_set_value_cb cb,
>                                      void *data) GPIOD_API;
>
> +/**
> + * @brief Set values of multiple GPIO lines.
> + * @param device Name, path, number or label of the gpiochip.
> + * @param offsets Array of offsets of lines the values of which should be set.
> + * @param values Array of integers containing new values.
> + * @param num_lines Number of lines, must be > 0.
> + * @param active_low The active state of this line - true if low.
> + * @param flags The flags for the lines.
> + * @param consumer Name of the consumer.
> + * @param cb Optional callback function that will be called right after setting
> + *           all values. Works the same as in ::gpiod_ctxless_set_value.
> + * @param data Optional user data that will be passed to the callback function.
> + * @return 0 if the operation succeeds, -1 on error.
> + */
> +int gpiod_ctxless_set_value_multiple_ext(const char *device,
> +                                        const unsigned int *offsets,
> +                                        const int *values,
> +                                        unsigned int num_lines,
> +                                        bool active_low, int flags,
> +                                        const char *consumer,
> +                                        gpiod_ctxless_set_value_cb cb,
> +                                        void *data) GPIOD_API;
> +
>  /**
>   * @brief Event types that the ctxless event monitor can wait for.
>   */
> @@ -327,6 +417,31 @@ int gpiod_ctxless_event_monitor(const char *device, int event_type,
>                                 gpiod_ctxless_event_handle_cb event_cb,
>                                 void *data) GPIOD_API;
>
> +/**
> + * @brief Wait for events on a single GPIO line.
> + * @param device Name, path, number or label of the gpiochip.
> + * @param event_type Type of events to listen for.
> + * @param offset GPIO line offset to monitor.
> + * @param active_low The active state of this line - true if low.
> + * @param flags The flags for the line.
> + * @param consumer Name of the consumer.
> + * @param timeout Maximum wait time for each iteration.
> + * @param poll_cb Callback function to call when waiting for events.
> + * @param event_cb Callback function to call for each line event.
> + * @param data User data passed to the callback.
> + * @return 0 if no errors were encountered, -1 if an error occurred.
> + * @note The way the ctxless event loop works is described in detail in
> + *       ::gpiod_ctxless_event_monitor_multiple - this is just a wrapper aound
> + *       this routine which calls it for a single GPIO line.
> + */
> +int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
> +                                   unsigned int offset, bool active_low,
> +                                   int flags, const char *consumer,
> +                                   const struct timespec *timeout,
> +                                   gpiod_ctxless_event_poll_cb poll_cb,
> +                                   gpiod_ctxless_event_handle_cb event_cb,
> +                                   void *data) GPIOD_API;
> +
>  /**
>   * @brief Wait for events on multiple GPIO lines.
>   * @param device Name, path, number or label of the gpiochip.
> @@ -366,6 +481,47 @@ int gpiod_ctxless_event_monitor_multiple(
>                         gpiod_ctxless_event_handle_cb event_cb,
>                         void *data) GPIOD_API;
>
> +/**
> + * @brief Wait for events on multiple GPIO lines.
> + * @param device Name, path, number or label of the gpiochip.
> + * @param event_type Type of events to listen for.
> + * @param offsets Array of GPIO line offsets to monitor.
> + * @param num_lines Number of lines to monitor.
> + * @param active_low The active state of this line - true if low.
> + * @param flags The flags for the lines.
> + * @param consumer Name of the consumer.
> + * @param timeout Maximum wait time for each iteration.
> + * @param poll_cb Callback function to call when waiting for events. Can
> + *                be NULL.
> + * @param event_cb Callback function to call on event occurrence.
> + * @param data User data passed to the callback.
> + * @return 0 no errors were encountered, -1 if an error occurred.
> + * @note The poll callback can be NULL in which case the routine will fall
> + *       back to a basic, ppoll() based callback.
> + *
> + * Internally this routine opens the GPIO chip, requests the set of lines for
> + * the type of events specified in the event_type parameter and calls the
> + * polling callback in a loop. The role of the polling callback is to detect
> + * input events on a set of file descriptors and notify the caller about the
> + * fds ready for reading.
> + *
> + * The ctxless event loop then reads each queued event from marked descriptors
> + * and calls the event callback. Both callbacks can stop the loop at any
> + * point.
> + *
> + * The poll_cb argument can be NULL in which case the function falls back to
> + * a default, ppoll() based callback.
> + */
> +int gpiod_ctxless_event_monitor_multiple_ext(
> +                       const char *device, int event_type,
> +                       const unsigned int *offsets,
> +                       unsigned int num_lines, bool active_low, int flags,
> +                       const char *consumer, const struct timespec *timeout,
> +                       gpiod_ctxless_event_poll_cb poll_cb,
> +                       gpiod_ctxless_event_handle_cb event_cb,
> +                       void *data) GPIOD_API;
> +
> +
>  /**
>   * @brief Determine the chip name and line offset of a line with given name.
>   * @param name The name of the GPIO line to lookup.
> @@ -658,6 +814,20 @@ enum {
>         /**< The active state of a GPIO is active-low. */
>  };
>
> +/**
> + * @brief Possible internal bias settings.
> + */
> +enum {
> +       GPIOD_LINE_BIAS_AS_IS = 1,
> +       /**< The internal bias state is unknown. */
> +       GPIOD_LINE_BIAS_DISABLE,
> +       /**< The internal bias is disabled. */
> +       GPIOD_LINE_BIAS_PULL_UP,
> +       /**< The internal pull-up bias is enabled. */
> +       GPIOD_LINE_BIAS_PULL_DOWN,
> +       /**< The internal pull-down bias is enabled. */
> +};
> +
>  /**
>   * @brief Read the GPIO line offset.
>   * @param line GPIO line object.
> @@ -697,6 +867,14 @@ int gpiod_line_direction(struct gpiod_line *line) GPIOD_API;
>   */
>  int gpiod_line_active_state(struct gpiod_line *line) GPIOD_API;
>
> +/**
> + * @brief Read the GPIO line bias setting.
> + * @param line GPIO line object.
> + * @return Returns GPIOD_LINE_BIAS_PULL_UP, GPIOD_LINE_BIAS_PULL_DOWN,
> + *         GPIOD_LINE_BIAS_DISABLE or GPIOD_LINE_BIAS_AS_IS.
> + */
> +int gpiod_line_bias(struct gpiod_line *line) GPIOD_API;
> +
>  /**
>   * @brief Check if the line is currently in use.
>   * @param line GPIO line object.
> @@ -792,6 +970,12 @@ enum {
>         /**< The line is an open-source port. */
>         GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW      = GPIOD_BIT(2),
>         /**< The active state of the line is low (high is the default). */
> +       GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE    = GPIOD_BIT(3),
> +       /**< The line has neither either pull-up nor pull-down resistor */
> +       GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN  = GPIOD_BIT(4),
> +       /**< The line has pull-down resistor enabled */
> +       GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP    = GPIOD_BIT(5),
> +       /**< The line has pull-up resistor enabled */
>  };
>
>  /**
> diff --git a/lib/core.c b/lib/core.c
> index f05e595..9b7d88f 100644
> --- a/lib/core.c
> +++ b/lib/core.c
> @@ -36,9 +36,7 @@ struct gpiod_line {
>         unsigned int offset;
>         int direction;
>         int active_state;
> -       bool used;
> -       bool open_source;
> -       bool open_drain;
> +       __u32 flags;
>
>         int state;
>         bool needs_update;
> @@ -359,19 +357,31 @@ int gpiod_line_active_state(struct gpiod_line *line)
>         return line->active_state;
>  }
>
> +int gpiod_line_bias(struct gpiod_line *line)
> +{
> +       if (line->flags & GPIOLINE_FLAG_BIAS_DISABLE)
> +               return GPIOD_LINE_BIAS_DISABLE;
> +       if (line->flags & GPIOLINE_FLAG_BIAS_PULL_UP)
> +               return GPIOD_LINE_BIAS_PULL_UP;
> +       if (line->flags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
> +               return GPIOD_LINE_BIAS_PULL_DOWN;
> +
> +       return GPIOD_LINE_BIAS_AS_IS;
> +}
> +
>  bool gpiod_line_is_used(struct gpiod_line *line)
>  {
> -       return line->used;
> +       return line->flags & GPIOLINE_FLAG_KERNEL;
>  }
>
>  bool gpiod_line_is_open_drain(struct gpiod_line *line)
>  {
> -       return line->open_drain;
> +       return line->flags & GPIOLINE_FLAG_OPEN_DRAIN;
>  }
>
>  bool gpiod_line_is_open_source(struct gpiod_line *line)
>  {
> -       return line->open_source;
> +       return line->flags & GPIOLINE_FLAG_OPEN_SOURCE;
>  }
>
>  bool gpiod_line_needs_update(struct gpiod_line *line)
> @@ -398,9 +408,7 @@ int gpiod_line_update(struct gpiod_line *line)
>                                                 ? GPIOD_LINE_ACTIVE_STATE_LOW
>                                                 : GPIOD_LINE_ACTIVE_STATE_HIGH;
>
> -       line->used = info.flags & GPIOLINE_FLAG_KERNEL;
> -       line->open_drain = info.flags & GPIOLINE_FLAG_OPEN_DRAIN;
> -       line->open_source = info.flags & GPIOLINE_FLAG_OPEN_SOURCE;
> +       line->flags = info.flags;
>
>         strncpy(line->name, info.name, sizeof(line->name));
>         strncpy(line->consumer, info.consumer, sizeof(line->consumer));
> @@ -473,6 +481,12 @@ static __u32 line_request_flag_to_gpio_handleflag(int flags)
>                 hflags |= GPIOHANDLE_REQUEST_OPEN_SOURCE;
>         if (flags & GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW)
>                 hflags |= GPIOHANDLE_REQUEST_ACTIVE_LOW;
> +       if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE)
> +               hflags |= GPIOHANDLE_REQUEST_BIAS_DISABLE;
> +       if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN)
> +               hflags |= GPIOHANDLE_REQUEST_BIAS_PULL_DOWN;
> +       if (flags & GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP)
> +               hflags |= GPIOHANDLE_REQUEST_BIAS_PULL_UP;
>
>         return hflags;
>  }
> diff --git a/lib/ctxless.c b/lib/ctxless.c
> index ba85018..44f1872 100644
> --- a/lib/ctxless.c
> +++ b/lib/ctxless.c
> @@ -14,6 +14,26 @@
>  #include <stdio.h>
>  #include <string.h>
>
> +static int ctxless_flags_to_line_request_flags(bool active_low, int flags)
> +{
> +       int lflags = 0;
> +
> +       if (active_low)
> +               lflags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
> +       if (flags & GPIOD_CTXLESS_FLAG_OPEN_DRAIN)
> +               lflags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN;
> +       if (flags & GPIOD_CTXLESS_FLAG_OPEN_SOURCE)
> +               lflags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
> +       if (flags & GPIOD_CTXLESS_FLAG_BIAS_DISABLE)
> +               lflags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE;
> +       if (flags & GPIOD_CTXLESS_FLAG_BIAS_PULL_UP)
> +               lflags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP;
> +       if (flags & GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN)
> +               lflags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN;
> +
> +       return lflags;
> +}
> +
>  int gpiod_ctxless_get_value(const char *device, unsigned int offset,
>                             bool active_low, const char *consumer)
>  {
> @@ -27,16 +47,45 @@ int gpiod_ctxless_get_value(const char *device, unsigned int offset,
>         return value;
>  }
>
> +int gpiod_ctxless_get_value_ext(const char *device, unsigned int offset,
> +                               bool active_low, int flags,
> +                               const char *consumer)
> +{
> +       int value, rv;
> +
> +       rv = gpiod_ctxless_get_value_multiple_ext(device, &offset, &value, 1,
> +                                                 active_low, flags, consumer);
> +       if (rv < 0)
> +               return rv;
> +
> +       return value;
> +}
> +
>  int gpiod_ctxless_get_value_multiple(const char *device,
>                                      const unsigned int *offsets, int *values,
>                                      unsigned int num_lines, bool active_low,
>                                      const char *consumer)
> +{
> +       int rv;
> +
> +       rv = gpiod_ctxless_get_value_multiple_ext(device, offsets, values,
> +                                                 num_lines, active_low, 0,
> +                                                 consumer);
> +       return rv;
> +}
> +
> +int gpiod_ctxless_get_value_multiple_ext(const char *device,
> +                                        const unsigned int *offsets,
> +                                        int *values,
> +                                        unsigned int num_lines,
> +                                        bool active_low, int flags,
> +                                        const char *consumer)
>  {
>         struct gpiod_line_bulk bulk;
>         struct gpiod_chip *chip;
>         struct gpiod_line *line;
>         unsigned int i;
> -       int rv, flags;
> +       int rv, lflags;
>
>         if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
>                 errno = EINVAL;
> @@ -59,9 +108,8 @@ int gpiod_ctxless_get_value_multiple(const char *device,
>                 gpiod_line_bulk_add(&bulk, line);
>         }
>
> -       flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
> -
> -       rv = gpiod_line_request_bulk_input_flags(&bulk, consumer, flags);
> +       lflags = ctxless_flags_to_line_request_flags(active_low, flags);
> +       rv = gpiod_line_request_bulk_input_flags(&bulk, consumer, lflags);
>         if (rv < 0) {
>                 gpiod_chip_close(chip);
>                 return -1;
> @@ -83,17 +131,39 @@ int gpiod_ctxless_set_value(const char *device, unsigned int offset, int value,
>                                                 active_low, consumer, cb, data);
>  }
>
> +int gpiod_ctxless_set_value_ext(const char *device, unsigned int offset,
> +                               int value, bool active_low, int flags,
> +                               const char *consumer,
> +                               gpiod_ctxless_set_value_cb cb, void *data)
> +{
> +       return gpiod_ctxless_set_value_multiple_ext(device, &offset, &value,
> +                                                   1, active_low, flags,
> +                                                   consumer, cb, data);
> +}
> +
>  int gpiod_ctxless_set_value_multiple(const char *device,
>                                      const unsigned int *offsets,
>                                      const int *values, unsigned int num_lines,
>                                      bool active_low, const char *consumer,
>                                      gpiod_ctxless_set_value_cb cb, void *data)
> +{
> +       return gpiod_ctxless_set_value_multiple_ext(device, offsets, values,
> +                                                   num_lines, active_low,
> +                                                   0, consumer, cb, data);
> +}
> +
> +int gpiod_ctxless_set_value_multiple_ext(
> +                       const char *device,
> +                       const unsigned int *offsets,
> +                       const int *values, unsigned int num_lines,
> +                       bool active_low, int flags, const char *consumer,
> +                       gpiod_ctxless_set_value_cb cb, void *data)
>  {
>         struct gpiod_line_bulk bulk;
>         struct gpiod_chip *chip;
>         struct gpiod_line *line;
>         unsigned int i;
> -       int rv, flags;
> +       int rv, lflags;
>
>         if (!num_lines || num_lines > GPIOD_LINE_BULK_MAX_LINES) {
>                 errno = EINVAL;
> @@ -116,10 +186,9 @@ int gpiod_ctxless_set_value_multiple(const char *device,
>                 gpiod_line_bulk_add(&bulk, line);
>         }
>
> -       flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
> -
> +       lflags = ctxless_flags_to_line_request_flags(active_low, flags);
>         rv = gpiod_line_request_bulk_output_flags(&bulk, consumer,
> -                                                 flags, values);
> +                                                 lflags, values);
>         if (rv < 0) {
>                 gpiod_chip_close(chip);
>                 return -1;
> @@ -216,6 +285,19 @@ int gpiod_ctxless_event_monitor(const char *device, int event_type,
>                                                     poll_cb, event_cb, data);
>  }
>
> +int gpiod_ctxless_event_monitor_ext(const char *device, int event_type,
> +                                   unsigned int offset, bool active_low,
> +                                   int flags, const char *consumer,
> +                                   const struct timespec *timeout,
> +                                   gpiod_ctxless_event_poll_cb poll_cb,
> +                                   gpiod_ctxless_event_handle_cb event_cb,
> +                                   void *data)
> +{
> +       return gpiod_ctxless_event_monitor_multiple_ext(
> +                       device, event_type, &offset, 1, active_low,
> +                       flags, consumer, timeout, poll_cb, event_cb, data);
> +}
> +
>  int gpiod_ctxless_event_monitor_multiple(
>                         const char *device, int event_type,
>                         const unsigned int *offsets,
> @@ -225,6 +307,21 @@ int gpiod_ctxless_event_monitor_multiple(
>                         gpiod_ctxless_event_poll_cb poll_cb,
>                         gpiod_ctxless_event_handle_cb event_cb,
>                         void *data)
> +{
> +       return gpiod_ctxless_event_monitor_multiple_ext(
> +                       device, event_type, offsets,
> +                       num_lines, active_low, 0, consumer, timeout,
> +                       poll_cb, event_cb, data);
> +}
> +
> +int gpiod_ctxless_event_monitor_multiple_ext(
> +                       const char *device, int event_type,
> +                       const unsigned int *offsets,
> +                       unsigned int num_lines, bool active_low, int flags,
> +                       const char *consumer, const struct timespec *timeout,
> +                       gpiod_ctxless_event_poll_cb poll_cb,
> +                       gpiod_ctxless_event_handle_cb event_cb,
> +                       void *data)
>  {
>         struct gpiod_ctxless_event_poll_fd fds[GPIOD_LINE_BULK_MAX_LINES];
>         struct gpiod_line_request_config conf;
> @@ -259,7 +356,7 @@ int gpiod_ctxless_event_monitor_multiple(
>                 gpiod_line_bulk_add(&bulk, line);
>         }
>
> -       conf.flags = active_low ? GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW : 0;
> +       conf.flags = ctxless_flags_to_line_request_flags(active_low, flags);
>         conf.consumer = consumer;
>
>         if (event_type == GPIOD_CTXLESS_EVENT_RISING_EDGE) {
> --
> 2.24.0
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 04/19] tests: add tests for bias flags
  2019-11-15 14:43 ` [libgpiod] [PATCH 04/19] tests: add tests for bias flags Kent Gibson
@ 2019-11-18 13:51   ` Bartosz Golaszewski
  2019-11-18 14:14     ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-18 13:51 UTC (permalink / raw)
  To: Kent Gibson; +Cc: linux-gpio

pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Extend test coverage over the bias flags, gpiod_line_bias and the extended
> ctxless functions.
>
> Also update existing tests to check bias flags where line state is checked.
>
> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
>  tests/tests-ctxless.c |  64 +++++++++++++++++++++-
>  tests/tests-event.c   | 120 ++++++++++++++++++++++++++++++++++++++++++
>  tests/tests-line.c    |  98 ++++++++++++++++++++++++++++++++++
>  3 files changed, 280 insertions(+), 2 deletions(-)
>
> diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c
> index c1e1ca6..da70587 100644
> --- a/tests/tests-ctxless.c
> +++ b/tests/tests-ctxless.c
> @@ -26,11 +26,41 @@ GPIOD_TEST_CASE(get_value, 0, { 8 })
>         g_assert_cmpint(ret, ==, 1);
>  }
>
> -static void set_value_check(gpointer data G_GNUC_UNUSED)
> +GPIOD_TEST_CASE(get_value_ext, 0, { 8 })
> +{
> +       gint ret;
> +
> +       ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> +                               false, GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN,
> +                               GPIOD_TEST_CONSUMER);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> +                               false, GPIOD_CTXLESS_FLAG_BIAS_PULL_UP,
> +                               GPIOD_TEST_CONSUMER);
> +       g_assert_cmpint(ret, ==, 1);
> +
> +       ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> +                               true, GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN,
> +                               GPIOD_TEST_CONSUMER);
> +       g_assert_cmpint(ret, ==, 1);
> +
> +       ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> +                               true, GPIOD_CTXLESS_FLAG_BIAS_PULL_UP,
> +                               GPIOD_TEST_CONSUMER);
> +       g_assert_cmpint(ret, ==, 0);
> +}
> +
> +static void set_value_check_hi(gpointer data G_GNUC_UNUSED)
>  {
>         g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
>  }
>
> +static void set_value_check_lo(gpointer data G_GNUC_UNUSED)
> +{
> +       g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> +}
> +
>  GPIOD_TEST_CASE(set_value, 0, { 8 })
>  {
>         gint ret;
> @@ -39,13 +69,43 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
>
>         ret = gpiod_ctxless_set_value(gpiod_test_chip_name(0), 3, 1,
>                                       false, GPIOD_TEST_CONSUMER,
> -                                     set_value_check, NULL);
> +                                     set_value_check_hi, NULL);
>         gpiod_test_return_if_failed();
>         g_assert_cmpint(ret, ==, 0);
>
>         g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
>  }
>
> +GPIOD_TEST_CASE(set_value_ext, 0, { 8 })
> +{
> +       gint ret;
> +
> +       gpiod_test_chip_set_pull(0, 3, 0);
> +
> +       ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
> +                       false, 0, GPIOD_TEST_CONSUMER,
> +                       set_value_check_hi, NULL);
> +       gpiod_test_return_if_failed();
> +       g_assert_cmpint(ret, ==, 0);
> +       g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> +
> +       // test drive flags by checking that sets are caught by emulation

Nit: don't use C++ comments in libgpiod.

Bart



> +       ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
> +                       false, GPIOD_CTXLESS_FLAG_OPEN_DRAIN,
> +                       GPIOD_TEST_CONSUMER, set_value_check_lo, NULL);
> +       gpiod_test_return_if_failed();
> +       g_assert_cmpint(ret, ==, 0);
> +       g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> +
> +       gpiod_test_chip_set_pull(0, 3, 1);
> +       ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 0,
> +                       false, GPIOD_CTXLESS_FLAG_OPEN_SOURCE,
> +                       GPIOD_TEST_CONSUMER, set_value_check_hi, NULL);
> +       gpiod_test_return_if_failed();
> +       g_assert_cmpint(ret, ==, 0);
> +       g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
> +}
> +
>  static const guint get_value_multiple_offsets[] = {
>         1, 3, 4, 5, 6, 7, 8, 9, 13, 14
>  };
> diff --git a/tests/tests-event.c b/tests/tests-event.c
> index 28b77ec..d425d1a 100644
> --- a/tests/tests-event.c
> +++ b/tests/tests-event.c
> @@ -196,6 +196,126 @@ GPIOD_TEST_CASE(both_edges_active_low, 0, { 8 })
>         g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
>  }
>
> +GPIOD_TEST_CASE(both_edges_bias_disable, 0, { 8 })
> +{
> +       g_autoptr(GpiodTestEventThread) ev_thread = NULL;
> +       g_autoptr(gpiod_chip_struct) chip = NULL;
> +       struct timespec ts = { 1, 0 };
> +       struct gpiod_line_event ev;
> +       struct gpiod_line *line;
> +       gint ret;
> +
> +       chip = gpiod_chip_open(gpiod_test_chip_path(0));
> +       g_assert_nonnull(chip);
> +       gpiod_test_return_if_failed();
> +
> +       line = gpiod_chip_get_line(chip, 7);
> +       g_assert_nonnull(line);
> +       gpiod_test_return_if_failed();
> +
> +       ret = gpiod_line_request_both_edges_events_flags(line,
> +               GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       ev_thread = gpiod_test_start_event_thread(0, 7, 100);
> +
> +       ret = gpiod_line_event_wait(line, &ts);
> +       g_assert_cmpint(ret, ==, 1);
> +
> +       ret = gpiod_line_event_read(line, &ev);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
> +
> +       ret = gpiod_line_event_wait(line, &ts);
> +       g_assert_cmpint(ret, ==, 1);
> +
> +       ret = gpiod_line_event_read(line, &ev);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
> +}
> +
> +GPIOD_TEST_CASE(both_edges_bias_pull_down, 0, { 8 })
> +{
> +       g_autoptr(GpiodTestEventThread) ev_thread = NULL;
> +       g_autoptr(gpiod_chip_struct) chip = NULL;
> +       struct timespec ts = { 1, 0 };
> +       struct gpiod_line_event ev;
> +       struct gpiod_line *line;
> +       gint ret;
> +
> +       chip = gpiod_chip_open(gpiod_test_chip_path(0));
> +       g_assert_nonnull(chip);
> +       gpiod_test_return_if_failed();
> +
> +       line = gpiod_chip_get_line(chip, 7);
> +       g_assert_nonnull(line);
> +       gpiod_test_return_if_failed();
> +
> +       ret = gpiod_line_request_both_edges_events_flags(line,
> +               GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       ev_thread = gpiod_test_start_event_thread(0, 7, 100);
> +
> +       ret = gpiod_line_event_wait(line, &ts);
> +       g_assert_cmpint(ret, ==, 1);
> +
> +       ret = gpiod_line_event_read(line, &ev);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
> +
> +       ret = gpiod_line_event_wait(line, &ts);
> +       g_assert_cmpint(ret, ==, 1);
> +
> +       ret = gpiod_line_event_read(line, &ev);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
> +}
> +
> +GPIOD_TEST_CASE(both_edges_bias_pull_up, 0, { 8 })
> +{
> +       g_autoptr(GpiodTestEventThread) ev_thread = NULL;
> +       g_autoptr(gpiod_chip_struct) chip = NULL;
> +       struct timespec ts = { 1, 0 };
> +       struct gpiod_line_event ev;
> +       struct gpiod_line *line;
> +       gint ret;
> +
> +       chip = gpiod_chip_open(gpiod_test_chip_path(0));
> +       g_assert_nonnull(chip);
> +       gpiod_test_return_if_failed();
> +
> +       line = gpiod_chip_get_line(chip, 7);
> +       g_assert_nonnull(line);
> +       gpiod_test_return_if_failed();
> +
> +       ret = gpiod_line_request_both_edges_events_flags(line,
> +               GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       ev_thread = gpiod_test_start_event_thread(0, 7, 100);
> +
> +       ret = gpiod_line_event_wait(line, &ts);
> +       g_assert_cmpint(ret, ==, 1);
> +
> +       ret = gpiod_line_event_read(line, &ev);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_FALLING_EDGE);
> +
> +       ret = gpiod_line_event_wait(line, &ts);
> +       g_assert_cmpint(ret, ==, 1);
> +
> +       ret = gpiod_line_event_read(line, &ev);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
> +}
> +
>  GPIOD_TEST_CASE(falling_edge_active_low, 0, { 8 })
>  {
>         g_autoptr(GpiodTestEventThread) ev_thread = NULL;
> diff --git a/tests/tests-line.c b/tests/tests-line.c
> index 4792211..b4bef1a 100644
> --- a/tests/tests-line.c
> +++ b/tests/tests-line.c
> @@ -451,6 +451,7 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
>         g_assert_false(gpiod_line_is_used(line));
>         g_assert_false(gpiod_line_is_open_drain(line));
>         g_assert_false(gpiod_line_is_open_source(line));
> +       g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
>
>         config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
>         config.consumer = GPIOD_TEST_CONSUMER;
> @@ -462,6 +463,7 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
>         g_assert_true(gpiod_line_is_used(line));
>         g_assert_true(gpiod_line_is_open_drain(line));
>         g_assert_false(gpiod_line_is_open_source(line));
> +       g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
>         g_assert_cmpint(gpiod_line_direction(line), ==,
>                         GPIOD_LINE_DIRECTION_OUTPUT);
>
> @@ -475,8 +477,11 @@ GPIOD_TEST_CASE(misc_flags, 0, { 8 })
>         g_assert_true(gpiod_line_is_used(line));
>         g_assert_false(gpiod_line_is_open_drain(line));
>         g_assert_true(gpiod_line_is_open_source(line));
> +       g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
>         g_assert_cmpint(gpiod_line_direction(line), ==,
>                         GPIOD_LINE_DIRECTION_OUTPUT);
> +
> +       gpiod_line_release(line);
>  }
>
>  GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
> @@ -510,6 +515,7 @@ GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
>         g_assert_true(gpiod_line_is_used(line));
>         g_assert_true(gpiod_line_is_open_drain(line));
>         g_assert_false(gpiod_line_is_open_source(line));
> +       g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
>         g_assert_cmpint(gpiod_line_active_state(line), ==,
>                         GPIOD_LINE_ACTIVE_STATE_LOW);
>         g_assert_cmpint(gpiod_line_direction(line), ==,
> @@ -526,8 +532,59 @@ GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
>         g_assert_true(gpiod_line_is_used(line));
>         g_assert_false(gpiod_line_is_open_drain(line));
>         g_assert_true(gpiod_line_is_open_source(line));
> +       g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_AS_IS);
>         g_assert_cmpint(gpiod_line_active_state(line), ==,
>                         GPIOD_LINE_ACTIVE_STATE_LOW);
> +
> +       gpiod_line_release(line);
> +
> +       /*
> +        * Verify that pull-up/down flags work together
> +        * with active_low.
> +        */
> +
> +       config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
> +       config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
> +                      GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
> +
> +       ret = gpiod_line_request(line, &config, 0);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       g_assert_true(gpiod_line_is_used(line));
> +       g_assert_false(gpiod_line_is_open_drain(line));
> +       g_assert_false(gpiod_line_is_open_source(line));
> +       g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN);
> +       g_assert_cmpint(gpiod_line_active_state(line), ==,
> +                       GPIOD_LINE_ACTIVE_STATE_LOW);
> +       g_assert_cmpint(gpiod_line_direction(line), ==,
> +                       GPIOD_LINE_DIRECTION_INPUT);
> +
> +       ret = gpiod_line_get_value(line);
> +       g_assert_cmpint(ret, ==, 1);
> +       g_assert_cmpint(errno, ==, 0);
> +
> +       gpiod_line_release(line);
> +
> +       config.flags = GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP |
> +                      GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
> +
> +       ret = gpiod_line_request(line, &config, 0);
> +       g_assert_cmpint(ret, ==, 0);
> +
> +       g_assert_true(gpiod_line_is_used(line));
> +       g_assert_false(gpiod_line_is_open_drain(line));
> +       g_assert_false(gpiod_line_is_open_source(line));
> +       g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP);
> +       g_assert_cmpint(gpiod_line_active_state(line), ==,
> +                       GPIOD_LINE_ACTIVE_STATE_LOW);
> +       g_assert_cmpint(gpiod_line_direction(line), ==,
> +                       GPIOD_LINE_DIRECTION_INPUT);
> +
> +       ret = gpiod_line_get_value(line);
> +       g_assert_cmpint(ret, ==, 0);
> +       g_assert_cmpint(errno, ==, 0);
> +
> +       gpiod_line_release(line);
>  }
>
>  GPIOD_TEST_CASE(open_source_open_drain_input_mode, 0, { 8 })
> @@ -576,6 +633,47 @@ GPIOD_TEST_CASE(open_source_open_drain_simultaneously, 0, { 8 })
>         g_assert_cmpint(errno, ==, EINVAL);
>  }
>
> +GPIOD_TEST_CASE(multiple_bias_flags, 0, { 8 })
> +{
> +       g_autoptr(gpiod_chip_struct) chip = NULL;
> +       struct gpiod_line *line;
> +       gint ret;
> +
> +       chip = gpiod_chip_open(gpiod_test_chip_path(0));
> +       g_assert_nonnull(chip);
> +       gpiod_test_return_if_failed();
> +
> +       line = gpiod_chip_get_line(chip, 2);
> +       g_assert_nonnull(line);
> +       gpiod_test_return_if_failed();
> +
> +       ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN);
> +       g_assert_cmpint(ret, ==, -1);
> +       g_assert_cmpint(errno, ==, EINVAL);
> +
> +       ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
> +       g_assert_cmpint(ret, ==, -1);
> +       g_assert_cmpint(errno, ==, EINVAL);
> +
> +       ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
> +       g_assert_cmpint(ret, ==, -1);
> +       g_assert_cmpint(errno, ==, EINVAL);
> +
> +       ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE |
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN |
> +                                       GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP);
> +       g_assert_cmpint(ret, ==, -1);
> +       g_assert_cmpint(errno, ==, EINVAL);
> +}
> +
> +
>  /* Verify that the reference counting of the line fd handle works correctly. */
>  GPIOD_TEST_CASE(release_one_use_another, 0, { 8 })
>  {
> --
> 2.24.0
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 06/19] bindings: cxx: initialise bitset with integer instead of string
  2019-11-15 14:43 ` [libgpiod] [PATCH 06/19] bindings: cxx: initialise bitset with integer instead of string Kent Gibson
@ 2019-11-18 13:51   ` Bartosz Golaszewski
  2019-11-18 14:17     ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-18 13:51 UTC (permalink / raw)
  To: Kent Gibson; +Cc: linux-gpio

pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Initialising bitsets with string is inefficient and confusing.
> Initialise them with the corresponding int instead.
>

I'm not a native English speaker, of course, so correcting you on
spelling may be risky but I generally try to stick to American
spelling so "initialise" looks somehow wrong to me. :) Anyway, this is
just the commit message, so never mind that.

> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
>  bindings/cxx/line_bulk.cpp | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp
> index 8369930..c708c8b 100644
> --- a/bindings/cxx/line_bulk.cpp
> +++ b/bindings/cxx/line_bulk.cpp
> @@ -11,9 +11,9 @@
>
>  namespace gpiod {
>
> -const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW("001");
> -const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE("010");
> -const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN("100");
> +const ::std::bitset<32> line_request::FLAG_ACTIVE_LOW(GPIOD_BIT(0));
> +const ::std::bitset<32> line_request::FLAG_OPEN_SOURCE(GPIOD_BIT(1));
> +const ::std::bitset<32> line_request::FLAG_OPEN_DRAIN(GPIOD_BIT(2));
>
>  namespace {
>
> --
> 2.24.0
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-15 14:43 ` [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG Kent Gibson
@ 2019-11-18 13:52   ` Bartosz Golaszewski
  2019-11-18 14:48     ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-18 13:52 UTC (permalink / raw)
  To: Kent Gibson; +Cc: linux-gpio

pt., 15 lis 2019 o 15:45 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> 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 | 115 ++++++++++++++++++++++++++++
>  lib/core.c      | 196 +++++++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 300 insertions(+), 11 deletions(-)
>
> diff --git a/include/gpiod.h b/include/gpiod.h
> index 159d745..4053fd2 100644
> --- a/include/gpiod.h
> +++ b/include/gpiod.h
> @@ -1252,6 +1252,14 @@ 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, false otherwise.

I'd clarify: "requested for reading/setting values".

> + */
> +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.
> @@ -1311,6 +1319,113 @@ 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.
> + * @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_bulk_input(struct gpiod_line_bulk *bulk
> +                                       ) GPIOD_API;

Please stick to the current convention of having "_bulk" at the end of
the function name.

> +
> +/**
> + * @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.
> + * @values The logical value to output for each line.
> + * @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_bulk_output(struct gpiod_line_bulk *bulk,
> +                                        const int *values) GPIOD_API;
> +
>  /**
>   * @}
>   *
> diff --git a/lib/core.c b/lib/core.c
> index 9b7d88f..c42cda5 100644
> --- a/lib/core.c
> +++ b/lib/core.c
> @@ -36,10 +36,13 @@ struct gpiod_line {
>         unsigned int offset;
>         int direction;
>         int active_state;
> -       __u32 flags;
> +       int output_value;
> +       __u32 lflags;
> +       __u32 cflags;

Ugh, these aren't very fortunate names - at first glance I have no
idea what they mean. Either document those or change the names to
something more obvious.

>
>         int state;
>         bool needs_update;
> +       bool as_is;
>
>         struct gpiod_chip *chip;
>         struct line_fd_handle *fd_handle;
> @@ -359,11 +362,11 @@ int gpiod_line_active_state(struct gpiod_line *line)
>
>  int gpiod_line_bias(struct gpiod_line *line)
>  {
> -       if (line->flags & GPIOLINE_FLAG_BIAS_DISABLE)
> +       if (line->lflags & GPIOLINE_FLAG_BIAS_DISABLE)
>                 return GPIOD_LINE_BIAS_DISABLE;
> -       if (line->flags & GPIOLINE_FLAG_BIAS_PULL_UP)
> +       if (line->lflags & GPIOLINE_FLAG_BIAS_PULL_UP)
>                 return GPIOD_LINE_BIAS_PULL_UP;
> -       if (line->flags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
> +       if (line->lflags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
>                 return GPIOD_LINE_BIAS_PULL_DOWN;
>
>         return GPIOD_LINE_BIAS_AS_IS;
> @@ -371,17 +374,17 @@ int gpiod_line_bias(struct gpiod_line *line)
>
>  bool gpiod_line_is_used(struct gpiod_line *line)
>  {
> -       return line->flags & GPIOLINE_FLAG_KERNEL;
> +       return line->lflags & GPIOLINE_FLAG_KERNEL;
>  }
>
>  bool gpiod_line_is_open_drain(struct gpiod_line *line)
>  {
> -       return line->flags & GPIOLINE_FLAG_OPEN_DRAIN;
> +       return line->lflags & GPIOLINE_FLAG_OPEN_DRAIN;
>  }
>
>  bool gpiod_line_is_open_source(struct gpiod_line *line)
>  {
> -       return line->flags & GPIOLINE_FLAG_OPEN_SOURCE;
> +       return line->lflags & GPIOLINE_FLAG_OPEN_SOURCE;
>  }
>
>  bool gpiod_line_needs_update(struct gpiod_line *line)
> @@ -408,7 +411,7 @@ int gpiod_line_update(struct gpiod_line *line)
>                                                 ? GPIOD_LINE_ACTIVE_STATE_LOW
>                                                 : GPIOD_LINE_ACTIVE_STATE_HIGH;
>
> -       line->flags = info.flags;
> +       line->lflags = info.flags;
>
>         strncpy(line->name, info.name, sizeof(line->name));
>         strncpy(line->consumer, info.consumer, sizeof(line->consumer));
> @@ -457,6 +460,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 +488,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 +533,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 +562,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 +585,14 @@ 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->cflags = config->flags;
> +               if (config->request_type ==
> +                       GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
> +                       line->output_value = req.default_values[i];
> +               if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_AS_IS)
> +                       line->as_is = true;
>                 line_set_fd(line, line_fd);
>                 line_maybe_update(line);
>         }
> @@ -590,6 +633,7 @@ static int line_request_event_single(struct gpiod_line *line,
>                 return -1;
>
>         line->state = LINE_REQUESTED_EVENTS;
> +       line->cflags = config->flags;
>         line_set_fd(line, line_fd);
>         line_maybe_update(line);
>
> @@ -688,6 +732,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 +815,134 @@ 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;
> +       bool as_is;
> +
> +       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;
> +
> +       as_is = line->as_is && direction == GPIOD_LINE_REQUEST_DIRECTION_AS_IS;
> +       gpiod_line_bulk_foreach_line_off(bulk, line, i) {
> +               line->cflags = flags;
> +               if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
> +                       line->output_value = hcfg.default_values[i];
> +               line->as_is = as_is;
> +               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->as_is) {

Can you explain the purpose of this as_is field? I'm not sure this is
really needed.

Bart


> +               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->cflags, 0);
> +}
> +
> +int gpiod_line_set_direction_bulk_input(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->cflags, 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->cflags, value);
> +}
> +
> +int gpiod_line_set_direction_bulk_output(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->cflags, values);
> +}
> +
>  int gpiod_line_event_wait(struct gpiod_line *line,
>                           const struct timespec *timeout)
>  {
> --
> 2.24.0
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 19/19] treewide: change "correspond with" to "correspond to"
  2019-11-15 14:43 ` [libgpiod] [PATCH 19/19] treewide: change "correspond with" to "correspond to" Kent Gibson
@ 2019-11-18 13:52   ` Bartosz Golaszewski
  2019-11-18 15:01     ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-18 13:52 UTC (permalink / raw)
  To: Kent Gibson; +Cc: linux-gpio

pt., 15 lis 2019 o 15:45 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> Trivial grammar fix. "correspond with" can mean either being in agreement
> with, happening at the same time, or communication between parties.
> "correspond to" is used to mean equivalance, which is the intended use
> throughout the documentation.
>

Thanks for this. I'm not a native English speaker, so if you see any
other language issues, please let me know, or feel free to fix them.

Bart

> Signed-off-by: Kent Gibson <warthog618@gmail.com>
> ---
>  bindings/python/gpiodmodule.c | 6 +++---
>  include/gpiod.h               | 2 +-
>  lib/core.c                    | 2 +-
>  tests/mockup/gpio-mockup.c    | 2 +-
>  4 files changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c
> index 4949b14..74fbea3 100644
> --- a/bindings/python/gpiodmodule.c
> +++ b/bindings/python/gpiodmodule.c
> @@ -1330,7 +1330,7 @@ PyDoc_STRVAR(gpiod_LineBulk_get_values_doc,
>  "get_values() -> list of integers\n"
>  "\n"
>  "Read the values of all the lines held by this LineBulk object. The index\n"
> -"of each value in the returned list corresponds with the index of the line\n"
> +"of each value in the returned list corresponds to the index of the line\n"
>  "in this gpiod.LineBulk object.");
>
>  static PyObject *gpiod_LineBulk_get_values(gpiod_LineBulkObject *self,
> @@ -1385,7 +1385,7 @@ PyDoc_STRVAR(gpiod_LineBulk_set_values_doc,
>  "\n"
>  "The number of values in the list passed as argument must be the same as\n"
>  "the number of lines held by this gpiod.LineBulk object. The index of each\n"
> -"value corresponds with the index of each line in the object.\n");
> +"value corresponds to the index of each line in the object.\n");
>
>  static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,
>                                            PyObject *args)
> @@ -1408,7 +1408,7 @@ static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self,
>         num_vals = PyObject_Size(val_list);
>         if (self->num_lines != num_vals) {
>                 PyErr_SetString(PyExc_TypeError,
> -                               "Number of values must correspond with the number of lines");
> +                               "Number of values must correspond to the number of lines");
>                 return NULL;
>         }
>
> diff --git a/include/gpiod.h b/include/gpiod.h
> index 4053fd2..6776852 100644
> --- a/include/gpiod.h
> +++ b/include/gpiod.h
> @@ -779,7 +779,7 @@ gpiod_line_bulk_num_lines(struct gpiod_line_bulk *bulk)
>   *
>   * This is a variant of ::gpiod_line_bulk_foreach_line which uses an integer
>   * variable (either signed or unsigned) to store the loop state. This offset
> - * variable is guaranteed to correspond with the offset of the current line in
> + * variable is guaranteed to correspond to the offset of the current line in
>   * the bulk->lines array.
>   */
>  #define gpiod_line_bulk_foreach_line_off(bulk, line, offset)           \
> diff --git a/lib/core.c b/lib/core.c
> index 2e54def..54ae09c 100644
> --- a/lib/core.c
> +++ b/lib/core.c
> @@ -111,7 +111,7 @@ static bool is_gpiochip_cdev(const char *path)
>
>         /*
>          * Make sure the major and minor numbers of the character device
> -        * correspond with the ones in the dev attribute in sysfs.
> +        * correspond to the ones in the dev attribute in sysfs.
>          */
>         snprintf(devstr, sizeof(devstr), "%u:%u",
>                  major(statbuf.st_rdev), minor(statbuf.st_rdev));
> diff --git a/tests/mockup/gpio-mockup.c b/tests/mockup/gpio-mockup.c
> index e3a53da..fa27bd7 100644
> --- a/tests/mockup/gpio-mockup.c
> +++ b/tests/mockup/gpio-mockup.c
> @@ -333,7 +333,7 @@ EXPORT int gpio_mockup_probe(struct gpio_mockup *ctx, unsigned int num_chips,
>         /*
>          * We can't assume that the order in which the mockup gpiochip
>          * devices are created will be deterministic, yet we want the
> -        * index passed to the test_chip_*() functions to correspond with the
> +        * index passed to the test_chip_*() functions to correspond to the
>          * order in which the chips were defined in the TEST_DEFINE()
>          * macro.
>          *
> --
> 2.24.0
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG
  2019-11-18 13:50 ` [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Bartosz Golaszewski
@ 2019-11-18 14:09   ` Kent Gibson
  2019-11-18 14:55     ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-18 14:09 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Mon, Nov 18, 2019 at 02:50:57PM +0100, Bartosz Golaszewski wrote:
> pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > This patch series adds support for changes to the GPIO uAPI that are on
> > track to be included in the v5.5 kernel.  There are two components to the
> > uAPI changes - the addition of bias flags and a new SET_CONFIG ioctl.  This
> > series adds support to the libgpiod API, and to both C++ and Python
> > bindings, for both of those components.
> >
> > The libgpiod tools are also updated, where appropriate, to support the bias
> > flags.
> >
> > There are a few additional patches that serve to restructure the code to
> > simplify subsequent patches, or to fix minor problems discovered during
> > development. These patches are generally adjacent to the main patch most
> > relevant to that patch.
> >
> > The series is based on the current libgpiod master@9ed02fc.
> >
> > Kent Gibson (19):
> >   core: move request flag to handle flag conversion into a separate
> >     function
> >   API: add support for bias flags
> >   core: fix misspelling of parameter
> >   tests: add tests for bias flags
> >   bindings: cxx: drop noexcept from direction and active_state
> >   bindings: cxx: initialise bitset with integer instead of string
> >   bindings: cxx: add support for bias flags
> >   bindings: cxx: tests: add tests for bias flags
> >   bindings: python: add support for bias flags
> >   bindings: python: tests: add tests for bias flags
> >   API: add support for SET_CONFIG
> >   tests: add tests for SET_CONFIG
> >   core: allow gpiod_line_set_value_bulk to accept null values
> >   bindings: cxx: add support for SET_CONFIG
> >   bindings: cxx: tests: add tests for SET_CONFIG methods
> >   bindings: python: add support for SET_CONFIG
> >   bindings: python: tests: add tests for SET_CONFIG methods
> >   tools: add support for bias flags
> >   treewide: change "correspond with" to "correspond to"
> >
> >  bindings/cxx/gpiod.hpp                 |  85 +++-
> >  bindings/cxx/line.cpp                  |  60 ++-
> >  bindings/cxx/line_bulk.cpp             |  95 ++++-
> >  bindings/cxx/tests/tests-line.cpp      | 215 ++++++++++
> >  bindings/python/gpiodmodule.c          | 469 +++++++++++++++++++++-
> >  bindings/python/tests/gpiod_py_test.py | 254 ++++++++++++
> >  include/gpiod.h                        | 303 +++++++++++++-
> >  lib/core.c                             | 250 ++++++++++--
> >  lib/ctxless.c                          | 115 +++++-
> >  tests/mockup/gpio-mockup.c             |   2 +-
> >  tests/tests-ctxless.c                  |  64 ++-
> >  tests/tests-event.c                    | 120 ++++++
> >  tests/tests-line.c                     | 522 ++++++++++++++++++++++++-
> >  tools/gpioget.c                        |  24 +-
> >  tools/gpiomon.c                        |  28 +-
> >  tools/gpioset.c                        |  26 +-
> >  16 files changed, 2561 insertions(+), 71 deletions(-)
> >
> > --
> > 2.24.0
> >
> 
> Hi Kent,
> 
> the series looks quite good. I addressed some obvious things. I'll
> review v2 more in detail, but honestly, I don't think there'll be a
> lot of issues.
> 
> Would you mind if I applied patches 1, 3, 5, 6, 13 & 19 right away?
> They fix existing problems, so there's no need to carry them over to
> subsequent iterations of the series.
> 

I don't have a problem with that.

Cheers,
Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 02/19] API: add support for bias flags
  2019-11-18 13:51   ` Bartosz Golaszewski
@ 2019-11-18 14:12     ` Kent Gibson
  0 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-18 14:12 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Mon, Nov 18, 2019 at 02:51:06PM +0100, Bartosz Golaszewski wrote:
> pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > Extend the libgpiod API to support the bias flags recently added to the
> > kernel GPIO uAPI.  The core change is the addition of
> > GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE, GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP
> > and GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN flags to be passed into
> > line_request functions, and the addition of gpiod_line_bias to return the
> > bias state of lines.
> >
> > Extended variants of the ctxless functions that accept an active_low flag
> > are added to also accept other flags. The variant names add a "_ext"
> > suffix to the name of the original function.
> >
> > Based on initial work by Drew Fustini <drew@pdp7.com>.
> >
> > Signed-off-by: Kent Gibson <warthog618@gmail.com>
> 
> Hi Kent,
> 
> this looks good, just a couple nits. I'd change the subject line to
> "core: add support for bias flags". Also: how about moving the flags
> argument to the last position in all the ctxless extended variants, so
> that they keep the same signature *except* for the appended new
> argument?
> 

Will do.

Kent.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 04/19] tests: add tests for bias flags
  2019-11-18 13:51   ` Bartosz Golaszewski
@ 2019-11-18 14:14     ` Kent Gibson
  0 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-18 14:14 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Mon, Nov 18, 2019 at 02:51:17PM +0100, Bartosz Golaszewski wrote:
> pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > Extend test coverage over the bias flags, gpiod_line_bias and the extended
> > ctxless functions.
> >
> > Also update existing tests to check bias flags where line state is checked.
> >
> > Signed-off-by: Kent Gibson <warthog618@gmail.com>
> > ---
> >  tests/tests-ctxless.c |  64 +++++++++++++++++++++-
> >  tests/tests-event.c   | 120 ++++++++++++++++++++++++++++++++++++++++++
> >  tests/tests-line.c    |  98 ++++++++++++++++++++++++++++++++++
> >  3 files changed, 280 insertions(+), 2 deletions(-)
> >
> > diff --git a/tests/tests-ctxless.c b/tests/tests-ctxless.c
> > index c1e1ca6..da70587 100644
> > --- a/tests/tests-ctxless.c
> > +++ b/tests/tests-ctxless.c
> > @@ -26,11 +26,41 @@ GPIOD_TEST_CASE(get_value, 0, { 8 })
> >         g_assert_cmpint(ret, ==, 1);
> >  }
> >
> > -static void set_value_check(gpointer data G_GNUC_UNUSED)
> > +GPIOD_TEST_CASE(get_value_ext, 0, { 8 })
> > +{
> > +       gint ret;
> > +
> > +       ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> > +                               false, GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN,
> > +                               GPIOD_TEST_CONSUMER);
> > +       g_assert_cmpint(ret, ==, 0);
> > +
> > +       ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> > +                               false, GPIOD_CTXLESS_FLAG_BIAS_PULL_UP,
> > +                               GPIOD_TEST_CONSUMER);
> > +       g_assert_cmpint(ret, ==, 1);
> > +
> > +       ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> > +                               true, GPIOD_CTXLESS_FLAG_BIAS_PULL_DOWN,
> > +                               GPIOD_TEST_CONSUMER);
> > +       g_assert_cmpint(ret, ==, 1);
> > +
> > +       ret = gpiod_ctxless_get_value_ext(gpiod_test_chip_name(0), 3,
> > +                               true, GPIOD_CTXLESS_FLAG_BIAS_PULL_UP,
> > +                               GPIOD_TEST_CONSUMER);
> > +       g_assert_cmpint(ret, ==, 0);
> > +}
> > +
> > +static void set_value_check_hi(gpointer data G_GNUC_UNUSED)
> >  {
> >         g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
> >  }
> >
> > +static void set_value_check_lo(gpointer data G_GNUC_UNUSED)
> > +{
> > +       g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> > +}
> > +
> >  GPIOD_TEST_CASE(set_value, 0, { 8 })
> >  {
> >         gint ret;
> > @@ -39,13 +69,43 @@ GPIOD_TEST_CASE(set_value, 0, { 8 })
> >
> >         ret = gpiod_ctxless_set_value(gpiod_test_chip_name(0), 3, 1,
> >                                       false, GPIOD_TEST_CONSUMER,
> > -                                     set_value_check, NULL);
> > +                                     set_value_check_hi, NULL);
> >         gpiod_test_return_if_failed();
> >         g_assert_cmpint(ret, ==, 0);
> >
> >         g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> >  }
> >
> > +GPIOD_TEST_CASE(set_value_ext, 0, { 8 })
> > +{
> > +       gint ret;
> > +
> > +       gpiod_test_chip_set_pull(0, 3, 0);
> > +
> > +       ret = gpiod_ctxless_set_value_ext(gpiod_test_chip_name(0), 3, 1,
> > +                       false, 0, GPIOD_TEST_CONSUMER,
> > +                       set_value_check_hi, NULL);
> > +       gpiod_test_return_if_failed();
> > +       g_assert_cmpint(ret, ==, 0);
> > +       g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 0);
> > +
> > +       // test drive flags by checking that sets are caught by emulation
> 
> Nit: don't use C++ comments in libgpiod.
> 

Sorry - old habits.

Kent.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 06/19] bindings: cxx: initialise bitset with integer instead of string
  2019-11-18 13:51   ` Bartosz Golaszewski
@ 2019-11-18 14:17     ` Kent Gibson
  0 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-18 14:17 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Mon, Nov 18, 2019 at 02:51:42PM +0100, Bartosz Golaszewski wrote:
> pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > Initialising bitsets with string is inefficient and confusing.
> > Initialise them with the corresponding int instead.
> >
> 
> I'm not a native English speaker, of course, so correcting you on
> spelling may be risky but I generally try to stick to American
> spelling so "initialise" looks somehow wrong to me. :) Anyway, this is
> just the commit message, so never mind that.
> 

And I speak English, not American, so I didn't even notice.
I will try to keep that in mind though.

Kent.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-18 13:52   ` Bartosz Golaszewski
@ 2019-11-18 14:48     ` Kent Gibson
  2019-11-19 15:52       ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-18 14:48 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski wrote:
> pt., 15 lis 2019 o 15:45 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > 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 | 115 ++++++++++++++++++++++++++++
> >  lib/core.c      | 196 +++++++++++++++++++++++++++++++++++++++++++++---
> >  2 files changed, 300 insertions(+), 11 deletions(-)
> >
> > diff --git a/include/gpiod.h b/include/gpiod.h
> > index 159d745..4053fd2 100644
> > --- a/include/gpiod.h
> > +++ b/include/gpiod.h
> > @@ -1252,6 +1252,14 @@ 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, false otherwise.
> 
> I'd clarify: "requested for reading/setting values".
> 
> > + */
> > +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.
> > @@ -1311,6 +1319,113 @@ 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.
> > + * @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_bulk_input(struct gpiod_line_bulk *bulk
> > +                                       ) GPIOD_API;
> 
> Please stick to the current convention of having "_bulk" at the end of
> the function name.
> 

That would be clearer.  Not sure why I went with those names - maybe
taking the lead from gpiod_line_request_bulk_falling_edge_events_flags?
Maybe I originally had a core set_direction function, and these were to
be wrappers around that?
Anyway - will change it.

> > +
> > +/**
> > + * @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.
> > + * @values The logical value to output for each line.
> > + * @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_bulk_output(struct gpiod_line_bulk *bulk,
> > +                                        const int *values) GPIOD_API;
> > +
> >  /**
> >   * @}
> >   *
> > diff --git a/lib/core.c b/lib/core.c
> > index 9b7d88f..c42cda5 100644
> > --- a/lib/core.c
> > +++ b/lib/core.c
> > @@ -36,10 +36,13 @@ struct gpiod_line {
> >         unsigned int offset;
> >         int direction;
> >         int active_state;
> > -       __u32 flags;
> > +       int output_value;
> > +       __u32 lflags;
> > +       __u32 cflags;
> 
> Ugh, these aren't very fortunate names - at first glance I have no
> idea what they mean. Either document those or change the names to
> something more obvious.
> 

Yeah - not the best - lflags are line_flags (those returned by
LINEINFO_IOCTL) and cflags is config_flags (those set in the initial
line request).  So maybe rename lflags to line_flags or info_flags,
and rename cflags to handle_flags or req_flags?
And add some documentation as well.

> >
> >         int state;
> >         bool needs_update;
> > +       bool as_is;
> >
> >         struct gpiod_chip *chip;
> >         struct line_fd_handle *fd_handle;
> > @@ -359,11 +362,11 @@ int gpiod_line_active_state(struct gpiod_line *line)
> >
> >  int gpiod_line_bias(struct gpiod_line *line)
> >  {
> > -       if (line->flags & GPIOLINE_FLAG_BIAS_DISABLE)
> > +       if (line->lflags & GPIOLINE_FLAG_BIAS_DISABLE)
> >                 return GPIOD_LINE_BIAS_DISABLE;
> > -       if (line->flags & GPIOLINE_FLAG_BIAS_PULL_UP)
> > +       if (line->lflags & GPIOLINE_FLAG_BIAS_PULL_UP)
> >                 return GPIOD_LINE_BIAS_PULL_UP;
> > -       if (line->flags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
> > +       if (line->lflags & GPIOLINE_FLAG_BIAS_PULL_DOWN)
> >                 return GPIOD_LINE_BIAS_PULL_DOWN;
> >
> >         return GPIOD_LINE_BIAS_AS_IS;
> > @@ -371,17 +374,17 @@ int gpiod_line_bias(struct gpiod_line *line)
> >
> >  bool gpiod_line_is_used(struct gpiod_line *line)
> >  {
> > -       return line->flags & GPIOLINE_FLAG_KERNEL;
> > +       return line->lflags & GPIOLINE_FLAG_KERNEL;
> >  }
> >
> >  bool gpiod_line_is_open_drain(struct gpiod_line *line)
> >  {
> > -       return line->flags & GPIOLINE_FLAG_OPEN_DRAIN;
> > +       return line->lflags & GPIOLINE_FLAG_OPEN_DRAIN;
> >  }
> >
> >  bool gpiod_line_is_open_source(struct gpiod_line *line)
> >  {
> > -       return line->flags & GPIOLINE_FLAG_OPEN_SOURCE;
> > +       return line->lflags & GPIOLINE_FLAG_OPEN_SOURCE;
> >  }
> >
> >  bool gpiod_line_needs_update(struct gpiod_line *line)
> > @@ -408,7 +411,7 @@ int gpiod_line_update(struct gpiod_line *line)
> >                                                 ? GPIOD_LINE_ACTIVE_STATE_LOW
> >                                                 : GPIOD_LINE_ACTIVE_STATE_HIGH;
> >
> > -       line->flags = info.flags;
> > +       line->lflags = info.flags;
> >
> >         strncpy(line->name, info.name, sizeof(line->name));
> >         strncpy(line->consumer, info.consumer, sizeof(line->consumer));
> > @@ -457,6 +460,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 +488,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 +533,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 +562,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 +585,14 @@ 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->cflags = config->flags;
> > +               if (config->request_type ==
> > +                       GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
> > +                       line->output_value = req.default_values[i];
> > +               if (config->request_type == GPIOD_LINE_REQUEST_DIRECTION_AS_IS)
> > +                       line->as_is = true;
> >                 line_set_fd(line, line_fd);
> >                 line_maybe_update(line);
> >         }
> > @@ -590,6 +633,7 @@ static int line_request_event_single(struct gpiod_line *line,
> >                 return -1;
> >
> >         line->state = LINE_REQUESTED_EVENTS;
> > +       line->cflags = config->flags;
> >         line_set_fd(line, line_fd);
> >         line_maybe_update(line);
> >
> > @@ -688,6 +732,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 +815,134 @@ 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;
> > +       bool as_is;
> > +
> > +       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;
> > +
> > +       as_is = line->as_is && direction == GPIOD_LINE_REQUEST_DIRECTION_AS_IS;
> > +       gpiod_line_bulk_foreach_line_off(bulk, line, i) {
> > +               line->cflags = flags;
> > +               if (direction == GPIOD_LINE_REQUEST_DIRECTION_OUTPUT)
> > +                       line->output_value = hcfg.default_values[i];
> > +               line->as_is = as_is;
> > +               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->as_is) {
> 
> Can you explain the purpose of this as_is field? I'm not sure this is
> really needed.
> 

It is there for gpiod_set_flags, which has to populate the direction
flags in the SET_CONFIG ioctl. The existing line->direction is
either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
as-is is gets mapped to input.
I didn't want to change the existing line->direction, and adding the
as-is seemed clearer than adding another flavour of direction that
contained all three.

Happy to entertain alternatives...

Cheers,
Kent.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG
  2019-11-18 14:09   ` Kent Gibson
@ 2019-11-18 14:55     ` Bartosz Golaszewski
  0 siblings, 0 replies; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-18 14:55 UTC (permalink / raw)
  To: Kent Gibson; +Cc: linux-gpio

pon., 18 lis 2019 o 15:09 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Mon, Nov 18, 2019 at 02:50:57PM +0100, Bartosz Golaszewski wrote:
> > pt., 15 lis 2019 o 15:44 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > This patch series adds support for changes to the GPIO uAPI that are on
> > > track to be included in the v5.5 kernel.  There are two components to the
> > > uAPI changes - the addition of bias flags and a new SET_CONFIG ioctl.  This
> > > series adds support to the libgpiod API, and to both C++ and Python
> > > bindings, for both of those components.
> > >
> > > The libgpiod tools are also updated, where appropriate, to support the bias
> > > flags.
> > >
> > > There are a few additional patches that serve to restructure the code to
> > > simplify subsequent patches, or to fix minor problems discovered during
> > > development. These patches are generally adjacent to the main patch most
> > > relevant to that patch.
> > >
> > > The series is based on the current libgpiod master@9ed02fc.
> > >
> > > Kent Gibson (19):
> > >   core: move request flag to handle flag conversion into a separate
> > >     function
> > >   API: add support for bias flags
> > >   core: fix misspelling of parameter
> > >   tests: add tests for bias flags
> > >   bindings: cxx: drop noexcept from direction and active_state
> > >   bindings: cxx: initialise bitset with integer instead of string
> > >   bindings: cxx: add support for bias flags
> > >   bindings: cxx: tests: add tests for bias flags
> > >   bindings: python: add support for bias flags
> > >   bindings: python: tests: add tests for bias flags
> > >   API: add support for SET_CONFIG
> > >   tests: add tests for SET_CONFIG
> > >   core: allow gpiod_line_set_value_bulk to accept null values
> > >   bindings: cxx: add support for SET_CONFIG
> > >   bindings: cxx: tests: add tests for SET_CONFIG methods
> > >   bindings: python: add support for SET_CONFIG
> > >   bindings: python: tests: add tests for SET_CONFIG methods
> > >   tools: add support for bias flags
> > >   treewide: change "correspond with" to "correspond to"
> > >
> > >  bindings/cxx/gpiod.hpp                 |  85 +++-
> > >  bindings/cxx/line.cpp                  |  60 ++-
> > >  bindings/cxx/line_bulk.cpp             |  95 ++++-
> > >  bindings/cxx/tests/tests-line.cpp      | 215 ++++++++++
> > >  bindings/python/gpiodmodule.c          | 469 +++++++++++++++++++++-
> > >  bindings/python/tests/gpiod_py_test.py | 254 ++++++++++++
> > >  include/gpiod.h                        | 303 +++++++++++++-
> > >  lib/core.c                             | 250 ++++++++++--
> > >  lib/ctxless.c                          | 115 +++++-
> > >  tests/mockup/gpio-mockup.c             |   2 +-
> > >  tests/tests-ctxless.c                  |  64 ++-
> > >  tests/tests-event.c                    | 120 ++++++
> > >  tests/tests-line.c                     | 522 ++++++++++++++++++++++++-
> > >  tools/gpioget.c                        |  24 +-
> > >  tools/gpiomon.c                        |  28 +-
> > >  tools/gpioset.c                        |  26 +-
> > >  16 files changed, 2561 insertions(+), 71 deletions(-)
> > >
> > > --
> > > 2.24.0
> > >
> >
> > Hi Kent,
> >
> > the series looks quite good. I addressed some obvious things. I'll
> > review v2 more in detail, but honestly, I don't think there'll be a
> > lot of issues.
> >
> > Would you mind if I applied patches 1, 3, 5, 6, 13 & 19 right away?
> > They fix existing problems, so there's no need to carry them over to
> > subsequent iterations of the series.
> >
>
> I don't have a problem with that.
>

Done. You should be able to rebase on top of my master branch. Let's
hope there are no conflicts - I had to fix up a couple details.

Bart

> Cheers,
> Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 19/19] treewide: change "correspond with" to "correspond to"
  2019-11-18 13:52   ` Bartosz Golaszewski
@ 2019-11-18 15:01     ` Kent Gibson
  0 siblings, 0 replies; 58+ messages in thread
From: Kent Gibson @ 2019-11-18 15:01 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Mon, Nov 18, 2019 at 02:52:56PM +0100, Bartosz Golaszewski wrote:
> pt., 15 lis 2019 o 15:45 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > Trivial grammar fix. "correspond with" can mean either being in agreement
> > with, happening at the same time, or communication between parties.
> > "correspond to" is used to mean equivalance, which is the intended use
> > throughout the documentation.
> >
> 
> Thanks for this. I'm not a native English speaker, so if you see any
> other language issues, please let me know, or feel free to fix them.
> 

In general usage you most often see "correspond with" in the
communication sense. Using it in the other senses is rare.
Ironically I wasn't totally sure on the usage without looking it up, but
it felt wrong as it was.  There are one or two cases in the documentation
where the "in agreement with" interpretation might work, but even there
the "correspond to" felt more appropriate to me.

Cheers,
Kent.



^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-18 14:48     ` Kent Gibson
@ 2019-11-19 15:52       ` Kent Gibson
  2019-11-20 11:00         ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-19 15:52 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: linux-gpio

On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > +
> > > +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->as_is) {
> > 
> > Can you explain the purpose of this as_is field? I'm not sure this is
> > really needed.
> > 
> 
> It is there for gpiod_set_flags, which has to populate the direction
> flags in the SET_CONFIG ioctl. The existing line->direction is
> either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> as-is is gets mapped to input.
> I didn't want to change the existing line->direction, and adding the
> as-is seemed clearer than adding another flavour of direction that
> contained all three.
> 

Hmmm, I think I see what you were getting at - the line->direction is the 
direction from the kernel, so it doesn't hurt to use that value to set the
corresponding request flags - even if the original request was as-is??

If that is the case then the line->as_is can be dropped throughout.

Kent.


^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-19 15:52       ` Kent Gibson
@ 2019-11-20 11:00         ` Bartosz Golaszewski
  2019-11-20 13:58           ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-20 11:00 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > +
> > > > +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->as_is) {
> > >
> > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > really needed.
> > >
> >
> > It is there for gpiod_set_flags, which has to populate the direction
> > flags in the SET_CONFIG ioctl. The existing line->direction is
> > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > as-is is gets mapped to input.
> > I didn't want to change the existing line->direction, and adding the
> > as-is seemed clearer than adding another flavour of direction that
> > contained all three.
> >
>
> Hmmm, I think I see what you were getting at - the line->direction is the
> direction from the kernel, so it doesn't hurt to use that value to set the
> corresponding request flags - even if the original request was as-is??
>
> If that is the case then the line->as_is can be dropped throughout.
>
> Kent.
>

Yes, this is what I was thinking. Just need to make sure the value
from the kernel is up-to-date.

Bart

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-20 11:00         ` Bartosz Golaszewski
@ 2019-11-20 13:58           ` Kent Gibson
  2019-11-20 14:08             ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-20 13:58 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > +
> > > > > +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->as_is) {
> > > >
> > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > really needed.
> > > >
> > >
> > > It is there for gpiod_set_flags, which has to populate the direction
> > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > as-is is gets mapped to input.
> > > I didn't want to change the existing line->direction, and adding the
> > > as-is seemed clearer than adding another flavour of direction that
> > > contained all three.
> > >
> >
> > Hmmm, I think I see what you were getting at - the line->direction is the
> > direction from the kernel, so it doesn't hurt to use that value to set the
> > corresponding request flags - even if the original request was as-is??
> >
> > If that is the case then the line->as_is can be dropped throughout.
> >
> > Kent.
> >
> 
> Yes, this is what I was thinking. Just need to make sure the value
> from the kernel is up-to-date.
> 

So fail if needs_update?

Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-20 13:58           ` Kent Gibson
@ 2019-11-20 14:08             ` Bartosz Golaszewski
  2019-11-20 14:13               ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-20 14:08 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > +
> > > > > > +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->as_is) {
> > > > >
> > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > really needed.
> > > > >
> > > >
> > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > as-is is gets mapped to input.
> > > > I didn't want to change the existing line->direction, and adding the
> > > > as-is seemed clearer than adding another flavour of direction that
> > > > contained all three.
> > > >
> > >
> > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > corresponding request flags - even if the original request was as-is??
> > >
> > > If that is the case then the line->as_is can be dropped throughout.
> > >
> > > Kent.
> > >
> >
> > Yes, this is what I was thinking. Just need to make sure the value
> > from the kernel is up-to-date.
> >
>
> So fail if needs_update?
>
> Kent.

I'd say: do an implicit update before setting config.

Bart

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-20 14:08             ` Bartosz Golaszewski
@ 2019-11-20 14:13               ` Kent Gibson
  2019-11-20 14:18                 ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-20 14:13 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > +
> > > > > > > +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->as_is) {
> > > > > >
> > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > really needed.
> > > > > >
> > > > >
> > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > as-is is gets mapped to input.
> > > > > I didn't want to change the existing line->direction, and adding the
> > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > contained all three.
> > > > >
> > > >
> > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > corresponding request flags - even if the original request was as-is??
> > > >
> > > > If that is the case then the line->as_is can be dropped throughout.
> > > >
> > > > Kent.
> > > >
> > >
> > > Yes, this is what I was thinking. Just need to make sure the value
> > > from the kernel is up-to-date.
> > >
> >
> > So fail if needs_update?
> >
> > Kent.
> 
> I'd say: do an implicit update before setting config.
> 

So gpiod_line_update if needs_update, and fail if that fails?

Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-20 14:13               ` Kent Gibson
@ 2019-11-20 14:18                 ` Bartosz Golaszewski
  2019-11-20 14:36                   ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-20 14:18 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > >
> > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > +
> > > > > > > > +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->as_is) {
> > > > > > >
> > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > really needed.
> > > > > > >
> > > > > >
> > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > as-is is gets mapped to input.
> > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > contained all three.
> > > > > >
> > > > >
> > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > corresponding request flags - even if the original request was as-is??
> > > > >
> > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > >
> > > > > Kent.
> > > > >
> > > >
> > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > from the kernel is up-to-date.
> > > >
> > >
> > > So fail if needs_update?
> > >
> > > Kent.
> >
> > I'd say: do an implicit update before setting config.
> >
>
> So gpiod_line_update if needs_update, and fail if that fails?
>
> Kent.

Without the if - needs_update is only set if an implicit update fails
in line_maybe_update(). But in this case we need to be sure, so do it
unconditionally.

Bart

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-20 14:18                 ` Bartosz Golaszewski
@ 2019-11-20 14:36                   ` Kent Gibson
  2019-11-20 15:18                     ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-20 14:36 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > >
> > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > +
> > > > > > > > > +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->as_is) {
> > > > > > > >
> > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > really needed.
> > > > > > > >
> > > > > > >
> > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > as-is is gets mapped to input.
> > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > contained all three.
> > > > > > >
> > > > > >
> > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > corresponding request flags - even if the original request was as-is??
> > > > > >
> > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > >
> > > > > > Kent.
> > > > > >
> > > > >
> > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > from the kernel is up-to-date.
> > > > >
> > > >
> > > > So fail if needs_update?
> > > >
> > > > Kent.
> > >
> > > I'd say: do an implicit update before setting config.
> > >
> >
> > So gpiod_line_update if needs_update, and fail if that fails?
> >
> > Kent.
> 
> Without the if - needs_update is only set if an implicit update fails
> in line_maybe_update(). But in this case we need to be sure, so do it
> unconditionally.
> 

Given that line_maybe_update is called at the end of request creation, and
whenever set_config is called, how can line->direction be inconsistent
with the kernel state - as long as needs_update is false?

Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-20 14:36                   ` Kent Gibson
@ 2019-11-20 15:18                     ` Bartosz Golaszewski
  2019-11-21  0:34                       ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-20 15:18 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > >
> > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > >
> > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > +
> > > > > > > > > > +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->as_is) {
> > > > > > > > >
> > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > really needed.
> > > > > > > > >
> > > > > > > >
> > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > as-is is gets mapped to input.
> > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > contained all three.
> > > > > > > >
> > > > > > >
> > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > >
> > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > >
> > > > > > > Kent.
> > > > > > >
> > > > > >
> > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > from the kernel is up-to-date.
> > > > > >
> > > > >
> > > > > So fail if needs_update?
> > > > >
> > > > > Kent.
> > > >
> > > > I'd say: do an implicit update before setting config.
> > > >
> > >
> > > So gpiod_line_update if needs_update, and fail if that fails?
> > >
> > > Kent.
> >
> > Without the if - needs_update is only set if an implicit update fails
> > in line_maybe_update(). But in this case we need to be sure, so do it
> > unconditionally.
> >
>
> Given that line_maybe_update is called at the end of request creation, and
> whenever set_config is called, how can line->direction be inconsistent
> with the kernel state - as long as needs_update is false?
>

I don't think we should call line_maybe_update() on set_config() - in
this case we should call gpiod_line_update() and fail in set_config()
if it fails.

I hope that's clearer.

Bart

> Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-20 15:18                     ` Bartosz Golaszewski
@ 2019-11-21  0:34                       ` Kent Gibson
  2019-11-21  7:13                         ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-21  0:34 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > >
> > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > >
> > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > +
> > > > > > > > > > > +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->as_is) {
> > > > > > > > > >
> > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > really needed.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > contained all three.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > >
> > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > >
> > > > > > > > Kent.
> > > > > > > >
> > > > > > >
> > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > from the kernel is up-to-date.
> > > > > > >
> > > > > >
> > > > > > So fail if needs_update?
> > > > > >
> > > > > > Kent.
> > > > >
> > > > > I'd say: do an implicit update before setting config.
> > > > >
> > > >
> > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > >
> > > > Kent.
> > >
> > > Without the if - needs_update is only set if an implicit update fails
> > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > unconditionally.
> > >
> >
> > Given that line_maybe_update is called at the end of request creation, and
> > whenever set_config is called, how can line->direction be inconsistent
> > with the kernel state - as long as needs_update is false?
> >
> 
> I don't think we should call line_maybe_update() on set_config() - in
> this case we should call gpiod_line_update() and fail in set_config()
> if it fails.
> 
> I hope that's clearer.
> 

Not really.  I was already shaky on the needs_update and I'm getting more
confused about the overall needs_update handling policy by the minute.

Perhaps it will be more productive to go to the code.
I'll send out what I have as v2 and we can go from there.

Cheers,
Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21  0:34                       ` Kent Gibson
@ 2019-11-21  7:13                         ` Bartosz Golaszewski
  2019-11-21  7:46                           ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-21  7:13 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > >
> > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > >
> > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > >
> > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > +
> > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > >
> > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > really needed.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > contained all three.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > >
> > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > >
> > > > > > > > > Kent.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > from the kernel is up-to-date.
> > > > > > > >
> > > > > > >
> > > > > > > So fail if needs_update?
> > > > > > >
> > > > > > > Kent.
> > > > > >
> > > > > > I'd say: do an implicit update before setting config.
> > > > > >
> > > > >
> > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > >
> > > > > Kent.
> > > >
> > > > Without the if - needs_update is only set if an implicit update fails
> > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > unconditionally.
> > > >
> > >
> > > Given that line_maybe_update is called at the end of request creation, and
> > > whenever set_config is called, how can line->direction be inconsistent
> > > with the kernel state - as long as needs_update is false?
> > >
> >
> > I don't think we should call line_maybe_update() on set_config() - in
> > this case we should call gpiod_line_update() and fail in set_config()
> > if it fails.
> >
> > I hope that's clearer.
> >
>
> Not really.  I was already shaky on the needs_update and I'm getting more
> confused about the overall needs_update handling policy by the minute.
>

Yeah it's not optimal. If you have better ideas on how to handle the
fact that the kernel can't really notify us about the changes in
line's flags introduced by other processes - I'll be more than glad to
give them a try. At some point I was thinking about another ioctl()
that - for a requested line - would return a file descriptor which
would emit events when a line changes - for instance, it's requested
by someone else or its direction is changed etc.

I then thought that nobody is requesting this yet and so it may be overkill.

Bart

> Perhaps it will be more productive to go to the code.
> I'll send out what I have as v2 and we can go from there.
>
> Cheers,
> Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21  7:13                         ` Bartosz Golaszewski
@ 2019-11-21  7:46                           ` Kent Gibson
  2019-11-21  8:46                             ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-21  7:46 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > >
> > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > >
> > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > >
> > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > +
> > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > >
> > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > really needed.
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > contained all three.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > >
> > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > >
> > > > > > > > > > Kent.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > from the kernel is up-to-date.
> > > > > > > > >
> > > > > > > >
> > > > > > > > So fail if needs_update?
> > > > > > > >
> > > > > > > > Kent.
> > > > > > >
> > > > > > > I'd say: do an implicit update before setting config.
> > > > > > >
> > > > > >
> > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > >
> > > > > > Kent.
> > > > >
> > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > unconditionally.
> > > > >
> > > >
> > > > Given that line_maybe_update is called at the end of request creation, and
> > > > whenever set_config is called, how can line->direction be inconsistent
> > > > with the kernel state - as long as needs_update is false?
> > > >
> > >
> > > I don't think we should call line_maybe_update() on set_config() - in
> > > this case we should call gpiod_line_update() and fail in set_config()
> > > if it fails.
> > >
> > > I hope that's clearer.
> > >
> >
> > Not really.  I was already shaky on the needs_update and I'm getting more
> > confused about the overall needs_update handling policy by the minute.
> >
> 
> Yeah it's not optimal. If you have better ideas on how to handle the
> fact that the kernel can't really notify us about the changes in
> line's flags introduced by other processes - I'll be more than glad to
> give them a try. At some point I was thinking about another ioctl()
> that - for a requested line - would return a file descriptor which
> would emit events when a line changes - for instance, it's requested
> by someone else or its direction is changed etc.
> 

I didn't realise it was possible for a requested line's flags to be
changed by other processes.  Quite the opposite - I thought that was one
of the reasons for GPIOD was to allow the userspace to prevent other from
processes messing with requested lines.

Kent.

> I then thought that nobody is requesting this yet and so it may be overkill.
> 
> Bart
> 
> > Perhaps it will be more productive to go to the code.
> > I'll send out what I have as v2 and we can go from there.
> >
> > Cheers,
> > Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21  7:46                           ` Kent Gibson
@ 2019-11-21  8:46                             ` Bartosz Golaszewski
  2019-11-21  9:30                               ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-21  8:46 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > >
> > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > >
> > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > >
> > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > >
> > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > +
> > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > >
> > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > really needed.
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > contained all three.
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > >
> > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > >
> > > > > > > > > > > Kent.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > So fail if needs_update?
> > > > > > > > >
> > > > > > > > > Kent.
> > > > > > > >
> > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > >
> > > > > > >
> > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > >
> > > > > > > Kent.
> > > > > >
> > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > unconditionally.
> > > > > >
> > > > >
> > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > with the kernel state - as long as needs_update is false?
> > > > >
> > > >
> > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > if it fails.
> > > >
> > > > I hope that's clearer.
> > > >
> > >
> > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > confused about the overall needs_update handling policy by the minute.
> > >
> >
> > Yeah it's not optimal. If you have better ideas on how to handle the
> > fact that the kernel can't really notify us about the changes in
> > line's flags introduced by other processes - I'll be more than glad to
> > give them a try. At some point I was thinking about another ioctl()
> > that - for a requested line - would return a file descriptor which
> > would emit events when a line changes - for instance, it's requested
> > by someone else or its direction is changed etc.
> >
>
> I didn't realise it was possible for a requested line's flags to be
> changed by other processes.  Quite the opposite - I thought that was one
> of the reasons for GPIOD was to allow the userspace to prevent other from
> processes messing with requested lines.
>

Ugh, sorry, was writing it before coffee. I was thinking about a
non-requested line. Something like lineinfo ioctl() but returning an
fd notifying about changes. Maybe we could even consider having
lineinfo2 ioctl() which would be extended with this functionality -
not only would it fill the relevant structure but also pass a new fd
for notification about changes.

Bart

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21  8:46                             ` Bartosz Golaszewski
@ 2019-11-21  9:30                               ` Kent Gibson
  2019-11-21 10:03                                 ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-21  9:30 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > >
> > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > >
> > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > >
> > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > >
> > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > >
> > > > > > > > > > > > >
> > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > >
> > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > >
> > > > > > > > > > > > Kent.
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > So fail if needs_update?
> > > > > > > > > >
> > > > > > > > > > Kent.
> > > > > > > > >
> > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > >
> > > > > > > >
> > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > >
> > > > > > > > Kent.
> > > > > > >
> > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > unconditionally.
> > > > > > >
> > > > > >
> > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > with the kernel state - as long as needs_update is false?
> > > > > >
> > > > >
> > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > if it fails.
> > > > >
> > > > > I hope that's clearer.
> > > > >
> > > >
> > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > confused about the overall needs_update handling policy by the minute.
> > > >
> > >
> > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > fact that the kernel can't really notify us about the changes in
> > > line's flags introduced by other processes - I'll be more than glad to
> > > give them a try. At some point I was thinking about another ioctl()
> > > that - for a requested line - would return a file descriptor which
> > > would emit events when a line changes - for instance, it's requested
> > > by someone else or its direction is changed etc.
> > >
> >
> > I didn't realise it was possible for a requested line's flags to be
> > changed by other processes.  Quite the opposite - I thought that was one
> > of the reasons for GPIOD was to allow the userspace to prevent other from
> > processes messing with requested lines.
> >
> 
> Ugh, sorry, was writing it before coffee. I was thinking about a
> non-requested line. Something like lineinfo ioctl() but returning an
> fd notifying about changes. Maybe we could even consider having
> lineinfo2 ioctl() which would be extended with this functionality -
> not only would it fill the relevant structure but also pass a new fd
> for notification about changes.
> 

Whew - that makes more sense. Had me worried there.

Not sure how useful an async info ioctl would be.  Couldn't you build
something equivalent in userspace with the existing API - as long as you
don't mind the daemon holding the line, and so having to control the
line via the daemon.  You want to be able to monitor without requesting
the line?

I'm still puzzled as to when the existing info ioctl could fail on a
requested line - which is when needs_update gets set in
line_maybe_update().  Hardware being unplugged?

Cheers,
Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21  9:30                               ` Kent Gibson
@ 2019-11-21 10:03                                 ` Bartosz Golaszewski
  2019-11-21 10:18                                   ` Kent Gibson
  0 siblings, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-21 10:03 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

czw., 21 lis 2019 o 10:30 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> > czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > >
> > > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > >
> > > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > >
> > > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > >
> > > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > >
> > > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > > >
> > > > > > > > > > > > >
> > > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > > >
> > > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > > >
> > > > > > > > > > > > > Kent.
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > So fail if needs_update?
> > > > > > > > > > >
> > > > > > > > > > > Kent.
> > > > > > > > > >
> > > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > > >
> > > > > > > > > Kent.
> > > > > > > >
> > > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > > unconditionally.
> > > > > > > >
> > > > > > >
> > > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > > with the kernel state - as long as needs_update is false?
> > > > > > >
> > > > > >
> > > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > > if it fails.
> > > > > >
> > > > > > I hope that's clearer.
> > > > > >
> > > > >
> > > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > > confused about the overall needs_update handling policy by the minute.
> > > > >
> > > >
> > > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > > fact that the kernel can't really notify us about the changes in
> > > > line's flags introduced by other processes - I'll be more than glad to
> > > > give them a try. At some point I was thinking about another ioctl()
> > > > that - for a requested line - would return a file descriptor which
> > > > would emit events when a line changes - for instance, it's requested
> > > > by someone else or its direction is changed etc.
> > > >
> > >
> > > I didn't realise it was possible for a requested line's flags to be
> > > changed by other processes.  Quite the opposite - I thought that was one
> > > of the reasons for GPIOD was to allow the userspace to prevent other from
> > > processes messing with requested lines.
> > >
> >
> > Ugh, sorry, was writing it before coffee. I was thinking about a
> > non-requested line. Something like lineinfo ioctl() but returning an
> > fd notifying about changes. Maybe we could even consider having
> > lineinfo2 ioctl() which would be extended with this functionality -
> > not only would it fill the relevant structure but also pass a new fd
> > for notification about changes.
> >
>
> Whew - that makes more sense. Had me worried there.
>
> Not sure how useful an async info ioctl would be.  Couldn't you build
> something equivalent in userspace with the existing API - as long as you
> don't mind the daemon holding the line, and so having to control the
> line via the daemon.  You want to be able to monitor without requesting
> the line?
>

I'm not sure if I was expressing myself clearly enough: a hypothetical
daemon calls LINEINFO ioctl(). Now a different program or kernel
driver requests this line. The daemon is not up-to-date on its state
unless it polls the line all the time. If a user now asks the daemon
about this line's state - it will be given outdated info. Listening on
this fd would allow us to be informed about such changes immediately.

> I'm still puzzled as to when the existing info ioctl could fail on a
> requested line - which is when needs_update gets set in
> line_maybe_update().  Hardware being unplugged?
>

If the ioctl() can fail, then we're obligated to check the return
value. As you say: unplugging the device is a good example - it may be
a GPIO expander on an HID device (e.g. Silicon Labs CP2112) that can
be easily disconnected from USB.

Bart

> Cheers,
> Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21 10:03                                 ` Bartosz Golaszewski
@ 2019-11-21 10:18                                   ` Kent Gibson
  2019-11-21 10:27                                     ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-21 10:18 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Thu, Nov 21, 2019 at 11:03:32AM +0100, Bartosz Golaszewski wrote:
> czw., 21 lis 2019 o 10:30 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> > > czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > >
> > > > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > >
> > > > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > >
> > > > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > >
> > > > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > >
> > > > > > > > > > > > >
> > > > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > So fail if needs_update?
> > > > > > > > > > > >
> > > > > > > > > > > > Kent.
> > > > > > > > > > >
> > > > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > > > >
> > > > > > > > > > Kent.
> > > > > > > > >
> > > > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > > > unconditionally.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > > > with the kernel state - as long as needs_update is false?
> > > > > > > >
> > > > > > >
> > > > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > > > if it fails.
> > > > > > >
> > > > > > > I hope that's clearer.
> > > > > > >
> > > > > >
> > > > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > > > confused about the overall needs_update handling policy by the minute.
> > > > > >
> > > > >
> > > > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > > > fact that the kernel can't really notify us about the changes in
> > > > > line's flags introduced by other processes - I'll be more than glad to
> > > > > give them a try. At some point I was thinking about another ioctl()
> > > > > that - for a requested line - would return a file descriptor which
> > > > > would emit events when a line changes - for instance, it's requested
> > > > > by someone else or its direction is changed etc.
> > > > >
> > > >
> > > > I didn't realise it was possible for a requested line's flags to be
> > > > changed by other processes.  Quite the opposite - I thought that was one
> > > > of the reasons for GPIOD was to allow the userspace to prevent other from
> > > > processes messing with requested lines.
> > > >
> > >
> > > Ugh, sorry, was writing it before coffee. I was thinking about a
> > > non-requested line. Something like lineinfo ioctl() but returning an
> > > fd notifying about changes. Maybe we could even consider having
> > > lineinfo2 ioctl() which would be extended with this functionality -
> > > not only would it fill the relevant structure but also pass a new fd
> > > for notification about changes.
> > >
> >
> > Whew - that makes more sense. Had me worried there.
> >
> > Not sure how useful an async info ioctl would be.  Couldn't you build
> > something equivalent in userspace with the existing API - as long as you
> > don't mind the daemon holding the line, and so having to control the
> > line via the daemon.  You want to be able to monitor without requesting
> > the line?
> >
> 
> I'm not sure if I was expressing myself clearly enough: a hypothetical
> daemon calls LINEINFO ioctl(). Now a different program or kernel
> driver requests this line. The daemon is not up-to-date on its state
> unless it polls the line all the time. If a user now asks the daemon
> about this line's state - it will be given outdated info. Listening on
> this fd would allow us to be informed about such changes immediately.
> 

I think I understand you - but you might not be getting my meaning...
I was thinking the daemon would request the lines it wanted to monitor
- which is why you would then have to control the line via the daemon.
The daemon then always knows the state of the line.
That obviously isn't the case if you want to monitor a line without
requesting it, hence the "You want to be able to monitor without requesting
the line?" question.


> > I'm still puzzled as to when the existing info ioctl could fail on a
> > requested line - which is when needs_update gets set in
> > line_maybe_update().  Hardware being unplugged?
> >
> 
> If the ioctl() can fail, then we're obligated to check the return
> value. As you say: unplugging the device is a good example - it may be
> a GPIO expander on an HID device (e.g. Silicon Labs CP2112) that can
> be easily disconnected from USB.
> 

Fair enough. But for failures of that scale shouldn't the line request
fail - rather than just setting needs_update?  Or are there less
catastrohpic failure modes?

Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21 10:18                                   ` Kent Gibson
@ 2019-11-21 10:27                                     ` Bartosz Golaszewski
  2019-11-21 10:31                                       ` Bartosz Golaszewski
  2019-11-21 10:59                                       ` Kent Gibson
  0 siblings, 2 replies; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-21 10:27 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

czw., 21 lis 2019 o 11:18 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Thu, Nov 21, 2019 at 11:03:32AM +0100, Bartosz Golaszewski wrote:
> > czw., 21 lis 2019 o 10:30 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> > > > czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > >
> > > > > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > > > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > >
> > > > > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > >
> > > > > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > >
> > > > > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > >
> > > > > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > > > > >
> > > > > > > > > > > > >
> > > > > > > > > > > > > So fail if needs_update?
> > > > > > > > > > > > >
> > > > > > > > > > > > > Kent.
> > > > > > > > > > > >
> > > > > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > > > > >
> > > > > > > > > > > Kent.
> > > > > > > > > >
> > > > > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > > > > unconditionally.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > > > > with the kernel state - as long as needs_update is false?
> > > > > > > > >
> > > > > > > >
> > > > > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > > > > if it fails.
> > > > > > > >
> > > > > > > > I hope that's clearer.
> > > > > > > >
> > > > > > >
> > > > > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > > > > confused about the overall needs_update handling policy by the minute.
> > > > > > >
> > > > > >
> > > > > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > > > > fact that the kernel can't really notify us about the changes in
> > > > > > line's flags introduced by other processes - I'll be more than glad to
> > > > > > give them a try. At some point I was thinking about another ioctl()
> > > > > > that - for a requested line - would return a file descriptor which
> > > > > > would emit events when a line changes - for instance, it's requested
> > > > > > by someone else or its direction is changed etc.
> > > > > >
> > > > >
> > > > > I didn't realise it was possible for a requested line's flags to be
> > > > > changed by other processes.  Quite the opposite - I thought that was one
> > > > > of the reasons for GPIOD was to allow the userspace to prevent other from
> > > > > processes messing with requested lines.
> > > > >
> > > >
> > > > Ugh, sorry, was writing it before coffee. I was thinking about a
> > > > non-requested line. Something like lineinfo ioctl() but returning an
> > > > fd notifying about changes. Maybe we could even consider having
> > > > lineinfo2 ioctl() which would be extended with this functionality -
> > > > not only would it fill the relevant structure but also pass a new fd
> > > > for notification about changes.
> > > >
> > >
> > > Whew - that makes more sense. Had me worried there.
> > >
> > > Not sure how useful an async info ioctl would be.  Couldn't you build
> > > something equivalent in userspace with the existing API - as long as you
> > > don't mind the daemon holding the line, and so having to control the
> > > line via the daemon.  You want to be able to monitor without requesting
> > > the line?
> > >
> >
> > I'm not sure if I was expressing myself clearly enough: a hypothetical
> > daemon calls LINEINFO ioctl(). Now a different program or kernel
> > driver requests this line. The daemon is not up-to-date on its state
> > unless it polls the line all the time. If a user now asks the daemon
> > about this line's state - it will be given outdated info. Listening on
> > this fd would allow us to be informed about such changes immediately.
> >
>
> I think I understand you - but you might not be getting my meaning...
> I was thinking the daemon would request the lines it wanted to monitor
> - which is why you would then have to control the line via the daemon.

No, I don't think requesting the line should be obligatory. In my WiP
dbus daemon, I expose line info for all lines in the system by reading
LINEINFO for each one. Then - for unrequested lines - every time the
client asks for any line info again - I call gpiod_line_update()
before responding. This could be optimized by this lineinfo fd
feature.

I don't want to force the user-space to choose between using a single
central daemon or dealing with lines separately.

> The daemon then always knows the state of the line.
> That obviously isn't the case if you want to monitor a line without
> requesting it, hence the "You want to be able to monitor without requesting
> the line?" question.
>

In other words: yes.

>
> > > I'm still puzzled as to when the existing info ioctl could fail on a
> > > requested line - which is when needs_update gets set in
> > > line_maybe_update().  Hardware being unplugged?
> > >
> >
> > If the ioctl() can fail, then we're obligated to check the return
> > value. As you say: unplugging the device is a good example - it may be
> > a GPIO expander on an HID device (e.g. Silicon Labs CP2112) that can
> > be easily disconnected from USB.
> >
>
> Fair enough. But for failures of that scale shouldn't the line request
> fail - rather than just setting needs_update?  Or are there less
> catastrohpic failure modes?
>

What if the disconnect happens after the request but before the
update? It's super unlikely, but again: the lineinfo ioctl() can fail,
so we need to check the return value. We also can't update line info
before requesting the line as it's racy - someone can change the state
between the update and the request.

(I hope I'm getting this right :))

Bart

> Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21 10:27                                     ` Bartosz Golaszewski
@ 2019-11-21 10:31                                       ` Bartosz Golaszewski
  2019-11-21 11:07                                         ` Kent Gibson
  2019-11-21 10:59                                       ` Kent Gibson
  1 sibling, 1 reply; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-21 10:31 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Kent Gibson, linux-gpio

czw., 21 lis 2019 o 11:27 Bartosz Golaszewski <brgl@bgdev.pl> napisał(a):
>
> czw., 21 lis 2019 o 11:18 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Thu, Nov 21, 2019 at 11:03:32AM +0100, Bartosz Golaszewski wrote:
> > > czw., 21 lis 2019 o 10:30 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> > > > > czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > >
> > > > > > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > > > > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > >
> > > > > > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > >
> > > > > > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > >
> > > > > > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > So fail if needs_update?
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > >
> > > > > > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > > > > > >
> > > > > > > > > > > > Kent.
> > > > > > > > > > >
> > > > > > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > > > > > unconditionally.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > > > > > with the kernel state - as long as needs_update is false?
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > > > > > if it fails.
> > > > > > > > >
> > > > > > > > > I hope that's clearer.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > > > > > confused about the overall needs_update handling policy by the minute.
> > > > > > > >
> > > > > > >
> > > > > > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > > > > > fact that the kernel can't really notify us about the changes in
> > > > > > > line's flags introduced by other processes - I'll be more than glad to
> > > > > > > give them a try. At some point I was thinking about another ioctl()
> > > > > > > that - for a requested line - would return a file descriptor which
> > > > > > > would emit events when a line changes - for instance, it's requested
> > > > > > > by someone else or its direction is changed etc.
> > > > > > >
> > > > > >
> > > > > > I didn't realise it was possible for a requested line's flags to be
> > > > > > changed by other processes.  Quite the opposite - I thought that was one
> > > > > > of the reasons for GPIOD was to allow the userspace to prevent other from
> > > > > > processes messing with requested lines.
> > > > > >
> > > > >
> > > > > Ugh, sorry, was writing it before coffee. I was thinking about a
> > > > > non-requested line. Something like lineinfo ioctl() but returning an
> > > > > fd notifying about changes. Maybe we could even consider having
> > > > > lineinfo2 ioctl() which would be extended with this functionality -
> > > > > not only would it fill the relevant structure but also pass a new fd
> > > > > for notification about changes.
> > > > >
> > > >
> > > > Whew - that makes more sense. Had me worried there.
> > > >
> > > > Not sure how useful an async info ioctl would be.  Couldn't you build
> > > > something equivalent in userspace with the existing API - as long as you
> > > > don't mind the daemon holding the line, and so having to control the
> > > > line via the daemon.  You want to be able to monitor without requesting
> > > > the line?
> > > >
> > >
> > > I'm not sure if I was expressing myself clearly enough: a hypothetical
> > > daemon calls LINEINFO ioctl(). Now a different program or kernel
> > > driver requests this line. The daemon is not up-to-date on its state
> > > unless it polls the line all the time. If a user now asks the daemon
> > > about this line's state - it will be given outdated info. Listening on
> > > this fd would allow us to be informed about such changes immediately.
> > >
> >
> > I think I understand you - but you might not be getting my meaning...
> > I was thinking the daemon would request the lines it wanted to monitor
> > - which is why you would then have to control the line via the daemon.
>
> No, I don't think requesting the line should be obligatory. In my WiP
> dbus daemon, I expose line info for all lines in the system by reading
> LINEINFO for each one. Then - for unrequested lines - every time the
> client asks for any line info again - I call gpiod_line_update()
> before responding. This could be optimized by this lineinfo fd
> feature.
>
> I don't want to force the user-space to choose between using a single
> central daemon or dealing with lines separately.
>
> > The daemon then always knows the state of the line.
> > That obviously isn't the case if you want to monitor a line without
> > requesting it, hence the "You want to be able to monitor without requesting
> > the line?" question.
> >
>
> In other words: yes.
>

Just to be clear: I mean line info - not values or events. By
monitoring I mean: be notified about changes to the line properties
without requesting it.

As for implementation: I imagine an ioctl() called LINEINFO_FD that
would return an open file descriptor on which read events would arrive
when the line properties change and then we could call regular line
info ioctl() to actually re-read it. Does that make sense? I can try
to prepare an example implementation.

Bart

> >
> > > > I'm still puzzled as to when the existing info ioctl could fail on a
> > > > requested line - which is when needs_update gets set in
> > > > line_maybe_update().  Hardware being unplugged?
> > > >
> > >
> > > If the ioctl() can fail, then we're obligated to check the return
> > > value. As you say: unplugging the device is a good example - it may be
> > > a GPIO expander on an HID device (e.g. Silicon Labs CP2112) that can
> > > be easily disconnected from USB.
> > >
> >
> > Fair enough. But for failures of that scale shouldn't the line request
> > fail - rather than just setting needs_update?  Or are there less
> > catastrohpic failure modes?
> >
>
> What if the disconnect happens after the request but before the
> update? It's super unlikely, but again: the lineinfo ioctl() can fail,
> so we need to check the return value. We also can't update line info
> before requesting the line as it's racy - someone can change the state
> between the update and the request.
>
> (I hope I'm getting this right :))
>
> Bart
>
> > Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21 10:27                                     ` Bartosz Golaszewski
  2019-11-21 10:31                                       ` Bartosz Golaszewski
@ 2019-11-21 10:59                                       ` Kent Gibson
  2019-11-21 15:20                                         ` Bartosz Golaszewski
  1 sibling, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-21 10:59 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Thu, Nov 21, 2019 at 11:27:10AM +0100, Bartosz Golaszewski wrote:
> czw., 21 lis 2019 o 11:18 Kent Gibson <warthog618@gmail.com> napisał(a):
> >
> > On Thu, Nov 21, 2019 at 11:03:32AM +0100, Bartosz Golaszewski wrote:
> > > czw., 21 lis 2019 o 10:30 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> > > > > czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > >
> > > > > > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > > > > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > >
> > > > > > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > >
> > > > > > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > >
> > > > > > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > So fail if needs_update?
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > >
> > > > > > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > > > > > >
> > > > > > > > > > > > Kent.
> > > > > > > > > > >
> > > > > > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > > > > > unconditionally.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > > > > > with the kernel state - as long as needs_update is false?
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > > > > > if it fails.
> > > > > > > > >
> > > > > > > > > I hope that's clearer.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > > > > > confused about the overall needs_update handling policy by the minute.
> > > > > > > >
> > > > > > >
> > > > > > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > > > > > fact that the kernel can't really notify us about the changes in
> > > > > > > line's flags introduced by other processes - I'll be more than glad to
> > > > > > > give them a try. At some point I was thinking about another ioctl()
> > > > > > > that - for a requested line - would return a file descriptor which
> > > > > > > would emit events when a line changes - for instance, it's requested
> > > > > > > by someone else or its direction is changed etc.
> > > > > > >
> > > > > >
> > > > > > I didn't realise it was possible for a requested line's flags to be
> > > > > > changed by other processes.  Quite the opposite - I thought that was one
> > > > > > of the reasons for GPIOD was to allow the userspace to prevent other from
> > > > > > processes messing with requested lines.
> > > > > >
> > > > >
> > > > > Ugh, sorry, was writing it before coffee. I was thinking about a
> > > > > non-requested line. Something like lineinfo ioctl() but returning an
> > > > > fd notifying about changes. Maybe we could even consider having
> > > > > lineinfo2 ioctl() which would be extended with this functionality -
> > > > > not only would it fill the relevant structure but also pass a new fd
> > > > > for notification about changes.
> > > > >
> > > >
> > > > Whew - that makes more sense. Had me worried there.
> > > >
> > > > Not sure how useful an async info ioctl would be.  Couldn't you build
> > > > something equivalent in userspace with the existing API - as long as you
> > > > don't mind the daemon holding the line, and so having to control the
> > > > line via the daemon.  You want to be able to monitor without requesting
> > > > the line?
> > > >
> > >
> > > I'm not sure if I was expressing myself clearly enough: a hypothetical
> > > daemon calls LINEINFO ioctl(). Now a different program or kernel
> > > driver requests this line. The daemon is not up-to-date on its state
> > > unless it polls the line all the time. If a user now asks the daemon
> > > about this line's state - it will be given outdated info. Listening on
> > > this fd would allow us to be informed about such changes immediately.
> > >
> >
> > I think I understand you - but you might not be getting my meaning...
> > I was thinking the daemon would request the lines it wanted to monitor
> > - which is why you would then have to control the line via the daemon.
> 
> No, I don't think requesting the line should be obligatory. In my WiP
> dbus daemon, I expose line info for all lines in the system by reading
> LINEINFO for each one. Then - for unrequested lines - every time the
> client asks for any line info again - I call gpiod_line_update()
> before responding. This could be optimized by this lineinfo fd
> feature.
> 
> I don't want to force the user-space to choose between using a single
> central daemon or dealing with lines separately.
> 
> > The daemon then always knows the state of the line.
> > That obviously isn't the case if you want to monitor a line without
> > requesting it, hence the "You want to be able to monitor without requesting
> > the line?" question.
> >
> 
> In other words: yes.
> 
> >
> > > > I'm still puzzled as to when the existing info ioctl could fail on a
> > > > requested line - which is when needs_update gets set in
> > > > line_maybe_update().  Hardware being unplugged?
> > > >
> > >
> > > If the ioctl() can fail, then we're obligated to check the return
> > > value. As you say: unplugging the device is a good example - it may be
> > > a GPIO expander on an HID device (e.g. Silicon Labs CP2112) that can
> > > be easily disconnected from USB.
> > >
> >
> > Fair enough. But for failures of that scale shouldn't the line request
> > fail - rather than just setting needs_update?  Or are there less
> > catastrohpic failure modes?
> >
> 
> What if the disconnect happens after the request but before the
> update? It's super unlikely, but again: the lineinfo ioctl() can fail,
> so we need to check the return value. We also can't update line info
> before requesting the line as it's racy - someone can change the state
> between the update and the request.
> 
> (I hope I'm getting this right :))
> 

I understand that the disconnect can occur between the request ioctl and
the info ioctl, but both of those are called within
line_request_values(), which implements the core of
gpiod_line_request_bulk(), so the opportunity exists to propagate the info
failure back as part of the request, but instead the error is absorbed
and needs_update is set.  This puts the onus on the caller to always
check gpiod_line_needs_update() between requesting a line and calling
any of the state accessors - else they may be returning garbage.

Similarly the event case in line_request_event_single().

I was wondering what the reasoning was for this approach?

Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21 10:31                                       ` Bartosz Golaszewski
@ 2019-11-21 11:07                                         ` Kent Gibson
  2019-11-21 15:22                                           ` Bartosz Golaszewski
  0 siblings, 1 reply; 58+ messages in thread
From: Kent Gibson @ 2019-11-21 11:07 UTC (permalink / raw)
  To: Bartosz Golaszewski; +Cc: Bartosz Golaszewski, linux-gpio

On Thu, Nov 21, 2019 at 11:31:52AM +0100, Bartosz Golaszewski wrote:
> czw., 21 lis 2019 o 11:27 Bartosz Golaszewski <brgl@bgdev.pl> napisał(a):
> >
> > czw., 21 lis 2019 o 11:18 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Thu, Nov 21, 2019 at 11:03:32AM +0100, Bartosz Golaszewski wrote:
> > > > czw., 21 lis 2019 o 10:30 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > >
> > > > > On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> > > > > > czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > >
> > > > > > > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > > > > > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > >
> > > > > > > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > >
> > > > > > > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > >
> > > > > > > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > So fail if needs_update?
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > > > > > > >
> > > > > > > > > > > > >
> > > > > > > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > > > > > > >
> > > > > > > > > > > > > Kent.
> > > > > > > > > > > >
> > > > > > > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > > > > > > unconditionally.
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > > > > > > with the kernel state - as long as needs_update is false?
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > > > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > > > > > > if it fails.
> > > > > > > > > >
> > > > > > > > > > I hope that's clearer.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > > > > > > confused about the overall needs_update handling policy by the minute.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > > > > > > fact that the kernel can't really notify us about the changes in
> > > > > > > > line's flags introduced by other processes - I'll be more than glad to
> > > > > > > > give them a try. At some point I was thinking about another ioctl()
> > > > > > > > that - for a requested line - would return a file descriptor which
> > > > > > > > would emit events when a line changes - for instance, it's requested
> > > > > > > > by someone else or its direction is changed etc.
> > > > > > > >
> > > > > > >
> > > > > > > I didn't realise it was possible for a requested line's flags to be
> > > > > > > changed by other processes.  Quite the opposite - I thought that was one
> > > > > > > of the reasons for GPIOD was to allow the userspace to prevent other from
> > > > > > > processes messing with requested lines.
> > > > > > >
> > > > > >
> > > > > > Ugh, sorry, was writing it before coffee. I was thinking about a
> > > > > > non-requested line. Something like lineinfo ioctl() but returning an
> > > > > > fd notifying about changes. Maybe we could even consider having
> > > > > > lineinfo2 ioctl() which would be extended with this functionality -
> > > > > > not only would it fill the relevant structure but also pass a new fd
> > > > > > for notification about changes.
> > > > > >
> > > > >
> > > > > Whew - that makes more sense. Had me worried there.
> > > > >
> > > > > Not sure how useful an async info ioctl would be.  Couldn't you build
> > > > > something equivalent in userspace with the existing API - as long as you
> > > > > don't mind the daemon holding the line, and so having to control the
> > > > > line via the daemon.  You want to be able to monitor without requesting
> > > > > the line?
> > > > >
> > > >
> > > > I'm not sure if I was expressing myself clearly enough: a hypothetical
> > > > daemon calls LINEINFO ioctl(). Now a different program or kernel
> > > > driver requests this line. The daemon is not up-to-date on its state
> > > > unless it polls the line all the time. If a user now asks the daemon
> > > > about this line's state - it will be given outdated info. Listening on
> > > > this fd would allow us to be informed about such changes immediately.
> > > >
> > >
> > > I think I understand you - but you might not be getting my meaning...
> > > I was thinking the daemon would request the lines it wanted to monitor
> > > - which is why you would then have to control the line via the daemon.
> >
> > No, I don't think requesting the line should be obligatory. In my WiP
> > dbus daemon, I expose line info for all lines in the system by reading
> > LINEINFO for each one. Then - for unrequested lines - every time the
> > client asks for any line info again - I call gpiod_line_update()
> > before responding. This could be optimized by this lineinfo fd
> > feature.
> >
> > I don't want to force the user-space to choose between using a single
> > central daemon or dealing with lines separately.
> >
> > > The daemon then always knows the state of the line.
> > > That obviously isn't the case if you want to monitor a line without
> > > requesting it, hence the "You want to be able to monitor without requesting
> > > the line?" question.
> > >
> >
> > In other words: yes.
> >
> 
> Just to be clear: I mean line info - not values or events. By
> monitoring I mean: be notified about changes to the line properties
> without requesting it.
> 
> As for implementation: I imagine an ioctl() called LINEINFO_FD that
> would return an open file descriptor on which read events would arrive
> when the line properties change and then we could call regular line
> info ioctl() to actually re-read it. Does that make sense? I can try
> to prepare an example implementation.
> 

Ah, ok.  So you might want to send a dbus message when someone requests
a line, or changes direction or whatever, but not have the monitoring
daemon involved in the line control.  And not have the daemon polling
the LINEINFO ioctl.

Sounds reasonable.

Now, how did we get here?? ;-).

Kent.

> Bart
> 
> > >
> > > > > I'm still puzzled as to when the existing info ioctl could fail on a
> > > > > requested line - which is when needs_update gets set in
> > > > > line_maybe_update().  Hardware being unplugged?
> > > > >
> > > >
> > > > If the ioctl() can fail, then we're obligated to check the return
> > > > value. As you say: unplugging the device is a good example - it may be
> > > > a GPIO expander on an HID device (e.g. Silicon Labs CP2112) that can
> > > > be easily disconnected from USB.
> > > >
> > >
> > > Fair enough. But for failures of that scale shouldn't the line request
> > > fail - rather than just setting needs_update?  Or are there less
> > > catastrohpic failure modes?
> > >
> >
> > What if the disconnect happens after the request but before the
> > update? It's super unlikely, but again: the lineinfo ioctl() can fail,
> > so we need to check the return value. We also can't update line info
> > before requesting the line as it's racy - someone can change the state
> > between the update and the request.
> >
> > (I hope I'm getting this right :))
> >
> > Bart
> >
> > > Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21 10:59                                       ` Kent Gibson
@ 2019-11-21 15:20                                         ` Bartosz Golaszewski
  0 siblings, 0 replies; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-21 15:20 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

czw., 21 lis 2019 o 11:59 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Thu, Nov 21, 2019 at 11:27:10AM +0100, Bartosz Golaszewski wrote:
> > czw., 21 lis 2019 o 11:18 Kent Gibson <warthog618@gmail.com> napisał(a):
> > >
> > > On Thu, Nov 21, 2019 at 11:03:32AM +0100, Bartosz Golaszewski wrote:
> > > > czw., 21 lis 2019 o 10:30 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > >
> > > > > On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> > > > > > czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > >
> > > > > > > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > > > > > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > >
> > > > > > > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > >
> > > > > > > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > >
> > > > > > > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > So fail if needs_update?
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > > > > > > >
> > > > > > > > > > > > >
> > > > > > > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > > > > > > >
> > > > > > > > > > > > > Kent.
> > > > > > > > > > > >
> > > > > > > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > > > > > > unconditionally.
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > > > > > > with the kernel state - as long as needs_update is false?
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > > > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > > > > > > if it fails.
> > > > > > > > > >
> > > > > > > > > > I hope that's clearer.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > > > > > > confused about the overall needs_update handling policy by the minute.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > > > > > > fact that the kernel can't really notify us about the changes in
> > > > > > > > line's flags introduced by other processes - I'll be more than glad to
> > > > > > > > give them a try. At some point I was thinking about another ioctl()
> > > > > > > > that - for a requested line - would return a file descriptor which
> > > > > > > > would emit events when a line changes - for instance, it's requested
> > > > > > > > by someone else or its direction is changed etc.
> > > > > > > >
> > > > > > >
> > > > > > > I didn't realise it was possible for a requested line's flags to be
> > > > > > > changed by other processes.  Quite the opposite - I thought that was one
> > > > > > > of the reasons for GPIOD was to allow the userspace to prevent other from
> > > > > > > processes messing with requested lines.
> > > > > > >
> > > > > >
> > > > > > Ugh, sorry, was writing it before coffee. I was thinking about a
> > > > > > non-requested line. Something like lineinfo ioctl() but returning an
> > > > > > fd notifying about changes. Maybe we could even consider having
> > > > > > lineinfo2 ioctl() which would be extended with this functionality -
> > > > > > not only would it fill the relevant structure but also pass a new fd
> > > > > > for notification about changes.
> > > > > >
> > > > >
> > > > > Whew - that makes more sense. Had me worried there.
> > > > >
> > > > > Not sure how useful an async info ioctl would be.  Couldn't you build
> > > > > something equivalent in userspace with the existing API - as long as you
> > > > > don't mind the daemon holding the line, and so having to control the
> > > > > line via the daemon.  You want to be able to monitor without requesting
> > > > > the line?
> > > > >
> > > >
> > > > I'm not sure if I was expressing myself clearly enough: a hypothetical
> > > > daemon calls LINEINFO ioctl(). Now a different program or kernel
> > > > driver requests this line. The daemon is not up-to-date on its state
> > > > unless it polls the line all the time. If a user now asks the daemon
> > > > about this line's state - it will be given outdated info. Listening on
> > > > this fd would allow us to be informed about such changes immediately.
> > > >
> > >
> > > I think I understand you - but you might not be getting my meaning...
> > > I was thinking the daemon would request the lines it wanted to monitor
> > > - which is why you would then have to control the line via the daemon.
> >
> > No, I don't think requesting the line should be obligatory. In my WiP
> > dbus daemon, I expose line info for all lines in the system by reading
> > LINEINFO for each one. Then - for unrequested lines - every time the
> > client asks for any line info again - I call gpiod_line_update()
> > before responding. This could be optimized by this lineinfo fd
> > feature.
> >
> > I don't want to force the user-space to choose between using a single
> > central daemon or dealing with lines separately.
> >
> > > The daemon then always knows the state of the line.
> > > That obviously isn't the case if you want to monitor a line without
> > > requesting it, hence the "You want to be able to monitor without requesting
> > > the line?" question.
> > >
> >
> > In other words: yes.
> >
> > >
> > > > > I'm still puzzled as to when the existing info ioctl could fail on a
> > > > > requested line - which is when needs_update gets set in
> > > > > line_maybe_update().  Hardware being unplugged?
> > > > >
> > > >
> > > > If the ioctl() can fail, then we're obligated to check the return
> > > > value. As you say: unplugging the device is a good example - it may be
> > > > a GPIO expander on an HID device (e.g. Silicon Labs CP2112) that can
> > > > be easily disconnected from USB.
> > > >
> > >
> > > Fair enough. But for failures of that scale shouldn't the line request
> > > fail - rather than just setting needs_update?  Or are there less
> > > catastrohpic failure modes?
> > >
> >
> > What if the disconnect happens after the request but before the
> > update? It's super unlikely, but again: the lineinfo ioctl() can fail,
> > so we need to check the return value. We also can't update line info
> > before requesting the line as it's racy - someone can change the state
> > between the update and the request.
> >
> > (I hope I'm getting this right :))
> >
>
> I understand that the disconnect can occur between the request ioctl and
> the info ioctl, but both of those are called within
> line_request_values(), which implements the core of
> gpiod_line_request_bulk(), so the opportunity exists to propagate the info
> failure back as part of the request, but instead the error is absorbed
> and needs_update is set.  This puts the onus on the caller to always
> check gpiod_line_needs_update() between requesting a line and calling
> any of the state accessors - else they may be returning garbage.
>
> Similarly the event case in line_request_event_single().
>
> I was wondering what the reasoning was for this approach?
>

So I've been thinking about why I decided to go with this - and while
I can't remember any more (I didn't comment on it...) I think there
must have been *some* reason to do this. Now it actually seems to me
as if we could make the request function release all lines and return
an error if updating fails (we'd also need to make
gpiod_line_needs_update() deprecated and always return false for
compatibility). I need to think about it some more...

Bart

> Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG
  2019-11-21 11:07                                         ` Kent Gibson
@ 2019-11-21 15:22                                           ` Bartosz Golaszewski
  0 siblings, 0 replies; 58+ messages in thread
From: Bartosz Golaszewski @ 2019-11-21 15:22 UTC (permalink / raw)
  To: Kent Gibson; +Cc: Bartosz Golaszewski, linux-gpio

czw., 21 lis 2019 o 12:07 Kent Gibson <warthog618@gmail.com> napisał(a):
>
> On Thu, Nov 21, 2019 at 11:31:52AM +0100, Bartosz Golaszewski wrote:
> > czw., 21 lis 2019 o 11:27 Bartosz Golaszewski <brgl@bgdev.pl> napisał(a):
> > >
> > > czw., 21 lis 2019 o 11:18 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > >
> > > > On Thu, Nov 21, 2019 at 11:03:32AM +0100, Bartosz Golaszewski wrote:
> > > > > czw., 21 lis 2019 o 10:30 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > >
> > > > > > On Thu, Nov 21, 2019 at 09:46:07AM +0100, Bartosz Golaszewski wrote:
> > > > > > > czw., 21 lis 2019 o 08:46 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > >
> > > > > > > > On Thu, Nov 21, 2019 at 08:13:42AM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > czw., 21 lis 2019 o 01:34 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > >
> > > > > > > > > > On Wed, Nov 20, 2019 at 04:18:24PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > śr., 20 lis 2019 o 15:36 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > >
> > > > > > > > > > > > On Wed, Nov 20, 2019 at 03:18:36PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > śr., 20 lis 2019 o 15:13 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > On Wed, Nov 20, 2019 at 03:08:57PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > > śr., 20 lis 2019 o 14:59 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > On Wed, Nov 20, 2019 at 12:00:45PM +0100, Bartosz Golaszewski wrote:
> > > > > > > > > > > > > > > > > wt., 19 lis 2019 o 16:53 Kent Gibson <warthog618@gmail.com> napisał(a):
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 10:48:25PM +0800, Kent Gibson wrote:
> > > > > > > > > > > > > > > > > > > On Mon, Nov 18, 2019 at 02:52:04PM +0100, Bartosz Golaszewski
> > > > > > > > > > > > > > > > > > > > > +
> > > > > > > > > > > > > > > > > > > > > +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->as_is) {
> > > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > > > Can you explain the purpose of this as_is field? I'm not sure this is
> > > > > > > > > > > > > > > > > > > > really needed.
> > > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > > It is there for gpiod_set_flags, which has to populate the direction
> > > > > > > > > > > > > > > > > > > flags in the SET_CONFIG ioctl. The existing line->direction is
> > > > > > > > > > > > > > > > > > > either input or output.  It is drawn from GPIOLINE_FLAG_IS_OUT, so
> > > > > > > > > > > > > > > > > > > as-is is gets mapped to input.
> > > > > > > > > > > > > > > > > > > I didn't want to change the existing line->direction, and adding the
> > > > > > > > > > > > > > > > > > > as-is seemed clearer than adding another flavour of direction that
> > > > > > > > > > > > > > > > > > > contained all three.
> > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > Hmmm, I think I see what you were getting at - the line->direction is the
> > > > > > > > > > > > > > > > > > direction from the kernel, so it doesn't hurt to use that value to set the
> > > > > > > > > > > > > > > > > > corresponding request flags - even if the original request was as-is??
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > If that is the case then the line->as_is can be dropped throughout.
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Yes, this is what I was thinking. Just need to make sure the value
> > > > > > > > > > > > > > > > > from the kernel is up-to-date.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > So fail if needs_update?
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > I'd say: do an implicit update before setting config.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > So gpiod_line_update if needs_update, and fail if that fails?
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Kent.
> > > > > > > > > > > > >
> > > > > > > > > > > > > Without the if - needs_update is only set if an implicit update fails
> > > > > > > > > > > > > in line_maybe_update(). But in this case we need to be sure, so do it
> > > > > > > > > > > > > unconditionally.
> > > > > > > > > > > > >
> > > > > > > > > > > >
> > > > > > > > > > > > Given that line_maybe_update is called at the end of request creation, and
> > > > > > > > > > > > whenever set_config is called, how can line->direction be inconsistent
> > > > > > > > > > > > with the kernel state - as long as needs_update is false?
> > > > > > > > > > > >
> > > > > > > > > > >
> > > > > > > > > > > I don't think we should call line_maybe_update() on set_config() - in
> > > > > > > > > > > this case we should call gpiod_line_update() and fail in set_config()
> > > > > > > > > > > if it fails.
> > > > > > > > > > >
> > > > > > > > > > > I hope that's clearer.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > Not really.  I was already shaky on the needs_update and I'm getting more
> > > > > > > > > > confused about the overall needs_update handling policy by the minute.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > Yeah it's not optimal. If you have better ideas on how to handle the
> > > > > > > > > fact that the kernel can't really notify us about the changes in
> > > > > > > > > line's flags introduced by other processes - I'll be more than glad to
> > > > > > > > > give them a try. At some point I was thinking about another ioctl()
> > > > > > > > > that - for a requested line - would return a file descriptor which
> > > > > > > > > would emit events when a line changes - for instance, it's requested
> > > > > > > > > by someone else or its direction is changed etc.
> > > > > > > > >
> > > > > > > >
> > > > > > > > I didn't realise it was possible for a requested line's flags to be
> > > > > > > > changed by other processes.  Quite the opposite - I thought that was one
> > > > > > > > of the reasons for GPIOD was to allow the userspace to prevent other from
> > > > > > > > processes messing with requested lines.
> > > > > > > >
> > > > > > >
> > > > > > > Ugh, sorry, was writing it before coffee. I was thinking about a
> > > > > > > non-requested line. Something like lineinfo ioctl() but returning an
> > > > > > > fd notifying about changes. Maybe we could even consider having
> > > > > > > lineinfo2 ioctl() which would be extended with this functionality -
> > > > > > > not only would it fill the relevant structure but also pass a new fd
> > > > > > > for notification about changes.
> > > > > > >
> > > > > >
> > > > > > Whew - that makes more sense. Had me worried there.
> > > > > >
> > > > > > Not sure how useful an async info ioctl would be.  Couldn't you build
> > > > > > something equivalent in userspace with the existing API - as long as you
> > > > > > don't mind the daemon holding the line, and so having to control the
> > > > > > line via the daemon.  You want to be able to monitor without requesting
> > > > > > the line?
> > > > > >
> > > > >
> > > > > I'm not sure if I was expressing myself clearly enough: a hypothetical
> > > > > daemon calls LINEINFO ioctl(). Now a different program or kernel
> > > > > driver requests this line. The daemon is not up-to-date on its state
> > > > > unless it polls the line all the time. If a user now asks the daemon
> > > > > about this line's state - it will be given outdated info. Listening on
> > > > > this fd would allow us to be informed about such changes immediately.
> > > > >
> > > >
> > > > I think I understand you - but you might not be getting my meaning...
> > > > I was thinking the daemon would request the lines it wanted to monitor
> > > > - which is why you would then have to control the line via the daemon.
> > >
> > > No, I don't think requesting the line should be obligatory. In my WiP
> > > dbus daemon, I expose line info for all lines in the system by reading
> > > LINEINFO for each one. Then - for unrequested lines - every time the
> > > client asks for any line info again - I call gpiod_line_update()
> > > before responding. This could be optimized by this lineinfo fd
> > > feature.
> > >
> > > I don't want to force the user-space to choose between using a single
> > > central daemon or dealing with lines separately.
> > >
> > > > The daemon then always knows the state of the line.
> > > > That obviously isn't the case if you want to monitor a line without
> > > > requesting it, hence the "You want to be able to monitor without requesting
> > > > the line?" question.
> > > >
> > >
> > > In other words: yes.
> > >
> >
> > Just to be clear: I mean line info - not values or events. By
> > monitoring I mean: be notified about changes to the line properties
> > without requesting it.
> >
> > As for implementation: I imagine an ioctl() called LINEINFO_FD that
> > would return an open file descriptor on which read events would arrive
> > when the line properties change and then we could call regular line
> > info ioctl() to actually re-read it. Does that make sense? I can try
> > to prepare an example implementation.
> >
>
> Ah, ok.  So you might want to send a dbus message when someone requests
> a line, or changes direction or whatever, but not have the monitoring
> daemon involved in the line control.  And not have the daemon polling
> the LINEINFO ioctl.
>
> Sounds reasonable.
>

That would be great, yes.

> Now, how did we get here?? ;-).
>

I'm actually happy you're doing this. You're making me think about
issues I never noticed. It's always great to have someone go through
your code. Thanks!

Bart

> Kent.
>
> > Bart
> >
> > > >
> > > > > > I'm still puzzled as to when the existing info ioctl could fail on a
> > > > > > requested line - which is when needs_update gets set in
> > > > > > line_maybe_update().  Hardware being unplugged?
> > > > > >
> > > > >
> > > > > If the ioctl() can fail, then we're obligated to check the return
> > > > > value. As you say: unplugging the device is a good example - it may be
> > > > > a GPIO expander on an HID device (e.g. Silicon Labs CP2112) that can
> > > > > be easily disconnected from USB.
> > > > >
> > > >
> > > > Fair enough. But for failures of that scale shouldn't the line request
> > > > fail - rather than just setting needs_update?  Or are there less
> > > > catastrohpic failure modes?
> > > >
> > >
> > > What if the disconnect happens after the request but before the
> > > update? It's super unlikely, but again: the lineinfo ioctl() can fail,
> > > so we need to check the return value. We also can't update line info
> > > before requesting the line as it's racy - someone can change the state
> > > between the update and the request.
> > >
> > > (I hope I'm getting this right :))
> > >
> > > Bart
> > >
> > > > Kent.

^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2019-11-21 15:22 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-15 14:43 [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 01/19] core: move request flag to handle flag conversion into a separate function Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 02/19] API: add support for bias flags Kent Gibson
2019-11-18 13:51   ` Bartosz Golaszewski
2019-11-18 14:12     ` Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 03/19] core: fix misspelling of parameter Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 04/19] tests: add tests for bias flags Kent Gibson
2019-11-18 13:51   ` Bartosz Golaszewski
2019-11-18 14:14     ` Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 05/19] bindings: cxx: drop noexcept from direction and active_state Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 06/19] bindings: cxx: initialise bitset with integer instead of string Kent Gibson
2019-11-18 13:51   ` Bartosz Golaszewski
2019-11-18 14:17     ` Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 07/19] bindings: cxx: add support for bias flags Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 08/19] bindings: cxx: tests: add tests " Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 09/19] bindings: python: add support " Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 10/19] bindings: python: tests: add tests " Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 11/19] API: add support for SET_CONFIG Kent Gibson
2019-11-18 13:52   ` Bartosz Golaszewski
2019-11-18 14:48     ` Kent Gibson
2019-11-19 15:52       ` Kent Gibson
2019-11-20 11:00         ` Bartosz Golaszewski
2019-11-20 13:58           ` Kent Gibson
2019-11-20 14:08             ` Bartosz Golaszewski
2019-11-20 14:13               ` Kent Gibson
2019-11-20 14:18                 ` Bartosz Golaszewski
2019-11-20 14:36                   ` Kent Gibson
2019-11-20 15:18                     ` Bartosz Golaszewski
2019-11-21  0:34                       ` Kent Gibson
2019-11-21  7:13                         ` Bartosz Golaszewski
2019-11-21  7:46                           ` Kent Gibson
2019-11-21  8:46                             ` Bartosz Golaszewski
2019-11-21  9:30                               ` Kent Gibson
2019-11-21 10:03                                 ` Bartosz Golaszewski
2019-11-21 10:18                                   ` Kent Gibson
2019-11-21 10:27                                     ` Bartosz Golaszewski
2019-11-21 10:31                                       ` Bartosz Golaszewski
2019-11-21 11:07                                         ` Kent Gibson
2019-11-21 15:22                                           ` Bartosz Golaszewski
2019-11-21 10:59                                       ` Kent Gibson
2019-11-21 15:20                                         ` Bartosz Golaszewski
2019-11-15 14:43 ` [libgpiod] [PATCH 12/19] tests: add tests " Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 13/19] core: allow gpiod_line_set_value_bulk to accept null values Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 14/19] bindings: cxx: add support for SET_CONFIG Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 15/19] bindings: cxx: tests: add tests for SET_CONFIG methods Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 16/19] bindings: python: add support for SET_CONFIG Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 17/19] bindings: python: tests: add tests for SET_CONFIG methods Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 18/19] tools: add support for bias flags Kent Gibson
2019-11-16 15:40   ` Kent Gibson
2019-11-17 12:18     ` Bartosz Golaszewski
2019-11-17 12:28       ` Kent Gibson
2019-11-17 13:12         ` Kent Gibson
2019-11-15 14:43 ` [libgpiod] [PATCH 19/19] treewide: change "correspond with" to "correspond to" Kent Gibson
2019-11-18 13:52   ` Bartosz Golaszewski
2019-11-18 15:01     ` Kent Gibson
2019-11-18 13:50 ` [libgpiod] [PATCH 00/19] Add support for bias flags and SET_CONFIG Bartosz Golaszewski
2019-11-18 14:09   ` Kent Gibson
2019-11-18 14:55     ` Bartosz Golaszewski

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).