@@ -28,9 +28,8 @@ AC_SUBST(VERSION_STR, [$PACKAGE_VERSION$EXTRA_VERSION])
AC_SUBST(ABI_VERSION, [4.1.2])
# Have a separate ABI version for C++ bindings:
AC_SUBST(ABI_CXX_VERSION, [2.1.1])
-# ABI version for libgpiomockup (we need this since it can be installed if we
+# ABI version for libgpiosim (we need this since it can be installed if we
# enable install-tests).
-AC_SUBST(ABI_MOCKUP_VERSION, [0.1.0])
AC_SUBST(ABI_GPIOSIM_VERSION, [0.1.0])
AC_CONFIG_AUX_DIR([autostuff])
@@ -138,14 +137,14 @@ AC_DEFUN([FUNC_NOT_FOUND_TESTS],
if test "x$with_tests" = xtrue
then
- # For libgpiomockup & libgpiosim
+ # For libgpiosim
AC_CHECK_FUNC([qsort], [], [FUNC_NOT_FOUND_TESTS([qsort])])
PKG_CHECK_MODULES([KMOD], [libkmod >= 18])
- PKG_CHECK_MODULES([UDEV], [libudev >= 215])
PKG_CHECK_MODULES([MOUNT], [mount >= 2.33.1])
# For core library tests
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.50])
+ PKG_CHECK_MODULES([GOBJECT], [gobject-2.0 >= 2.50])
if test "x$with_tools" = xtrue
then
@@ -236,7 +235,6 @@ AC_CONFIG_FILES([Makefile
lib/libgpiod.pc
tools/Makefile
tests/Makefile
- tests/mockup/Makefile
tests/gpiosim/Makefile
bindings/cxx/libgpiodcxx.pc
bindings/Makefile
@@ -1,24 +1,32 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl>
-SUBDIRS = mockup gpiosim
+SUBDIRS = gpiosim
AM_CFLAGS = -I$(top_srcdir)/include/ -I$(top_srcdir)/tests/gpiosim/
AM_CFLAGS += -include $(top_builddir)/config.h
-AM_CFLAGS += -Wall -Wextra -g -std=gnu89 $(GLIB_CFLAGS)
+AM_CFLAGS += -Wall -Wextra -g -std=gnu89 $(GLIB_CFLAGS) $(GOBJECT_CFLAGS)
AM_CFLAGS += -DG_LOG_DOMAIN=\"gpiod-test\"
AM_CFLAGS += $(PROFILING_CFLAGS)
-AM_LDFLAGS = -pthread $(PROFILING_LDFLAGS)
+AM_LDFLAGS = -pthread
LDADD = $(top_builddir)/lib/libgpiod.la
LDADD += $(top_builddir)/tests/gpiosim/libgpiosim.la
-LDADD += $(GLIB_LIBS)
+LDADD += $(GLIB_LIBS) $(GOBJECT_LIBS)
bin_PROGRAMS = gpiod-test
gpiod_test_SOURCES = \
gpiod-test.c \
gpiod-test.h \
+ gpiod-test-helpers.c \
+ gpiod-test-helpers.h \
+ gpiod-test-sim.c \
+ gpiod-test-sim.h \
tests-chip.c \
- tests-event.c \
- tests-line.c \
- tests-misc.c
+ tests-edge-event.c \
+ tests-info-event.c \
+ tests-line-config.c \
+ tests-line-info.c \
+ tests-line-request.c \
+ tests-misc.c \
+ tests-request-config.c
new file mode 100644
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+/*
+ * Testing framework for the core library.
+ *
+ * This file contains functions and definitions extending the GLib unit testing
+ * framework with functionalities necessary to test the libgpiod core C API as
+ * well as the kernel-to-user-space interface.
+ */
+
+#include "gpiod-test-helpers.h"
+
+GVariant *
+gpiod_test_package_line_names(const struct gpiod_test_line_name *names)
+{
+ const struct gpiod_test_line_name *name;
+ GVariantBuilder *builder;
+ GVariant *ret;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a(us)"));
+
+ for (name = &names[0]; name->name; name++)
+ g_variant_builder_add(builder, "(us)",
+ name->offset, name->name);
+
+ ret = g_variant_new("a(us)", builder);
+ g_variant_builder_unref(builder);
+
+ return ret;
+}
+
+GVariant *gpiod_test_package_hogs(const struct gpiod_test_hog *hogs)
+{
+ const struct gpiod_test_hog *hog;
+ GVariantBuilder *builder;
+ GVariant *ret;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a(usi)"));
+
+ for (hog = &hogs[0]; hog->name; hog++)
+ g_variant_builder_add(builder, "(usi)",
+ hog->offset, hog->name, hog->direction);
+
+ ret = g_variant_new("a(usi)", builder);
+ g_variant_builder_unref(builder);
+
+ return ret;
+}
new file mode 100644
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+#ifndef __GPIOD_TEST_HELPERS_H__
+#define __GPIOD_TEST_HELPERS_H__
+
+#include <errno.h>
+#include <glib.h>
+#include <gpiod.h>
+
+#include "gpiod-test-sim.h"
+
+/*
+ * These typedefs are needed to make g_autoptr work - it doesn't accept
+ * regular 'struct typename' syntax.
+ */
+
+typedef struct gpiod_chip struct_gpiod_chip;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_chip, gpiod_chip_close);
+
+typedef struct gpiod_line_info struct_gpiod_line_info;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_info, gpiod_line_info_free);
+
+typedef struct gpiod_info_event struct_gpiod_info_event;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_info_event, gpiod_info_event_free);
+
+typedef struct gpiod_line_config struct_gpiod_line_config;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_config, gpiod_line_config_free);
+
+typedef struct gpiod_request_config struct_gpiod_request_config;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_request_config,
+ gpiod_request_config_free);
+
+typedef struct gpiod_line_request struct_gpiod_line_request;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_line_request,
+ gpiod_line_request_release);
+
+typedef struct gpiod_edge_event struct_gpiod_edge_event;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_edge_event, gpiod_edge_event_free);
+
+typedef struct gpiod_edge_event_buffer struct_gpiod_edge_event_buffer;
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(struct_gpiod_edge_event_buffer,
+ gpiod_edge_event_buffer_free);
+
+#define gpiod_test_return_if_failed() \
+ do { \
+ if (g_test_failed()) \
+ return; \
+ } while (0)
+
+#define gpiod_test_join_thread_and_return_if_failed(_thread) \
+ do { \
+ if (g_test_failed()) { \
+ g_thread_join(_thread); \
+ return; \
+ } \
+ } while (0)
+
+#define gpiod_test_open_chip_or_fail(_path) \
+ ({ \
+ struct gpiod_chip *_chip = gpiod_chip_open((_path)); \
+ g_assert_nonnull(_chip); \
+ gpiod_test_return_if_failed(); \
+ _chip; \
+ })
+
+#define gpiod_test_get_line_info_or_fail(_chip, _offset) \
+ ({ \
+ struct gpiod_line_info *_info = \
+ gpiod_chip_get_line_info((_chip), (_offset)); \
+ g_assert_nonnull(_info); \
+ gpiod_test_return_if_failed(); \
+ _info; \
+ })
+
+#define gpiod_test_create_line_config_or_fail() \
+ ({ \
+ struct gpiod_line_config *_config = \
+ gpiod_line_config_new(); \
+ g_assert_nonnull(_config); \
+ gpiod_test_return_if_failed(); \
+ _config; \
+ })
+
+#define gpiod_test_create_edge_event_buffer_or_fail(_capacity) \
+ ({ \
+ struct gpiod_edge_event_buffer *_buffer = \
+ gpiod_edge_event_buffer_new(_capacity); \
+ g_assert_nonnull(_buffer); \
+ gpiod_test_return_if_failed(); \
+ _buffer; \
+ })
+
+#define gpiod_test_create_request_config_or_fail() \
+ ({ \
+ struct gpiod_request_config *_config = \
+ gpiod_request_config_new(); \
+ g_assert_nonnull(_config); \
+ gpiod_test_return_if_failed(); \
+ _config; \
+ })
+
+#define gpiod_test_request_lines_or_fail(_chip, _req_cfg, _line_cfg) \
+ ({ \
+ struct gpiod_line_request *_request = \
+ gpiod_chip_request_lines((_chip), \
+ (_req_cfg), (_line_cfg)); \
+ g_assert_nonnull(_request); \
+ gpiod_test_return_if_failed(); \
+ _request; \
+ })
+
+#define gpiod_test_reconfigure_lines_or_fail(_request, _line_cfg) \
+ do { \
+ gint ret = gpiod_line_request_reconfigure_lines((_request), \
+ (_line_cfg)); \
+ g_assert_cmpint(ret, ==, 0); \
+ gpiod_test_return_if_failed(); \
+ } while (0)
+
+#define gpiod_test_expect_errno(_expected) \
+ g_assert_cmpint((_expected), ==, errno)
+
+struct gpiod_test_line_name {
+ guint offset;
+ const gchar *name;
+};
+
+struct gpiod_test_hog {
+ guint offset;
+ const gchar *name;
+ GPIOSimHogDir direction;
+};
+
+GVariant *
+gpiod_test_package_line_names(const struct gpiod_test_line_name *names);
+GVariant *gpiod_test_package_hogs(const struct gpiod_test_hog *hogs);
+
+#endif /* __GPIOD_TEST_HELPERS_H__ */
new file mode 100644
@@ -0,0 +1,308 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+#include <errno.h>
+#include <gpiosim.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "gpiod-test-sim.h"
+
+struct _GPIOSimChip {
+ GObject parent_instance;
+ struct gpiosim_bank *bank;
+};
+
+enum {
+ G_GPIOSIM_CHIP_PROP_DEV_PATH = 1,
+ G_GPIOSIM_CHIP_PROP_NAME,
+ G_GPIOSIM_CHIP_PROP_NUM_LINES,
+ G_GPIOSIM_CHIP_PROP_LABEL,
+ G_GPIOSIM_CHIP_PROP_LINE_NAMES,
+ G_GPIOSIM_CHIP_PROP_HOGS,
+};
+
+static struct gpiosim_ctx *sim_ctx;
+static pid_t pid;
+static guint sim_id;
+
+G_DEFINE_TYPE(GPIOSimChip, g_gpiosim_chip, G_TYPE_OBJECT);
+
+static void g_gpiosim_ctx_unref(void)
+{
+ gpiosim_ctx_unref(sim_ctx);
+}
+
+static void g_gpiosim_ctx_init(void)
+{
+ sim_ctx = gpiosim_ctx_new();
+ if (!sim_ctx)
+ g_error("Unable to initialize libgpiosim: %s",
+ g_strerror(errno));
+
+ atexit(g_gpiosim_ctx_unref);
+ pid = getpid();
+}
+
+static void g_gpiosim_chip_constructed(GObject *obj)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+ struct gpiosim_dev *dev;
+ gint ret;
+
+ dev = gpiosim_bank_get_dev(self->bank);
+ ret = gpiosim_dev_enable(dev);
+ gpiosim_dev_unref(dev);
+ if (ret)
+ g_error("Error while trying to enable the simulated GPIO device: %s",
+ g_strerror(errno));
+}
+
+static void g_gpiosim_chip_get_property(GObject *obj, guint prop_id,
+ GValue *val, GParamSpec *pspec)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+
+ switch (prop_id) {
+ case G_GPIOSIM_CHIP_PROP_DEV_PATH:
+ g_value_set_static_string(val,
+ gpiosim_bank_get_dev_path(self->bank));
+ break;
+ case G_GPIOSIM_CHIP_PROP_NAME:
+ g_value_set_static_string(val,
+ gpiosim_bank_get_chip_name(self->bank));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void g_gpiosim_chip_set_property(GObject *obj, guint prop_id,
+ const GValue *val, GParamSpec *pspec)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+ gint ret, vdir, dir;
+ GVariantIter *iter;
+ GVariant *variant;
+ guint offset;
+ gchar *name;
+
+ switch (prop_id) {
+ case G_GPIOSIM_CHIP_PROP_NUM_LINES:
+ ret = gpiosim_bank_set_num_lines(self->bank,
+ g_value_get_uint(val));
+ if (ret)
+ g_error("Unable to set the number of lines exposed by the simulated chip: %s",
+ g_strerror(errno));
+ break;
+ case G_GPIOSIM_CHIP_PROP_LABEL:
+ ret = gpiosim_bank_set_label(self->bank,
+ g_value_get_string(val));
+ if (ret)
+ g_error("Unable to set the label of the simulated chip: %s",
+ g_strerror(errno));
+ break;
+ case G_GPIOSIM_CHIP_PROP_LINE_NAMES:
+ variant = g_value_get_variant(val);
+ if (!variant)
+ break;
+
+ iter = g_variant_iter_new(variant);
+
+ while (g_variant_iter_loop(iter, "(us)", &offset, &name)) {
+ ret = gpiosim_bank_set_line_name(self->bank,
+ offset, name);
+ if (ret)
+ g_error("Unable to set the name of the simulated GPIO line: %s",
+ g_strerror(errno));
+ }
+
+ g_variant_iter_free(iter);
+ break;
+ case G_GPIOSIM_CHIP_PROP_HOGS:
+ variant = g_value_get_variant(val);
+ if (!variant)
+ break;
+
+ iter = g_variant_iter_new(variant);
+
+ while (g_variant_iter_loop(iter, "(usi)",
+ &offset, &name, &vdir)) {
+ switch (vdir) {
+ case G_GPIOSIM_HOG_DIR_INPUT:
+ dir = GPIOSIM_HOG_DIR_INPUT;
+ break;
+ case G_GPIOSIM_HOG_DIR_OUTPUT_HIGH:
+ dir = GPIOSIM_HOG_DIR_OUTPUT_HIGH;
+ break;
+ case G_GPIOSIM_HOG_DIR_OUTPUT_LOW:
+ dir = GPIOSIM_HOG_DIR_OUTPUT_LOW;
+ break;
+ default:
+ g_error("Invalid hog direction value: %d",
+ vdir);
+ }
+
+ ret = gpiosim_bank_hog_line(self->bank,
+ offset, name, dir);
+ if (ret)
+ g_error("Unable to hog the simulated GPIO line: %s",
+ g_strerror(errno));
+ }
+
+ g_variant_iter_free(iter);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void g_gpiosim_chip_dispose(GObject *obj)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+ struct gpiosim_dev *dev;
+ gint ret;
+
+ dev = gpiosim_bank_get_dev(self->bank);
+
+ if (gpiosim_dev_is_live(dev)) {
+ ret = gpiosim_dev_disable(dev);
+ if (ret)
+ g_error("Error while trying to disable the simulated GPIO device: %s",
+ g_strerror(errno));
+ }
+
+ gpiosim_dev_unref(dev);
+ sim_id--;
+}
+
+static void g_gpiosim_chip_finalize(GObject *obj)
+{
+ GPIOSimChip *self = G_GPIOSIM_CHIP(obj);
+
+ gpiosim_bank_unref(self->bank);
+
+ G_OBJECT_CLASS(g_gpiosim_chip_parent_class)->finalize(obj);
+}
+
+static void g_gpiosim_chip_class_init(GPIOSimChipClass *chip_class)
+{
+ GObjectClass *class = G_OBJECT_CLASS(chip_class);
+
+ class->constructed = g_gpiosim_chip_constructed;
+ class->get_property = g_gpiosim_chip_get_property;
+ class->set_property = g_gpiosim_chip_set_property;
+ class->dispose = g_gpiosim_chip_dispose;
+ class->finalize = g_gpiosim_chip_finalize;
+
+ g_object_class_install_property(class, G_GPIOSIM_CHIP_PROP_DEV_PATH,
+ g_param_spec_string("dev-path", "Device path",
+ "Character device filesystem path.", NULL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property(class, G_GPIOSIM_CHIP_PROP_NAME,
+ g_param_spec_string("name", "Chip name",
+ "Name of this chip device as set by the kernel.", NULL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property(class, G_GPIOSIM_CHIP_PROP_NUM_LINES,
+ g_param_spec_uint("num-lines", "Number of lines",
+ "Number of lines this simulated chip exposes.",
+ 1, G_MAXUINT, 1,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property(class, G_GPIOSIM_CHIP_PROP_LABEL,
+ g_param_spec_string("label", "Chip label",
+ "Label of this simulated chip.", NULL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property(class, G_GPIOSIM_CHIP_PROP_LINE_NAMES,
+ g_param_spec_variant("line-names", "Line names",
+ "List of names of the lines exposed by this chip",
+ (GVariantType *)"a(us)", NULL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property(class, G_GPIOSIM_CHIP_PROP_HOGS,
+ g_param_spec_variant("hogs", "Line hogs",
+ "List of hogged lines and their directions.",
+ (GVariantType *)"a(usi)", NULL,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void g_gpiosim_chip_init(GPIOSimChip *self)
+{
+ g_autofree gchar *dev_name = NULL;
+ struct gpiosim_dev *dev;
+
+ if (!sim_ctx)
+ g_gpiosim_ctx_init();
+
+ dev_name = g_strdup_printf("gpiod-test-dev.%u.%u", pid, sim_id++);
+ dev = gpiosim_dev_new(sim_ctx, dev_name);
+ if (!dev)
+ g_error("Unable to instantiate new GPIO device: %s",
+ g_strerror(errno));
+
+ self->bank = gpiosim_bank_new(dev, "bank");
+ gpiosim_dev_unref(dev);
+ if (!self->bank)
+ g_error("Unable to instantiate new GPIO bank: %s",
+ g_strerror(errno));
+}
+
+static const gchar *
+g_gpiosim_chip_get_string_prop(GPIOSimChip *self, const gchar *prop)
+{
+ GValue val = G_VALUE_INIT;
+ const gchar *str;
+
+ g_object_get_property(G_OBJECT(self), prop, &val);
+ str = g_value_get_string(&val);
+ g_value_unset(&val);
+
+ return str;
+}
+
+const gchar *g_gpiosim_chip_get_dev_path(GPIOSimChip *self)
+{
+ return g_gpiosim_chip_get_string_prop(self, "dev-path");
+}
+
+const gchar *g_gpiosim_chip_get_name(GPIOSimChip *self)
+{
+ return g_gpiosim_chip_get_string_prop(self, "name");
+}
+
+gint g_gpiosim_chip_get_value(GPIOSimChip *chip, guint offset)
+{
+ gint val;
+
+ val = gpiosim_bank_get_value(chip->bank, offset);
+ if (val < 0)
+ g_error("Unable to read the line value: %s", g_strerror(errno));
+
+ return val;
+}
+
+void g_gpiosim_chip_set_pull(GPIOSimChip *chip, guint offset, GPIOSimPull pull)
+{
+ gint ret, sim_pull;
+
+ switch (pull) {
+ case G_GPIOSIM_PULL_DOWN:
+ sim_pull = GPIOSIM_PULL_DOWN;
+ break;
+ case G_GPIOSIM_PULL_UP:
+ sim_pull = GPIOSIM_PULL_UP;
+ break;
+ default:
+ g_error("invalid pull value");
+ }
+
+ ret = gpiosim_bank_set_pull(chip->bank, offset, sim_pull);
+ if (ret)
+ g_error("Unable to set the pull setting for simulated line: %s",
+ g_strerror(errno));
+}
new file mode 100644
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* SPDX-FileCopyrightText: 2022 Bartosz Golaszewski <brgl@bgdev.pl> */
+
+#ifndef __GPIOD_TEST_SIM_H__
+#define __GPIOD_TEST_SIM_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ G_GPIOSIM_PULL_UP = 1,
+ G_GPIOSIM_PULL_DOWN,
+} GPIOSimPull;
+
+typedef enum {
+ G_GPIOSIM_HOG_DIR_INPUT = 1,
+ G_GPIOSIM_HOG_DIR_OUTPUT_HIGH,
+ G_GPIOSIM_HOG_DIR_OUTPUT_LOW,
+} GPIOSimHogDir;
+
+typedef struct _GPIOSimChip GPIOSimChip;
+
+G_DECLARE_FINAL_TYPE(GPIOSimChip, g_gpiosim_chip, G_GPIOSIM, CHIP, GObject);
+
+#define G_GPIOSIM_TYPE_CHIP (g_gpiosim_chip_get_type())
+#define G_GPIOSIM_CHIP(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), G_GPIOSIM_TYPE_CHIP, GPIOSimChip))
+
+#define g_gpiosim_chip_new(...) \
+ G_GPIOSIM_CHIP(g_object_new(G_GPIOSIM_TYPE_CHIP, __VA_ARGS__))
+
+const gchar *g_gpiosim_chip_get_dev_path(GPIOSimChip *self);
+const gchar *g_gpiosim_chip_get_name(GPIOSimChip *self);
+
+gint g_gpiosim_chip_get_value(GPIOSimChip *self, guint offset);
+void g_gpiosim_chip_set_pull(GPIOSimChip *self, guint offset, GPIOSimPull pull);
+
+G_END_DECLS
+
+#endif /* __GPIOD_TEST_SIM_H__ */
@@ -2,8 +2,6 @@
// SPDX-FileCopyrightText: 2017-2022 Bartosz Golaszewski <brgl@bgdev.pl>
#include <errno.h>
-#include <glib/gstdio.h>
-#include <gpiosim.h>
#include <linux/version.h>
#include <stdio.h>
#include <sys/utsname.h>
@@ -12,28 +10,13 @@
#include "gpiod-test.h"
#define MIN_KERNEL_MAJOR 5
-#define MIN_KERNEL_MINOR 10
+#define MIN_KERNEL_MINOR 16
#define MIN_KERNEL_RELEASE 0
#define MIN_KERNEL_VERSION KERNEL_VERSION(MIN_KERNEL_MAJOR, \
MIN_KERNEL_MINOR, \
MIN_KERNEL_RELEASE)
-struct gpiod_test_event_thread {
- GThread *id;
- GMutex lock;
- GCond cond;
- gboolean should_stop;
- guint chip_index;
- guint line_offset;
- guint period_ms;
-};
-
-static struct {
- GList *tests;
- struct gpiosim_ctx *gpiosim;
- GPtrArray *sim_chips;
- GPtrArray *sim_banks;
-} globals;
+static GList *tests;
static void check_kernel(void)
{
@@ -63,103 +46,16 @@ static void check_kernel(void)
return;
}
-static void remove_gpiosim_chip(gpointer data)
-{
- struct gpiosim_dev *dev = data;
- gint ret;
-
- ret = gpiosim_dev_disable(dev);
- if (ret)
- g_error("unable to uncommit a simulated GPIO device: %s",
- g_strerror(errno));
-
- gpiosim_dev_unref(dev);
-}
-
-static void remove_gpiosim_bank(gpointer data)
-{
- struct gpiosim_bank *bank = data;
-
- gpiosim_bank_unref(bank);
-}
-
static void test_func_wrapper(gconstpointer data)
{
- const _GpiodTestCase *test = data;
- struct gpiosim_bank *sim_bank;
- struct gpiosim_dev *sim_dev;
- gchar *line_name, *label;
- gchar chip_idx;
- guint i, j;
- gint ret;
-
- globals.sim_chips = g_ptr_array_new_full(test->num_chips,
- remove_gpiosim_chip);
- globals.sim_banks = g_ptr_array_new_full(test->num_chips,
- remove_gpiosim_bank);
-
- for (i = 0; i < test->num_chips; i++) {
- chip_idx = i + 65;
-
- sim_dev = gpiosim_dev_new(globals.gpiosim, NULL);
- if (!sim_dev)
- g_error("unable to create a simulated GPIO chip: %s",
- g_strerror(errno));
-
- sim_bank = gpiosim_bank_new(sim_dev, NULL);
- if (!sim_bank)
- g_error("unable to create a simulated GPIO bank: %s",
- g_strerror(errno));
-
- label = g_strdup_printf("gpio-mockup-%c", chip_idx);
- ret = gpiosim_bank_set_label(sim_bank, label);
- g_free(label);
- if (ret)
- g_error("unable to set simulated chip label: %s",
- g_strerror(errno));
-
- ret = gpiosim_bank_set_num_lines(sim_bank, test->chip_sizes[i]);
- if (ret)
- g_error("unable to set the number of lines for a simulated chip: %s",
- g_strerror(errno));
-
- if (test->flags & GPIOD_TEST_FLAG_NAMED_LINES) {
- for (j = 0; j < test->chip_sizes[i]; j++) {
- line_name = g_strdup_printf("gpio-mockup-%c-%u",
- chip_idx, j);
-
- ret = gpiosim_bank_set_line_name(sim_bank, j,
- line_name);
- g_free(line_name);
- if (ret)
- g_error("unable to set the line names for a simulated bank: %s",
- g_strerror(errno));
- }
- }
-
- ret = gpiosim_dev_enable(sim_dev);
- if (ret)
- g_error("unable to commit the simulated GPIO device: %s",
- g_strerror(errno));
-
- g_ptr_array_add(globals.sim_chips, sim_dev);
- g_ptr_array_add(globals.sim_banks, sim_bank);
- }
+ const struct _gpiod_test_case *test = data;
test->func();
-
- g_ptr_array_unref(globals.sim_banks);
- g_ptr_array_unref(globals.sim_chips);
-}
-
-static void unref_gpiosim(void)
-{
- gpiosim_ctx_unref(globals.gpiosim);
}
static void add_test_from_list(gpointer element, gpointer data G_GNUC_UNUSED)
{
- _GpiodTestCase *test = element;
+ struct _gpiod_test_case *test = element;
g_test_add_data_func(test->path, test, test_func_wrapper);
}
@@ -170,128 +66,17 @@ int main(gint argc, gchar **argv)
g_test_set_nonfatal_assertions();
g_debug("running libgpiod test suite");
- g_debug("%u tests registered", g_list_length(globals.tests));
-
- /*
- * Setup libpiosim first so that it runs its own kernel version
- * check before we tell the user our local requirements are met as
- * well.
- */
- globals.gpiosim = gpiosim_ctx_new();
- if (!globals.gpiosim)
- g_error("unable to initialize gpiosim library: %s",
- g_strerror(errno));
- atexit(unref_gpiosim);
+ g_debug("%u tests registered", g_list_length(tests));
check_kernel();
- g_list_foreach(globals.tests, add_test_from_list, NULL);
- g_list_free(globals.tests);
+ g_list_foreach(tests, add_test_from_list, NULL);
+ g_list_free(tests);
return g_test_run();
}
-void _gpiod_test_register(_GpiodTestCase *test)
-{
- globals.tests = g_list_append(globals.tests, test);
-}
-
-const gchar *gpiod_test_chip_path(guint idx)
-{
- struct gpiosim_bank *bank = g_ptr_array_index(globals.sim_banks, idx);
-
- return gpiosim_bank_get_dev_path(bank);
-}
-
-const gchar *gpiod_test_chip_name(guint idx)
-{
- struct gpiosim_bank *bank = g_ptr_array_index(globals.sim_banks, idx);
-
- return gpiosim_bank_get_chip_name(bank);
-}
-
-gint gpiod_test_chip_get_value(guint chip_index, guint line_offset)
-{
- struct gpiosim_bank *bank = g_ptr_array_index(globals.sim_banks,
- chip_index);
- gint ret;
-
- ret = gpiosim_bank_get_value(bank, line_offset);
- if (ret < 0)
- g_error("unable to read line value from gpiosim: %s",
- g_strerror(errno));
-
- return ret;
-}
-
-void gpiod_test_chip_set_pull(guint chip_index, guint line_offset, gint pull)
-{
- struct gpiosim_bank *bank = g_ptr_array_index(globals.sim_banks,
- chip_index);
- gint ret;
-
- ret = gpiosim_bank_set_pull(bank, line_offset,
- pull ? GPIOSIM_PULL_UP : GPIOSIM_PULL_DOWN);
- if (ret)
- g_error("unable to set line pull in gpiosim: %s",
- g_strerror(errno));
-}
-
-static gpointer event_worker_func(gpointer data)
-{
- GpiodTestEventThread *thread = data;
- gboolean signalled;
- gint64 end_time;
- gint i;
-
- for (i = 0;; i++) {
- g_mutex_lock(&thread->lock);
- if (thread->should_stop) {
- g_mutex_unlock(&thread->lock);
- break;
- }
-
- end_time = g_get_monotonic_time() + thread->period_ms * 1000;
-
- signalled = g_cond_wait_until(&thread->cond,
- &thread->lock, end_time);
- if (!signalled)
- gpiod_test_chip_set_pull(thread->chip_index,
- thread->line_offset, i % 2);
-
- g_mutex_unlock(&thread->lock);
- }
-
- return NULL;
-}
-
-GpiodTestEventThread *
-gpiod_test_start_event_thread(guint chip_index, guint line_offset, guint period_ms)
+void _gpiod_test_register(struct _gpiod_test_case *test)
{
- GpiodTestEventThread *thread = g_malloc0(sizeof(*thread));
-
- g_mutex_init(&thread->lock);
- g_cond_init(&thread->cond);
-
- thread->chip_index = chip_index;
- thread->line_offset = line_offset;
- thread->period_ms = period_ms;
-
- thread->id = g_thread_new("event-worker", event_worker_func, thread);
-
- return thread;
-}
-
-void gpiod_test_stop_event_thread(GpiodTestEventThread *thread)
-{
- g_mutex_lock(&thread->lock);
- thread->should_stop = TRUE;
- g_cond_broadcast(&thread->cond);
- g_mutex_unlock(&thread->lock);
-
- (void)g_thread_join(thread->id);
-
- g_mutex_clear(&thread->lock);
- g_cond_clear(&thread->cond);
- g_free(thread);
+ tests = g_list_append(tests, test);
}
@@ -13,86 +13,33 @@
#define __GPIOD_TEST_H__
#include <glib.h>
-#include <gpiod.h>
-
-/*
- * These typedefs are needed to make g_autoptr work - it doesn't accept
- * regular 'struct typename' syntax.
- */
-typedef struct gpiod_chip gpiod_chip_struct;
-typedef struct gpiod_line_bulk gpiod_line_bulk_struct;
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_struct, gpiod_chip_unref);
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_line_bulk_struct, gpiod_line_bulk_free);
/* These are private definitions and should not be used directly. */
-typedef void (*_gpiod_test_func)(void);
-typedef struct _gpiod_test_case _GpiodTestCase;
struct _gpiod_test_case {
const gchar *path;
- _gpiod_test_func func;
-
- guint num_chips;
- guint *chip_sizes;
- gint flags;
+ void (*func)(void);
};
-void _gpiod_test_register(_GpiodTestCase *test);
+void _gpiod_test_register(struct _gpiod_test_case *test);
#define _GPIOD_TEST_PATH(_name) \
"/gpiod/" GPIOD_TEST_GROUP "/" G_STRINGIFY(_name)
-enum {
- /* Dummy lines for this test case should have names assigned. */
- GPIOD_TEST_FLAG_NAMED_LINES = (1 << 0),
-};
-
/*
- * Register a test case function. The last argument is the array of numbers
- * of lines per simulated chip.
+ * Register a test case function.
*/
-#define GPIOD_TEST_CASE(_name, _flags, ...) \
- static void _name(void); \
- static guint _##_name##_chip_sizes[] = __VA_ARGS__; \
- static _GpiodTestCase _##_name##_test_case = { \
- .path = _GPIOD_TEST_PATH(_name), \
- .func = _name, \
- .num_chips = G_N_ELEMENTS(_##_name##_chip_sizes), \
- .chip_sizes = _##_name##_chip_sizes, \
- .flags = _flags, \
- }; \
- static __attribute__((constructor)) void \
- _##_name##_test_register(void) \
- { \
- _gpiod_test_register(&_##_name##_test_case); \
- } \
- static void _name(void)
-
-#define GPIOD_TEST_CONSUMER "gpiod-test"
-
-#define gpiod_test_return_if_failed() \
- do { \
- if (g_test_failed()) \
- return; \
- } while (0)
-
-/* Wrappers around libgpiomockup helpers. */
-const gchar *gpiod_test_chip_path(guint idx);
-const gchar *gpiod_test_chip_name(guint idx);
-gint gpiod_test_chip_get_value(guint chip_index, guint line_offset);
-void gpiod_test_chip_set_pull(guint chip_index, guint line_offset, gint pull);
-
-/* Helpers for triggering line events in a separate thread. */
-struct gpiod_test_event_thread;
-typedef struct gpiod_test_event_thread GpiodTestEventThread;
-
-GpiodTestEventThread *
-gpiod_test_start_event_thread(guint chip_index,
- guint line_offset, guint period_ms);
-void gpiod_test_stop_event_thread(GpiodTestEventThread *thread);
-
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(GpiodTestEventThread,
- gpiod_test_stop_event_thread);
+#define GPIOD_TEST_CASE(_name) \
+ static void _gpiod_test_func_##_name(void); \
+ static struct _gpiod_test_case _##_name##_test_case = { \
+ .path = _GPIOD_TEST_PATH(_name), \
+ .func = _gpiod_test_func_##_name, \
+ }; \
+ static __attribute__((constructor)) void \
+ _##_name##_test_register(void) \
+ { \
+ _gpiod_test_register(&_##_name##_test_case); \
+ } \
+ static void _gpiod_test_func_##_name(void)
#endif /* __GPIOD_TEST_H__ */
@@ -736,6 +736,7 @@ static void bank_release(struct refcount *ref)
unsigned int i;
char buf[64];
+ /* FIXME should be based on dirent because num_lines can change. */
for (i = 0; i < bank->num_lines; i++) {
snprintf(buf, sizeof(buf), "line%u/hog", i);
unlinkat(bank->cfs_dir_fd, buf, AT_REMOVEDIR);
deleted file mode 100644
@@ -1,11 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-or-later
-# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-lib_LTLIBRARIES = libgpiomockup.la
-
-libgpiomockup_la_SOURCES = gpio-mockup.c gpio-mockup.h
-libgpiomockup_la_CFLAGS = -Wall -Wextra -g -fvisibility=hidden -std=gnu89
-libgpiomockup_la_CFLAGS += -include $(top_builddir)/config.h
-libgpiomockup_la_CFLAGS += $(KMOD_CFLAGS) $(UDEV_CFLAGS)
-libgpiomockup_la_LDFLAGS = -version-info $(subst .,:,$(ABI_MOCKUP_VERSION))
-libgpiomockup_la_LDFLAGS += $(KMOD_LIBS) $(UDEV_LIBS)
deleted file mode 100644
@@ -1,496 +0,0 @@
-// SPDX-License-Identifier: LGPL-2.1-or-later
-// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-#include <errno.h>
-#include <libkmod.h>
-#include <libudev.h>
-#include <linux/version.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/utsname.h>
-#include <unistd.h>
-
-#include "gpio-mockup.h"
-
-#define EXPORT __attribute__((visibility("default")))
-/*
- * The gpio-mockup features (including the debugfs interface) we're using
- * in this library have first been released in the linux kernel version below.
- */
-#define MIN_KERNEL_VERSION KERNEL_VERSION(5, 10, 0)
-
-struct gpio_mockup_chip {
- char *name;
- char *path;
- unsigned int num;
-};
-
-struct gpio_mockup {
- struct gpio_mockup_chip **chips;
- unsigned int num_chips;
- struct kmod_ctx *kmod;
- struct kmod_module *module;
- int refcount;
-};
-
-static void free_chip(struct gpio_mockup_chip *chip)
-{
- free(chip->name);
- free(chip->path);
- free(chip);
-}
-
-static bool check_kernel_version(void)
-{
- unsigned int major, minor, release;
- struct utsname un;
- int rv;
-
- rv = uname(&un);
- if (rv)
- return false;
-
- rv = sscanf(un.release, "%u.%u.%u", &major, &minor, &release);
- if (rv != 3) {
- errno = EFAULT;
- return false;
- }
-
- if (KERNEL_VERSION(major, minor, release) < MIN_KERNEL_VERSION) {
- errno = EOPNOTSUPP;
- return false;
- }
-
- return true;
-}
-
-EXPORT struct gpio_mockup *gpio_mockup_new(void)
-{
- struct gpio_mockup *ctx;
- const char *modpath;
- int rv;
-
- if (!check_kernel_version())
- goto err_out;
-
- ctx = malloc(sizeof(*ctx));
- if (!ctx)
- goto err_out;
-
- memset(ctx, 0, sizeof(*ctx));
- ctx->refcount = 1;
-
- ctx->kmod = kmod_new(NULL, NULL);
- if (!ctx->kmod)
- goto err_free_kmod;
-
- rv = kmod_module_new_from_name(ctx->kmod, "gpio-mockup", &ctx->module);
- if (rv)
- goto err_unref_module;
-
- /* First see if we can find the module. */
- modpath = kmod_module_get_path(ctx->module);
- if (!modpath) {
- errno = ENOENT;
- goto err_unref_module;
- }
-
- /*
- * Then see if we can freely load and unload it. If it's already
- * loaded - no problem, we'll remove it next anyway.
- */
- rv = kmod_module_probe_insert_module(ctx->module,
- KMOD_PROBE_IGNORE_LOADED,
- "gpio_mockup_ranges=-1,4",
- NULL, NULL, NULL);
- if (rv)
- goto err_unref_module;
-
- /* We need to check that the gpio-mockup debugfs directory exists. */
- rv = access("/sys/kernel/debug/gpio-mockup", R_OK | W_OK);
- if (rv)
- goto err_unref_module;
-
- rv = kmod_module_remove_module(ctx->module, 0);
- if (rv)
- goto err_unref_module;
-
- return ctx;
-
-err_unref_module:
- kmod_unref(ctx->kmod);
-err_free_kmod:
- free(ctx);
-err_out:
- return NULL;
-}
-
-EXPORT void gpio_mockup_ref(struct gpio_mockup *ctx)
-{
- ctx->refcount++;
-}
-
-EXPORT void gpio_mockup_unref(struct gpio_mockup *ctx)
-{
- ctx->refcount--;
-
- if (ctx->refcount == 0) {
- if (ctx->chips)
- gpio_mockup_remove(ctx);
-
- kmod_module_unref(ctx->module);
- kmod_unref(ctx->kmod);
- free(ctx);
- }
-}
-
-static char *make_module_param_string(unsigned int num_chips,
- const unsigned int *num_lines, int flags)
-{
- char *params, *new;
- unsigned int i;
- int rv;
-
- params = strdup("gpio_mockup_ranges=");
- if (!params)
- return NULL;
-
- for (i = 0; i < num_chips; i++) {
- rv = asprintf(&new, "%s-1,%u,", params, num_lines[i]);
- free(params);
- if (rv < 0)
- return NULL;
-
- params = new;
- }
- params[strlen(params) - 1] = '\0'; /* Remove the last comma. */
-
- if (flags & GPIO_MOCKUP_FLAG_NAMED_LINES) {
- rv = asprintf(&new, "%s gpio_mockup_named_lines", params);
- free(params);
- if (rv < 0)
- return NULL;
-
- params = new;
- }
-
- return params;
-}
-
-static bool devpath_is_mockup(const char *devpath)
-{
- static const char mockup_devpath[] = "/devices/platform/gpio-mockup";
-
- return !strncmp(devpath, mockup_devpath, sizeof(mockup_devpath) - 1);
-}
-
-static int chipcmp(const void *c1, const void *c2)
-{
- const struct gpio_mockup_chip *chip1, *chip2;
-
- chip1 = *(const struct gpio_mockup_chip **)c1;
- chip2 = *(const struct gpio_mockup_chip **)c2;
-
- return chip1->num > chip2->num;
-}
-
-static struct gpio_mockup_chip *make_chip(const char *sysname,
- const char *devnode)
-{
- struct gpio_mockup_chip *chip;
- int rv;
-
- chip = malloc(sizeof(*chip));
- if (!chip)
- return NULL;
-
- chip->name = strdup(sysname);
- if (!chip->name) {
- free(chip);
- return NULL;
- }
-
- chip->path = strdup(devnode);
- if (!chip->path) {
- free(chip->name);
- free(chip);
- return NULL;
- }
-
- rv = sscanf(sysname, "gpiochip%u", &chip->num);
- if (rv != 1) {
- errno = EINVAL;
- free(chip->path);
- free(chip->name);
- free(chip);
- return NULL;
- }
-
- return chip;
-}
-
-EXPORT int gpio_mockup_probe(struct gpio_mockup *ctx, unsigned int num_chips,
- const unsigned int *chip_sizes, int flags)
-{
- const char *devpath, *devnode, *sysname, *action;
- struct gpio_mockup_chip *chip;
- struct udev_monitor *monitor;
- unsigned int i, detected = 0;
- struct udev_device *dev;
- struct udev *udev_ctx;
- struct pollfd pfd;
- char *params;
- int rv;
-
- if (ctx->chips) {
- errno = EBUSY;
- goto err_out;
- }
-
- if (num_chips < 1) {
- errno = EINVAL;
- goto err_out;
- }
-
- udev_ctx = udev_new();
- if (!udev_ctx)
- goto err_out;
-
- monitor = udev_monitor_new_from_netlink(udev_ctx, "udev");
- if (!monitor)
- goto err_unref_udev;
-
- rv = udev_monitor_filter_add_match_subsystem_devtype(monitor,
- "gpio", NULL);
- if (rv < 0)
- goto err_unref_monitor;
-
- rv = udev_monitor_enable_receiving(monitor);
- if (rv < 0)
- goto err_unref_monitor;
-
- params = make_module_param_string(num_chips, chip_sizes, flags);
- if (!params)
- goto err_unref_monitor;
-
- rv = kmod_module_probe_insert_module(ctx->module,
- KMOD_PROBE_FAIL_ON_LOADED,
- params, NULL, NULL, NULL);
- free(params);
- if (rv)
- goto err_unref_monitor;
-
- ctx->chips = calloc(num_chips, sizeof(struct gpio_mockup_chip *));
- if (!ctx->chips)
- goto err_remove_module;
-
- ctx->num_chips = num_chips;
-
- pfd.fd = udev_monitor_get_fd(monitor);
- pfd.events = POLLIN | POLLPRI;
-
- while (num_chips > detected) {
- rv = poll(&pfd, 1, 5000);
- if (rv < 0) {
- goto err_free_chips;
- } if (rv == 0) {
- errno = EAGAIN;
- goto err_free_chips;
- }
-
- dev = udev_monitor_receive_device(monitor);
- if (!dev)
- goto err_free_chips;
-
- devpath = udev_device_get_devpath(dev);
- devnode = udev_device_get_devnode(dev);
- sysname = udev_device_get_sysname(dev);
- action = udev_device_get_action(dev);
-
- if (!devpath || !devnode || !sysname ||
- !devpath_is_mockup(devpath) || strcmp(action, "add") != 0) {
- udev_device_unref(dev);
- continue;
- }
-
- chip = make_chip(sysname, devnode);
- if (!chip)
- goto err_free_chips;
-
- ctx->chips[detected++] = chip;
- udev_device_unref(dev);
- }
-
- udev_monitor_unref(monitor);
- udev_unref(udev_ctx);
-
- /*
- * 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 to the
- * order in which the chips were defined in the TEST_DEFINE()
- * macro.
- *
- * Once all gpiochips are there, sort them by chip number.
- */
- qsort(ctx->chips, ctx->num_chips, sizeof(*ctx->chips), chipcmp);
-
- return 0;
-
-err_free_chips:
- for (i = 0; i < detected; i++)
- free_chip(ctx->chips[i]);
- free(ctx->chips);
-err_remove_module:
- kmod_module_remove_module(ctx->module, 0);
-err_unref_monitor:
- udev_monitor_unref(monitor);
-err_unref_udev:
- udev_unref(udev_ctx);
-err_out:
- return -1;
-}
-
-EXPORT int gpio_mockup_remove(struct gpio_mockup *ctx)
-{
- unsigned int i;
- int rv;
-
- if (!ctx->chips) {
- errno = ENODEV;
- return -1;
- }
-
- rv = kmod_module_remove_module(ctx->module, 0);
- if (rv)
- return -1;
-
- for (i = 0; i < ctx->num_chips; i++)
- free_chip(ctx->chips[i]);
- free(ctx->chips);
- ctx->chips = NULL;
- ctx->num_chips = 0;
-
- return 0;
-}
-
-static bool index_valid(struct gpio_mockup *ctx, unsigned int idx)
-{
- if (!ctx->chips) {
- errno = ENODEV;
- return false;
- }
-
- if (idx >= ctx->num_chips) {
- errno = EINVAL;
- return false;
- }
-
- return true;
-}
-
-EXPORT const char *
-gpio_mockup_chip_name(struct gpio_mockup *ctx, unsigned int idx)
-{
- if (!index_valid(ctx, idx))
- return NULL;
-
- return ctx->chips[idx]->name;
-}
-
-EXPORT const char *
-gpio_mockup_chip_path(struct gpio_mockup *ctx, unsigned int idx)
-{
- if (!index_valid(ctx, idx))
- return NULL;
-
- return ctx->chips[idx]->path;
-}
-
-EXPORT int gpio_mockup_chip_num(struct gpio_mockup *ctx, unsigned int idx)
-{
- if (!index_valid(ctx, idx))
- return -1;
-
- return ctx->chips[idx]->num;
-}
-
-static int debugfs_open(unsigned int chip_num,
- unsigned int line_offset, int flags)
-{
- char *path;
- int fd, rv;
-
- rv = asprintf(&path, "/sys/kernel/debug/gpio-mockup/gpiochip%u/%u",
- chip_num, line_offset);
- if (rv < 0)
- return -1;
-
- fd = open(path, flags);
- free(path);
-
- return fd;
-}
-
-EXPORT int gpio_mockup_get_value(struct gpio_mockup *ctx,
- unsigned int chip_idx,
- unsigned int line_offset)
-{
- ssize_t rd;
- char buf;
- int fd;
-
- if (!index_valid(ctx, chip_idx))
- return -1;
-
- fd = debugfs_open(ctx->chips[chip_idx]->num, line_offset, O_RDONLY);
- if (fd < 0)
- return fd;
-
- rd = read(fd, &buf, 1);
- close(fd);
- if (rd < 0)
- return rd;
- if (rd != 1) {
- errno = ENOTTY;
- return -1;
- }
- if (buf != '0' && buf != '1') {
- errno = EIO;
- return -1;
- }
-
- return buf == '0' ? 0 : 1;
-}
-
-EXPORT int gpio_mockup_set_pull(struct gpio_mockup *ctx,
- unsigned int chip_idx,
- unsigned int line_offset, int pull)
-{
- char buf[2];
- ssize_t wr;
- int fd;
-
- if (!index_valid(ctx, chip_idx))
- return -1;
-
- fd = debugfs_open(ctx->chips[chip_idx]->num, line_offset, O_WRONLY);
- if (fd < 0)
- return fd;
-
- buf[0] = pull ? '1' : '0';
- buf[1] = '\n';
-
- wr = write(fd, &buf, sizeof(buf));
- close(fd);
- if (wr < 0)
- return wr;
- if (wr != sizeof(buf)) {
- errno = EAGAIN;
- return -1;
- }
-
- return 0;
-}
deleted file mode 100644
@@ -1,36 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/* SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com> */
-
-#ifndef __GPIO_MOCKUP_H__
-#define __GPIO_MOCKUP_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct gpio_mockup;
-
-#define GPIO_MOCKUP_FLAG_NAMED_LINES (1 << 0)
-
-struct gpio_mockup *gpio_mockup_new(void);
-void gpio_mockup_ref(struct gpio_mockup *ctx);
-void gpio_mockup_unref(struct gpio_mockup *ctx);
-
-int gpio_mockup_probe(struct gpio_mockup *ctx, unsigned int num_chips,
- const unsigned int *chip_sizes, int flags);
-int gpio_mockup_remove(struct gpio_mockup *ctx);
-
-const char *gpio_mockup_chip_name(struct gpio_mockup *ctx, unsigned int idx);
-const char *gpio_mockup_chip_path(struct gpio_mockup *ctx, unsigned int idx);
-int gpio_mockup_chip_num(struct gpio_mockup *ctx, unsigned int idx);
-
-int gpio_mockup_get_value(struct gpio_mockup *ctx,
- unsigned int chip_idx, unsigned int line_offset);
-int gpio_mockup_set_pull(struct gpio_mockup *ctx, unsigned int chip_idx,
- unsigned int line_offset, int pull);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#endif /* __GPIO_MOCKUP_H__ */
@@ -2,229 +2,171 @@
// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
#include <errno.h>
+#include <glib.h>
+#include <gpiod.h>
#include "gpiod-test.h"
+#include "gpiod-test-helpers.h"
+#include "gpiod-test-sim.h"
#define GPIOD_TEST_GROUP "chip"
-GPIOD_TEST_CASE(is_gpiochip_good, 0, { 8 })
+GPIOD_TEST_CASE(open_chip_good)
{
- g_assert_true(gpiod_is_gpiochip_device(gpiod_test_chip_path(0)));
-}
-
-GPIOD_TEST_CASE(is_gpiochip_bad, 0, { 8 })
-{
- g_assert_false(gpiod_is_gpiochip_device("/dev/null"));
-}
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new(NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
-GPIOD_TEST_CASE(is_gpiochip_nonexistent, 0, { 8 })
-{
- g_assert_false(gpiod_is_gpiochip_device("/dev/nonexistent_gpiochip"));
+ chip = gpiod_chip_open(g_gpiosim_chip_get_dev_path(sim));
+ g_assert_nonnull(chip);
}
-GPIOD_TEST_CASE(open_good, 0, { 8 })
+GPIOD_TEST_CASE(open_chip_nonexistent)
{
- g_autoptr(gpiod_chip_struct) chip = NULL;
+ g_autoptr(struct_gpiod_chip) chip = NULL;
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
+ chip = gpiod_chip_open("/dev/nonexistent");
+ g_assert_null(chip);
+ gpiod_test_expect_errno(ENOENT);
}
-GPIOD_TEST_CASE(open_nonexistent, 0, { 8 })
+GPIOD_TEST_CASE(open_chip_not_a_character_device)
{
- struct gpiod_chip *chip;
+ g_autoptr(struct_gpiod_chip) chip = NULL;
- chip = gpiod_chip_open("/dev/nonexistent_gpiochip");
+ chip = gpiod_chip_open("/tmp");
g_assert_null(chip);
- g_assert_cmpint(errno, ==, ENOENT);
+ gpiod_test_expect_errno(ENOTTY);
}
-GPIOD_TEST_CASE(open_notty, 0, { 8 })
+GPIOD_TEST_CASE(open_chip_not_a_gpio_device)
{
- struct gpiod_chip *chip;
+ g_autoptr(struct_gpiod_chip) chip = NULL;
chip = gpiod_chip_open("/dev/null");
g_assert_null(chip);
- g_assert_cmpint(errno, ==, ENOTTY);
+ gpiod_test_expect_errno(ENODEV);
}
-GPIOD_TEST_CASE(get_name, 0, { 8, 8, 8})
+GPIOD_TEST_CASE(get_chip_name)
{
- g_autoptr(gpiod_chip_struct) chip0 = NULL;
- g_autoptr(gpiod_chip_struct) chip1 = NULL;
- g_autoptr(gpiod_chip_struct) chip2 = NULL;
-
- chip0 = gpiod_chip_open(gpiod_test_chip_path(0));
- chip1 = gpiod_chip_open(gpiod_test_chip_path(1));
- chip2 = gpiod_chip_open(gpiod_test_chip_path(2));
-
- g_assert_nonnull(chip0);
- g_assert_nonnull(chip1);
- g_assert_nonnull(chip2);
- gpiod_test_return_if_failed();
-
- g_assert_cmpstr(gpiod_chip_get_name(chip0), ==,
- gpiod_test_chip_name(0));
- g_assert_cmpstr(gpiod_chip_get_name(chip1), ==,
- gpiod_test_chip_name(1));
- g_assert_cmpstr(gpiod_chip_get_name(chip2), ==,
- gpiod_test_chip_name(2));
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new(NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ g_assert_cmpstr(gpiod_chip_get_name(chip), ==,
+ g_gpiosim_chip_get_name(sim));
}
-GPIOD_TEST_CASE(get_label, 0, { 8, 8, 8})
+GPIOD_TEST_CASE(get_chip_label)
{
- g_autoptr(gpiod_chip_struct) chip0 = NULL;
- g_autoptr(gpiod_chip_struct) chip1 = NULL;
- g_autoptr(gpiod_chip_struct) chip2 = NULL;
-
- chip0 = gpiod_chip_open(gpiod_test_chip_path(0));
- chip1 = gpiod_chip_open(gpiod_test_chip_path(1));
- chip2 = gpiod_chip_open(gpiod_test_chip_path(2));
-
- g_assert_nonnull(chip0);
- g_assert_nonnull(chip1);
- g_assert_nonnull(chip2);
- gpiod_test_return_if_failed();
-
- g_assert_cmpstr(gpiod_chip_get_label(chip0), ==, "gpio-mockup-A");
- g_assert_cmpstr(gpiod_chip_get_label(chip1), ==, "gpio-mockup-B");
- g_assert_cmpstr(gpiod_chip_get_label(chip2), ==, "gpio-mockup-C");
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("label", "foobar",
+ NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ g_assert_cmpstr(gpiod_chip_get_label(chip), ==, "foobar");
}
-GPIOD_TEST_CASE(num_lines, 0, { 1, 4, 8, 16, 32 })
+GPIOD_TEST_CASE(get_chip_path)
{
- g_autoptr(gpiod_chip_struct) chip0 = NULL;
- g_autoptr(gpiod_chip_struct) chip1 = NULL;
- g_autoptr(gpiod_chip_struct) chip2 = NULL;
- g_autoptr(gpiod_chip_struct) chip3 = NULL;
- g_autoptr(gpiod_chip_struct) chip4 = NULL;
-
- chip0 = gpiod_chip_open(gpiod_test_chip_path(0));
- chip1 = gpiod_chip_open(gpiod_test_chip_path(1));
- chip2 = gpiod_chip_open(gpiod_test_chip_path(2));
- chip3 = gpiod_chip_open(gpiod_test_chip_path(3));
- chip4 = gpiod_chip_open(gpiod_test_chip_path(4));
-
- g_assert_nonnull(chip0);
- g_assert_nonnull(chip1);
- g_assert_nonnull(chip2);
- g_assert_nonnull(chip3);
- g_assert_nonnull(chip4);
- gpiod_test_return_if_failed();
-
- g_assert_cmpuint(gpiod_chip_get_num_lines(chip0), ==, 1);
- g_assert_cmpuint(gpiod_chip_get_num_lines(chip1), ==, 4);
- g_assert_cmpuint(gpiod_chip_get_num_lines(chip2), ==, 8);
- g_assert_cmpuint(gpiod_chip_get_num_lines(chip3), ==, 16);
- g_assert_cmpuint(gpiod_chip_get_num_lines(chip4), ==, 32);
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new(NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ const gchar *path = g_gpiosim_chip_get_dev_path(sim);
+
+ chip = gpiod_test_open_chip_or_fail(path);
+
+ g_assert_cmpstr(gpiod_chip_get_path(chip), ==, path);
}
-GPIOD_TEST_CASE(get_line, 0, { 16 })
+GPIOD_TEST_CASE(get_num_lines)
{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line *line;
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 16, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
- line = gpiod_chip_get_line(chip, 3);
- g_assert_nonnull(line);
- g_assert_cmpuint(gpiod_line_offset(line), ==, 3);
+ g_assert_cmpuint(gpiod_chip_get_num_lines(chip), ==, 16);
}
-GPIOD_TEST_CASE(get_lines, 0, { 16 })
+GPIOD_TEST_CASE(get_fd)
{
- struct gpiod_line *line0, *line1, *line2, *line3;
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- guint offsets[4];
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new(NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- offsets[0] = 1;
- offsets[1] = 3;
- offsets[2] = 4;
- offsets[3] = 7;
-
- bulk = gpiod_chip_get_lines(chip, offsets, 4);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
- g_assert_cmpuint(gpiod_line_bulk_num_lines(bulk), ==, 4);
- gpiod_test_return_if_failed();
-
- line0 = gpiod_line_bulk_get_line(bulk, 0);
- line1 = gpiod_line_bulk_get_line(bulk, 1);
- line2 = gpiod_line_bulk_get_line(bulk, 2);
- line3 = gpiod_line_bulk_get_line(bulk, 3);
-
- g_assert_cmpuint(gpiod_line_offset(line0), ==, 1);
- g_assert_cmpuint(gpiod_line_offset(line1), ==, 3);
- g_assert_cmpuint(gpiod_line_offset(line2), ==, 4);
- g_assert_cmpuint(gpiod_line_offset(line3), ==, 7);
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ g_assert_cmpint(gpiod_chip_get_fd(chip), >=, 0);
}
-GPIOD_TEST_CASE(get_all_lines, 0, { 4 })
+GPIOD_TEST_CASE(find_line_bad)
{
- struct gpiod_line *line0, *line1, *line2, *line3;
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
-
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- bulk = gpiod_chip_get_all_lines(chip);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
- g_assert_cmpuint(gpiod_line_bulk_num_lines(bulk), ==, 4);
- gpiod_test_return_if_failed();
-
- line0 = gpiod_line_bulk_get_line(bulk, 0);
- line1 = gpiod_line_bulk_get_line(bulk, 1);
- line2 = gpiod_line_bulk_get_line(bulk, 2);
- line3 = gpiod_line_bulk_get_line(bulk, 3);
-
- g_assert_cmpuint(gpiod_line_offset(line0), ==, 0);
- g_assert_cmpuint(gpiod_line_offset(line1), ==, 1);
- g_assert_cmpuint(gpiod_line_offset(line2), ==, 2);
- g_assert_cmpuint(gpiod_line_offset(line3), ==, 3);
+ static const struct gpiod_test_line_name names[] = {
+ { .offset = 1, .name = "foo", },
+ { .offset = 2, .name = "bar", },
+ { .offset = 4, .name = "baz", },
+ { .offset = 5, .name = "xyz", },
+ { }
+ };
+
+ g_autoptr(GPIOSimChip) sim = NULL;
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+
+ sim = g_gpiosim_chip_new(
+ "num-lines", 8,
+ "line-names", gpiod_test_package_line_names(names),
+ NULL);
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ g_assert_cmpint(gpiod_chip_find_line(chip, "nonexistent"), ==, -1);
+ gpiod_test_expect_errno(ENOENT);
}
-GPIOD_TEST_CASE(find_line_good, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 })
+GPIOD_TEST_CASE(find_line_good)
{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line *line;
- int offset;
+ static const struct gpiod_test_line_name names[] = {
+ { .offset = 1, .name = "foo", },
+ { .offset = 2, .name = "bar", },
+ { .offset = 4, .name = "baz", },
+ { .offset = 5, .name = "xyz", },
+ { }
+ };
- chip = gpiod_chip_open(gpiod_test_chip_path(1));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
+ g_autoptr(GPIOSimChip) sim = NULL;
+ g_autoptr(struct_gpiod_chip) chip = NULL;
- offset = gpiod_chip_find_line(chip, "gpio-mockup-B-4");
- g_assert_cmpint(offset, ==, 4);
- gpiod_test_return_if_failed();
+ sim = g_gpiosim_chip_new(
+ "num-lines", 8,
+ "line-names", gpiod_test_package_line_names(names),
+ NULL);
- line = gpiod_chip_get_line(chip, 4);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
- g_assert_cmpstr(gpiod_line_name(line), ==, "gpio-mockup-B-4");
+ g_assert_cmpint(gpiod_chip_find_line(chip, "baz"), ==, 4);
}
-GPIOD_TEST_CASE(find_line_unique_not_found,
- GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 })
+/* Verify that for duplicated line names, the first one is returned. */
+GPIOD_TEST_CASE(find_line_duplicate)
{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- int offset;
+ static const struct gpiod_test_line_name names[] = {
+ { .offset = 1, .name = "foo", },
+ { .offset = 2, .name = "baz", },
+ { .offset = 4, .name = "baz", },
+ { .offset = 5, .name = "xyz", },
+ { }
+ };
- chip = gpiod_chip_open(gpiod_test_chip_path(1));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
+ g_autoptr(GPIOSimChip) sim = NULL;
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+
+ sim = g_gpiosim_chip_new(
+ "num-lines", 8,
+ "line-names", gpiod_test_package_line_names(names),
+ NULL);
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
- offset = gpiod_chip_find_line(chip, "nonexistent");
- g_assert_cmpint(offset, ==, -1);
- g_assert_cmpint(errno, ==, ENOENT);
+ g_assert_cmpint(gpiod_chip_find_line(chip, "baz"), ==, 2);
}
new file mode 100644
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
+
+#include <glib.h>
+#include <gpiod.h>
+#include <poll.h>
+
+#include "gpiod-test.h"
+#include "gpiod-test-helpers.h"
+#include "gpiod-test-sim.h"
+
+#define GPIOD_TEST_GROUP "edge-event"
+
+GPIOD_TEST_CASE(edge_event_buffer_capacity)
+{
+ g_autoptr(struct_gpiod_edge_event_buffer) buffer = NULL;
+
+ buffer = gpiod_test_create_edge_event_buffer_or_fail(32);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_capacity(buffer), ==, 32);
+}
+
+GPIOD_TEST_CASE(edge_event_buffer_max_capacity)
+{
+ g_autoptr(struct_gpiod_edge_event_buffer) buffer = NULL;
+
+ buffer = gpiod_test_create_edge_event_buffer_or_fail(16 * 64 * 2);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_capacity(buffer),
+ ==, 16 * 64);
+}
+
+GPIOD_TEST_CASE(edge_event_wait_timeout)
+{
+ static const guint offset = 4;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_BOTH);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000);
+ g_assert_cmpint(ret, ==, 0);
+}
+
+GPIOD_TEST_CASE(cannot_request_lines_in_output_mode_with_edge_detection)
+{
+ static const guint offset = 4;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_BOTH);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+ g_assert_null(request);
+ gpiod_test_expect_errno(EINVAL);
+}
+
+static gpointer falling_and_rising_edge_events(gpointer data)
+{
+ GPIOSimChip *sim = data;
+
+ g_usleep(50);
+
+ g_gpiosim_chip_set_pull(sim, 2, G_GPIOSIM_PULL_UP);
+
+ g_usleep(50);
+
+ g_gpiosim_chip_set_pull(sim, 2, G_GPIOSIM_PULL_DOWN);
+
+ return NULL;
+}
+
+GPIOD_TEST_CASE(read_both_events)
+{
+ static const guint offset = 2;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(GThread) thread = NULL;
+ g_autoptr(struct_gpiod_edge_event_buffer) buffer = NULL;
+ struct gpiod_edge_event *event;
+ guint64 ts_rising, ts_falling;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ buffer = gpiod_test_create_edge_event_buffer_or_fail(64);
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_BOTH);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ thread = g_thread_new("request-release",
+ falling_and_rising_edge_events, sim);
+ g_thread_ref(thread);
+
+ /* First event. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ ret = gpiod_line_request_edge_event_read(request, buffer, 1);
+ g_assert_cmpint(ret, ==, 1);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_num_events(buffer), ==, 1);
+ event = gpiod_edge_event_buffer_get_event(buffer, 0);
+ g_assert_nonnull(event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_edge_event_get_event_type(event),
+ ==, GPIOD_EDGE_EVENT_RISING_EDGE);
+ g_assert_cmpuint(gpiod_edge_event_get_line_offset(event), ==, 2);
+ ts_rising = gpiod_edge_event_get_timestamp(event);
+
+ /* Second event. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ ret = gpiod_line_request_edge_event_read(request, buffer, 1);
+ g_assert_cmpint(ret, ==, 1);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_num_events(buffer), ==, 1);
+ event = gpiod_edge_event_buffer_get_event(buffer, 0);
+ g_assert_nonnull(event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_edge_event_get_event_type(event),
+ ==, GPIOD_EDGE_EVENT_FALLING_EDGE);
+ g_assert_cmpuint(gpiod_edge_event_get_line_offset(event), ==, 2);
+ ts_falling = gpiod_edge_event_get_timestamp(event);
+
+ g_thread_join(thread);
+
+ g_assert_cmpuint(ts_falling, >, ts_rising);
+}
+
+GPIOD_TEST_CASE(read_rising_edge_event)
+{
+ static const guint offset = 2;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(GThread) thread = NULL;
+ g_autoptr(struct_gpiod_edge_event_buffer) buffer = NULL;
+ struct gpiod_edge_event *event;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ buffer = gpiod_test_create_edge_event_buffer_or_fail(64);
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_RISING);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ thread = g_thread_new("edge-generator",
+ falling_and_rising_edge_events, sim);
+ g_thread_ref(thread);
+
+ /* First event. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ ret = gpiod_line_request_edge_event_read(request, buffer, 1);
+ g_assert_cmpint(ret, ==, 1);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_num_events(buffer), ==, 1);
+ event = gpiod_edge_event_buffer_get_event(buffer, 0);
+ g_assert_nonnull(event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_edge_event_get_event_type(event),
+ ==, GPIOD_EDGE_EVENT_RISING_EDGE);
+ g_assert_cmpuint(gpiod_edge_event_get_line_offset(event), ==, 2);
+
+ /* Second event. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000);
+ g_assert_cmpint(ret, ==, 0); /* Time-out. */
+
+ g_thread_join(thread);
+}
+
+GPIOD_TEST_CASE(read_falling_edge_event)
+{
+ static const guint offset = 2;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(GThread) thread = NULL;
+ g_autoptr(struct_gpiod_edge_event_buffer) buffer = NULL;
+ struct gpiod_edge_event *event;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ buffer = gpiod_test_create_edge_event_buffer_or_fail(64);
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_FALLING);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ thread = g_thread_new("request-release",
+ falling_and_rising_edge_events, sim);
+ g_thread_ref(thread);
+
+ /* First event is the second generated. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ ret = gpiod_line_request_edge_event_read(request, buffer, 1);
+ g_assert_cmpint(ret, ==, 1);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_num_events(buffer), ==, 1);
+ event = gpiod_edge_event_buffer_get_event(buffer, 0);
+ g_assert_nonnull(event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_edge_event_get_event_type(event),
+ ==, GPIOD_EDGE_EVENT_FALLING_EDGE);
+ g_assert_cmpuint(gpiod_edge_event_get_line_offset(event), ==, 2);
+
+ /* No more events. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000);
+ g_assert_cmpint(ret, ==, 0); /* Time-out. */
+
+ g_thread_join(thread);
+}
+
+GPIOD_TEST_CASE(read_rising_edge_event_polled)
+{
+ static const guint offset = 2;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(GThread) thread = NULL;
+ g_autoptr(struct_gpiod_edge_event_buffer) buffer = NULL;
+ struct gpiod_edge_event *event;
+ struct timespec ts;
+ struct pollfd pfd;
+ gint ret, fd;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ buffer = gpiod_test_create_edge_event_buffer_or_fail(64);
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_RISING);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ thread = g_thread_new("edge-generator",
+ falling_and_rising_edge_events, sim);
+ g_thread_ref(thread);
+
+ /* First event. */
+
+ fd = gpiod_line_request_get_fd(request);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = fd;
+ pfd.events = POLLIN | POLLPRI;
+
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+
+ ret = ppoll(&pfd, 1, &ts, NULL);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ ret = gpiod_line_request_edge_event_read(request, buffer, 1);
+ g_assert_cmpint(ret, ==, 1);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_num_events(buffer), ==, 1);
+ event = gpiod_edge_event_buffer_get_event(buffer, 0);
+ g_assert_nonnull(event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_edge_event_get_event_type(event),
+ ==, GPIOD_EDGE_EVENT_RISING_EDGE);
+ g_assert_cmpuint(gpiod_edge_event_get_line_offset(event), ==, 2);
+
+ /* Second event. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000);
+ g_assert_cmpint(ret, ==, 0); /* Time-out. */
+
+ g_thread_join(thread);
+}
+
+static gpointer rising_edge_events_on_two_offsets(gpointer data)
+{
+ GPIOSimChip *sim = data;
+
+ g_usleep(50);
+
+ g_gpiosim_chip_set_pull(sim, 2, G_GPIOSIM_PULL_UP);
+
+ g_usleep(50);
+
+ g_gpiosim_chip_set_pull(sim, 3, G_GPIOSIM_PULL_UP);
+
+ return NULL;
+}
+
+GPIOD_TEST_CASE(seqno)
+{
+ static const guint offsets[] = { 2, 3 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(GThread) thread = NULL;
+ g_autoptr(struct_gpiod_edge_event_buffer) buffer = NULL;
+ struct gpiod_edge_event *event;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ buffer = gpiod_test_create_edge_event_buffer_or_fail(64);
+
+ gpiod_request_config_set_offsets(req_cfg, 2, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_BOTH);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ thread = g_thread_new("request-release",
+ rising_edge_events_on_two_offsets, sim);
+ g_thread_ref(thread);
+
+ /* First event. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ ret = gpiod_line_request_edge_event_read(request, buffer, 1);
+ g_assert_cmpint(ret, ==, 1);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_num_events(buffer), ==, 1);
+ event = gpiod_edge_event_buffer_get_event(buffer, 0);
+ g_assert_nonnull(event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_get_line_offset(event), ==, 2);
+ g_assert_cmpuint(gpiod_edge_event_get_global_seqno(event), ==, 1);
+ g_assert_cmpuint(gpiod_edge_event_get_line_seqno(event), ==, 1);
+
+ /* Second event. */
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ ret = gpiod_line_request_edge_event_read(request, buffer, 1);
+ g_assert_cmpint(ret, ==, 1);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_buffer_get_num_events(buffer), ==, 1);
+ event = gpiod_edge_event_buffer_get_event(buffer, 0);
+ g_assert_nonnull(event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpuint(gpiod_edge_event_get_line_offset(event), ==, 3);
+ g_assert_cmpuint(gpiod_edge_event_get_global_seqno(event), ==, 2);
+ g_assert_cmpuint(gpiod_edge_event_get_line_seqno(event), ==, 1);
+}
+
+GPIOD_TEST_CASE(event_copy)
+{
+ static const guint offset = 2;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(GThread) thread = NULL;
+ g_autoptr(struct_gpiod_edge_event_buffer) buffer = NULL;
+ g_autoptr(struct_gpiod_edge_event) copy = NULL;
+ struct gpiod_edge_event *event;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ buffer = gpiod_test_create_edge_event_buffer_or_fail(64);
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_BOTH);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ g_gpiosim_chip_set_pull(sim, 2, G_GPIOSIM_PULL_UP);
+
+ ret = gpiod_line_request_edge_event_wait(request, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_edge_event_read(request, buffer, 1);
+ g_assert_cmpint(ret, ==, 1);
+ gpiod_test_return_if_failed();
+
+ event = gpiod_edge_event_buffer_get_event(buffer, 0);
+ g_assert_nonnull(event);
+ gpiod_test_return_if_failed();
+
+ copy = gpiod_edge_event_copy(event);
+ g_assert_nonnull(copy);
+ g_assert_true(copy != event);
+}
deleted file mode 100644
@@ -1,908 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-#include <errno.h>
-#include <unistd.h>
-
-#include "gpiod-test.h"
-
-#define GPIOD_TEST_GROUP "event"
-
-GPIOD_TEST_CASE(rising_edge_good, 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_rising_edge_events(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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);
-}
-
-GPIOD_TEST_CASE(falling_edge_good, 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_falling_edge_events(line,
- GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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);
-}
-
-GPIOD_TEST_CASE(rising_edge_ignore_falling, 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[3];
- 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_rising_edge_events(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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[0]);
- g_assert_cmpint(ret, ==, 0);
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 1);
- ret = gpiod_line_event_read(line, &ev[1]);
- g_assert_cmpint(ret, ==, 0);
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 1);
- ret = gpiod_line_event_read(line, &ev[2]);
- g_assert_cmpint(ret, ==, 0);
-
- g_assert_cmpint(ev[0].event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
- g_assert_cmpint(ev[1].event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
- g_assert_cmpint(ev[2].event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
-}
-
-GPIOD_TEST_CASE(both_edges, 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(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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_active_low, 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_ACTIVE_LOW);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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(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_DISABLED);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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);
- gpiod_test_return_if_failed();
-
- 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);
- gpiod_test_return_if_failed();
-
- 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;
- 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_falling_edge_events_flags(line,
- GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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);
-}
-
-GPIOD_TEST_CASE(get_value, 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();
-
- gpiod_test_chip_set_pull(0, 7, 1);
-
- ret = gpiod_line_request_falling_edge_events(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_get_value(line);
- g_assert_cmpint(ret, ==, 1);
-
- 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);
-}
-
-GPIOD_TEST_CASE(get_value_active_low, 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();
-
- gpiod_test_chip_set_pull(0, 7, 1);
-
- ret = gpiod_line_request_falling_edge_events_flags(line,
- GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_get_value(line);
- 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);
-}
-
-GPIOD_TEST_CASE(get_values, 0, { 8 })
-{
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line *line;
- gint i, ret, vals[8];
-
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- bulk = gpiod_line_bulk_new(8);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- for (i = 0; i < 8; i++) {
- line = gpiod_chip_get_line(chip, i);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulk, line);
- gpiod_test_chip_set_pull(0, i, 1);
- }
-
- ret = gpiod_line_request_bulk_rising_edge_events(bulk,
- GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- memset(vals, 0, sizeof(vals));
- ret = gpiod_line_get_value_bulk(bulk, vals);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(vals[0], ==, 1);
- g_assert_cmpint(vals[1], ==, 1);
- g_assert_cmpint(vals[2], ==, 1);
- g_assert_cmpint(vals[3], ==, 1);
- g_assert_cmpint(vals[4], ==, 1);
- g_assert_cmpint(vals[5], ==, 1);
- g_assert_cmpint(vals[6], ==, 1);
- g_assert_cmpint(vals[7], ==, 1);
-
- gpiod_test_chip_set_pull(0, 1, 0);
- gpiod_test_chip_set_pull(0, 3, 0);
- gpiod_test_chip_set_pull(0, 4, 0);
- gpiod_test_chip_set_pull(0, 7, 0);
-
- memset(vals, 0, sizeof(vals));
- ret = gpiod_line_get_value_bulk(bulk, vals);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(vals[0], ==, 1);
- g_assert_cmpint(vals[1], ==, 0);
- g_assert_cmpint(vals[2], ==, 1);
- g_assert_cmpint(vals[3], ==, 0);
- g_assert_cmpint(vals[4], ==, 0);
- g_assert_cmpint(vals[5], ==, 1);
- g_assert_cmpint(vals[6], ==, 1);
- g_assert_cmpint(vals[7], ==, 0);
-}
-
-GPIOD_TEST_CASE(get_values_active_low, 0, { 8 })
-{
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line *line;
- gint i, ret, vals[8];
-
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- bulk = gpiod_line_bulk_new(8);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- for (i = 0; i < 8; i++) {
- line = gpiod_chip_get_line(chip, i);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulk, line);
- gpiod_test_chip_set_pull(0, i, 0);
- }
-
- ret = gpiod_line_request_bulk_rising_edge_events_flags(bulk,
- GPIOD_TEST_CONSUMER, GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- memset(vals, 0, sizeof(vals));
- ret = gpiod_line_get_value_bulk(bulk, vals);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(vals[0], ==, 1);
- g_assert_cmpint(vals[1], ==, 1);
- g_assert_cmpint(vals[2], ==, 1);
- g_assert_cmpint(vals[3], ==, 1);
- g_assert_cmpint(vals[4], ==, 1);
- g_assert_cmpint(vals[5], ==, 1);
- g_assert_cmpint(vals[6], ==, 1);
- g_assert_cmpint(vals[7], ==, 1);
-
- gpiod_test_chip_set_pull(0, 1, 1);
- gpiod_test_chip_set_pull(0, 3, 1);
- gpiod_test_chip_set_pull(0, 4, 1);
- gpiod_test_chip_set_pull(0, 7, 1);
-
- memset(vals, 0, sizeof(vals));
- ret = gpiod_line_get_value_bulk(bulk, vals);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(vals[0], ==, 1);
- g_assert_cmpint(vals[1], ==, 0);
- g_assert_cmpint(vals[2], ==, 1);
- g_assert_cmpint(vals[3], ==, 0);
- g_assert_cmpint(vals[4], ==, 0);
- g_assert_cmpint(vals[5], ==, 1);
- g_assert_cmpint(vals[6], ==, 1);
- g_assert_cmpint(vals[7], ==, 0);
-}
-
-GPIOD_TEST_CASE(wait_multiple, 0, { 8 })
-{
- g_autoptr(GpiodTestEventThread) ev_thread = NULL;
- g_autoptr(gpiod_line_bulk_struct) ev_bulk = NULL;
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct timespec ts = { 1, 0 };
- struct gpiod_line_event ev;
- struct gpiod_line *line;
- gint ret, i;
-
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- bulk = gpiod_line_bulk_new(8);
- ev_bulk = gpiod_line_bulk_new(8);
- g_assert_nonnull(bulk);
- g_assert_nonnull(ev_bulk);
- gpiod_test_return_if_failed();
-
- for (i = 1; i < 8; i++) {
- line = gpiod_chip_get_line(chip, i);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulk, line);
- }
-
- ret = gpiod_line_request_bulk_rising_edge_events(bulk,
- GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- ev_thread = gpiod_test_start_event_thread(0, 4, 100);
-
- ret = gpiod_line_event_wait_bulk(bulk, &ts, ev_bulk);
- g_assert_cmpint(ret, ==, 1);
-
- g_assert_cmpuint(gpiod_line_bulk_num_lines(ev_bulk), ==, 1);
- line = gpiod_line_bulk_get_line(ev_bulk, 0);
- g_assert_cmpuint(gpiod_line_offset(line), ==, 4);
-
- ret = gpiod_line_event_read(line, &ev);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(ev.event_type, ==, GPIOD_LINE_EVENT_RISING_EDGE);
- g_assert_cmpint(ev.offset, ==, 4);
-}
-
-GPIOD_TEST_CASE(get_fd_when_values_requested, 0, { 8 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line *line;
- gint ret, fd;
-
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- line = gpiod_chip_get_line(chip, 3);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- fd = gpiod_line_event_get_fd(line);
- g_assert_cmpint(fd, ==, -1);
- g_assert_cmpint(errno, ==, EPERM);
-}
-
-GPIOD_TEST_CASE(request_bulk_fail, 0, { 8 })
-{
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line *line;
- gint ret, i;
-
- 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_input(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- bulk = gpiod_line_bulk_new(8);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- for (i = 0; i < 8; i++) {
- line = gpiod_chip_get_line(chip, i);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
- gpiod_line_bulk_add_line(bulk, line);
- }
-
- ret = gpiod_line_request_bulk_both_edges_events(bulk,
- GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, -1);
- g_assert_cmpint(errno, ==, EBUSY);
-}
-
-GPIOD_TEST_CASE(invalid_fd, 0, { 8 })
-{
- g_autoptr(gpiod_line_bulk_struct) ev_bulk = NULL;
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct timespec ts = { 1, 0 };
- struct gpiod_line *line;
- gint ret, fd;
-
- 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(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- fd = gpiod_line_event_get_fd(line);
- close(fd);
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, -1);
- g_assert_cmpint(errno, ==, EINVAL);
-
- bulk = gpiod_line_bulk_new(1);
- ev_bulk = gpiod_line_bulk_new(1);
- g_assert_nonnull(bulk);
- g_assert_nonnull(ev_bulk);
-
- /*
- * The single line variant calls gpiod_line_event_wait_bulk() with the
- * event_bulk argument set to NULL, so test this use case explicitly
- * as well.
- */
- gpiod_line_bulk_add_line(bulk, line);
- ret = gpiod_line_event_wait_bulk(bulk, &ts, ev_bulk);
- g_assert_cmpint(ret, ==, -1);
- g_assert_cmpint(errno, ==, EINVAL);
-}
-
-GPIOD_TEST_CASE(read_events_individually, 0, { 8 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct timespec ts = { 1, 0 };
- struct gpiod_line_event ev;
- struct gpiod_line *line;
- gint ret;
- guint i;
-
- 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);
- gpiod_test_return_if_failed();
-
- /* generate multiple events */
- for (i = 0; i < 3; i++) {
- gpiod_test_chip_set_pull(0, 7, i & 1);
- usleep(10000);
- }
-
- /* read them individually... */
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 1);
- if (!ret)
- return;
-
- 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);
- if (!ret)
- return;
-
- 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);
- if (!ret)
- return;
-
- 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, ==, 0);
-}
-
-GPIOD_TEST_CASE(read_multiple_events, 0, { 8 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line_event events[5];
- struct timespec ts = { 1, 0 };
- struct gpiod_line *line;
- gint ret;
- guint i;
-
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- line = gpiod_chip_get_line(chip, 4);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_request_both_edges_events(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- /* generate multiple events */
- for (i = 0; i < 7; i++) {
- gpiod_test_chip_set_pull(0, 4, !(i & 1));
- /*
- * We sleep for a short period of time here and in other
- * test cases for multiple events to let the kernel service
- * each simulated interrupt. Otherwise we'd risk triggering
- * an interrupt while the previous one is still being
- * handled.
- */
- usleep(10000);
- }
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 1);
- if (!ret)
- return;
-
- /* read a chunk */
- ret = gpiod_line_event_read_multiple(line, events, 3);
- g_assert_cmpint(ret, ==, 3);
-
- g_assert_cmpint(events[0].event_type, ==,
- GPIOD_LINE_EVENT_RISING_EDGE);
- g_assert_cmpint(events[1].event_type, ==,
- GPIOD_LINE_EVENT_FALLING_EDGE);
- g_assert_cmpint(events[2].event_type, ==,
- GPIOD_LINE_EVENT_RISING_EDGE);
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 1);
- if (!ret)
- return;
-
- /*
- * read the remainder
- * - note the attempt to read more than are available
- */
- ret = gpiod_line_event_read_multiple(line, events, 5);
- g_assert_cmpint(ret, ==, 4);
-
- g_assert_cmpint(events[0].event_type, ==,
- GPIOD_LINE_EVENT_FALLING_EDGE);
- g_assert_cmpint(events[1].event_type, ==,
- GPIOD_LINE_EVENT_RISING_EDGE);
- g_assert_cmpint(events[2].event_type, ==,
- GPIOD_LINE_EVENT_FALLING_EDGE);
- g_assert_cmpint(events[3].event_type, ==,
- GPIOD_LINE_EVENT_RISING_EDGE);
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 0);
-}
-
-GPIOD_TEST_CASE(read_multiple_events_fd, 0, { 8 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line_event events[5];
- struct timespec ts = { 1, 0 };
- struct gpiod_line *line;
- gint ret, fd;
- guint i;
-
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- line = gpiod_chip_get_line(chip, 4);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_request_both_edges_events(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- /* generate multiple events */
- for (i = 0; i < 7; i++) {
- gpiod_test_chip_set_pull(0, 4, !(i & 1));
- usleep(10000);
- }
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 1);
- if (!ret)
- return;
-
- fd = gpiod_line_event_get_fd(line);
- g_assert_cmpint(fd, >=, 0);
-
- /* read a chunk */
- ret = gpiod_line_event_read_fd_multiple(fd, events, 3);
- g_assert_cmpint(ret, ==, 3);
-
- g_assert_cmpint(events[0].event_type, ==,
- GPIOD_LINE_EVENT_RISING_EDGE);
- g_assert_cmpint(events[1].event_type, ==,
- GPIOD_LINE_EVENT_FALLING_EDGE);
- g_assert_cmpint(events[2].event_type, ==,
- GPIOD_LINE_EVENT_RISING_EDGE);
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 1);
- if (!ret)
- return;
-
- /*
- * read the remainder
- * - note the attempt to read more than are available
- */
- ret = gpiod_line_event_read_fd_multiple(fd, events, 5);
- g_assert_cmpint(ret, ==, 4);
-
- g_assert_cmpint(events[0].event_type, ==,
- GPIOD_LINE_EVENT_FALLING_EDGE);
- g_assert_cmpint(events[1].event_type, ==,
- GPIOD_LINE_EVENT_RISING_EDGE);
- g_assert_cmpint(events[2].event_type, ==,
- GPIOD_LINE_EVENT_FALLING_EDGE);
- g_assert_cmpint(events[3].event_type, ==,
- GPIOD_LINE_EVENT_RISING_EDGE);
-
- ret = gpiod_line_event_wait(line, &ts);
- g_assert_cmpint(ret, ==, 0);
-}
new file mode 100644
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
+
+#include <glib.h>
+#include <gpiod.h>
+#include <poll.h>
+
+#include "gpiod-test.h"
+#include "gpiod-test-helpers.h"
+#include "gpiod-test-sim.h"
+
+#define GPIOD_TEST_GROUP "info-event"
+
+GPIOD_TEST_CASE(watching_info_events_returns_line_info)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ info = gpiod_chip_watch_line_info(chip, 3);
+ g_assert_nonnull(info);
+ g_assert_cmpuint(gpiod_line_info_get_offset(info), ==, 3);
+}
+
+GPIOD_TEST_CASE(try_offset_out_of_range)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ info = gpiod_chip_watch_line_info(chip, 10);
+ g_assert_null(info);
+ gpiod_test_expect_errno(EINVAL);
+}
+
+GPIOD_TEST_CASE(event_timeout)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ info = gpiod_chip_watch_line_info(chip, 6);
+ g_assert_nonnull(info);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_chip_info_event_wait(chip, 100000000);
+ g_assert_cmpint(ret, ==, 0);
+}
+
+struct request_ctx {
+ struct gpiod_chip *chip;
+ struct gpiod_request_config *req_cfg;
+ struct gpiod_line_config *line_cfg;
+};
+
+static gpointer request_release_line(gpointer data)
+{
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ struct request_ctx *ctx = data;
+ gint ret;
+
+ g_usleep(50);
+
+ request = gpiod_chip_request_lines(ctx->chip,
+ ctx->req_cfg, ctx->line_cfg);
+ g_assert_nonnull(request);
+ if (g_test_failed())
+ return NULL;
+
+ g_usleep(50);
+
+ gpiod_line_config_set_direction_default(ctx->line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+
+ ret = gpiod_line_request_reconfigure_lines(request, ctx->line_cfg);
+ g_assert_cmpint(ret, ==, 0);
+ if (g_test_failed())
+ return NULL;
+
+ g_usleep(50);
+
+ gpiod_line_request_release(request);
+ request = NULL;
+
+ return NULL;
+}
+
+GPIOD_TEST_CASE(request_reconfigure_release_events)
+{
+ static const guint offset = 3;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+ g_autoptr(struct_gpiod_info_event) request_event = NULL;
+ g_autoptr(struct_gpiod_info_event) reconfigure_event = NULL;
+ g_autoptr(struct_gpiod_info_event) release_event = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(GThread) thread = NULL;
+ struct gpiod_line_info *request_info, *reconfigure_info, *release_info;
+ guint64 request_ts, reconfigure_ts, release_ts;
+ struct request_ctx ctx;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+
+ info = gpiod_chip_watch_line_info(chip, 3);
+ g_assert_nonnull(info);
+ gpiod_test_return_if_failed();
+
+ g_assert_false(gpiod_line_info_is_used(info));
+
+ ctx.chip = chip;
+ ctx.req_cfg = req_cfg;
+ ctx.line_cfg = line_cfg;
+
+ thread = g_thread_new("request-release", request_release_line, &ctx);
+ g_thread_ref(thread);
+
+ ret = gpiod_chip_info_event_wait(chip, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ request_event = gpiod_chip_info_event_read(chip);
+ g_assert_nonnull(request_event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_info_event_get_event_type(request_event), ==,
+ GPIOD_INFO_EVENT_LINE_REQUESTED);
+
+ request_info = gpiod_info_event_get_line_info(request_event);
+
+ g_assert_cmpuint(gpiod_line_info_get_offset(request_info), ==, 3);
+ g_assert_true(gpiod_line_info_is_used(request_info));
+ g_assert_cmpint(gpiod_line_info_get_direction(request_info), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+
+ ret = gpiod_chip_info_event_wait(chip, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ reconfigure_event = gpiod_chip_info_event_read(chip);
+ g_assert_nonnull(reconfigure_event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_info_event_get_event_type(reconfigure_event), ==,
+ GPIOD_INFO_EVENT_LINE_CONFIG_CHANGED);
+
+ reconfigure_info = gpiod_info_event_get_line_info(reconfigure_event);
+
+ g_assert_cmpuint(gpiod_line_info_get_offset(reconfigure_info), ==, 3);
+ g_assert_true(gpiod_line_info_is_used(reconfigure_info));
+ g_assert_cmpint(gpiod_line_info_get_direction(reconfigure_info), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+
+ ret = gpiod_chip_info_event_wait(chip, 1000000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ release_event = gpiod_chip_info_event_read(chip);
+ g_assert_nonnull(release_event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_info_event_get_event_type(release_event), ==,
+ GPIOD_INFO_EVENT_LINE_RELEASED);
+
+ release_info = gpiod_info_event_get_line_info(release_event);
+
+ g_assert_cmpuint(gpiod_line_info_get_offset(release_info), ==, 3);
+ g_assert_false(gpiod_line_info_is_used(release_info));
+
+ g_thread_join(thread);
+
+ request_ts = gpiod_info_event_get_timestamp(request_event);
+ reconfigure_ts = gpiod_info_event_get_timestamp(reconfigure_event);
+ release_ts = gpiod_info_event_get_timestamp(release_event);
+
+ g_assert_cmpuint(request_ts, <, reconfigure_ts);
+ g_assert_cmpuint(reconfigure_ts, <, release_ts);
+}
+
+GPIOD_TEST_CASE(chip_fd_can_be_polled)
+{
+ static const guint offset = 3;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+ g_autoptr(struct_gpiod_info_event) event = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(GThread) thread = NULL;
+ struct gpiod_line_info *evinfo;
+ struct request_ctx ctx;
+ struct timespec ts;
+ struct pollfd pfd;
+ gint ret, fd;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+
+ info = gpiod_chip_watch_line_info(chip, 3);
+ g_assert_nonnull(info);
+ gpiod_test_return_if_failed();
+
+ g_assert_false(gpiod_line_info_is_used(info));
+
+ ctx.chip = chip;
+ ctx.req_cfg = req_cfg;
+ ctx.line_cfg = line_cfg;
+
+ thread = g_thread_new("request-release", request_release_line, &ctx);
+ g_thread_ref(thread);
+
+ fd = gpiod_chip_get_fd(chip);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = fd;
+ pfd.events = POLLIN | POLLPRI;
+
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+
+ ret = ppoll(&pfd, 1, &ts, NULL);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ event = gpiod_chip_info_event_read(chip);
+ g_assert_nonnull(event);
+ gpiod_test_join_thread_and_return_if_failed(thread);
+
+ g_assert_cmpint(gpiod_info_event_get_event_type(event), ==,
+ GPIOD_INFO_EVENT_LINE_REQUESTED);
+
+ evinfo = gpiod_info_event_get_line_info(event);
+
+ g_assert_cmpuint(gpiod_line_info_get_offset(evinfo), ==, 3);
+ g_assert_true(gpiod_line_info_is_used(evinfo));
+
+ g_thread_join(thread);
+}
+
+GPIOD_TEST_CASE(unwatch_and_check_that_no_events_are_generated)
+{
+ static const guint offset = 3;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+ g_autoptr(struct_gpiod_info_event) event = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+
+ info = gpiod_chip_watch_line_info(chip, 3);
+ g_assert_nonnull(info);
+ gpiod_test_return_if_failed();
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ ret = gpiod_chip_info_event_wait(chip, 100000000);
+ g_assert_cmpint(ret, >, 0);
+ gpiod_test_return_if_failed();
+
+ event = gpiod_chip_info_event_read(chip);
+ g_assert_nonnull(event);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_chip_unwatch_line_info(chip, 3);
+ g_assert_cmpint(ret, ==, 0);
+ gpiod_test_return_if_failed();
+
+ gpiod_line_request_release(request);
+ request = NULL;
+
+ ret = gpiod_chip_info_event_wait(chip, 100000000);
+ g_assert_cmpint(ret, ==, 0);
+}
new file mode 100644
@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
+
+#include <errno.h>
+#include <glib.h>
+#include <gpiod.h>
+#include <stdint.h>
+
+#include "gpiod-test.h"
+#include "gpiod-test-helpers.h"
+#include "gpiod-test-sim.h"
+
+#define GPIOD_TEST_GROUP "line-config"
+
+GPIOD_TEST_CASE(default_config)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpint(gpiod_line_config_get_direction_default(config), ==,
+ GPIOD_LINE_DIRECTION_AS_IS);
+ g_assert_cmpint(gpiod_line_config_get_edge_detection_default(config),
+ ==, GPIOD_LINE_EDGE_NONE);
+ g_assert_cmpint(gpiod_line_config_get_bias_default(config), ==,
+ GPIOD_LINE_BIAS_AS_IS);
+ g_assert_cmpint(gpiod_line_config_get_drive_default(config), ==,
+ GPIOD_LINE_DRIVE_PUSH_PULL);
+ g_assert_false(gpiod_line_config_get_active_low_default(config));
+ g_assert_cmpuint(
+ gpiod_line_config_get_debounce_period_us_default(config), ==,
+ 0);
+ g_assert_cmpint(gpiod_line_config_get_event_clock_default(config), ==,
+ GPIOD_LINE_EVENT_CLOCK_MONOTONIC);
+ g_assert_cmpint(gpiod_line_config_get_output_value_default(config), ==,
+ GPIOD_LINE_VALUE_INACTIVE);
+ g_assert_cmpuint(gpiod_line_config_get_num_overrides(config),
+ ==, 0);
+}
+
+GPIOD_TEST_CASE(defaults_are_used_for_non_overridden_offsets)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpint(gpiod_line_config_get_direction_offset(config, 4), ==,
+ GPIOD_LINE_DIRECTION_AS_IS);
+ g_assert_cmpint(gpiod_line_config_get_edge_detection_offset(config, 4),
+ ==, GPIOD_LINE_EDGE_NONE);
+ g_assert_cmpint(gpiod_line_config_get_bias_offset(config, 4), ==,
+ GPIOD_LINE_BIAS_AS_IS);
+ g_assert_cmpint(gpiod_line_config_get_drive_offset(config, 4), ==,
+ GPIOD_LINE_DRIVE_PUSH_PULL);
+ g_assert_false(gpiod_line_config_get_active_low_offset(config, 4));
+ g_assert_cmpuint(
+ gpiod_line_config_get_debounce_period_us_offset(config, 4), ==,
+ 0);
+ g_assert_cmpint(gpiod_line_config_get_event_clock_offset(config, 4),
+ ==, GPIOD_LINE_EVENT_CLOCK_MONOTONIC);
+ g_assert_cmpint(gpiod_line_config_get_output_value_offset(config, 4),
+ ==, GPIOD_LINE_VALUE_INACTIVE);
+ g_assert_cmpuint(gpiod_line_config_get_num_overrides(config),
+ ==, 0);
+}
+
+GPIOD_TEST_CASE(set_and_clear_direction_override)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpint(gpiod_line_config_get_direction_default(config), ==,
+ GPIOD_LINE_DIRECTION_AS_IS);
+ gpiod_line_config_set_direction_override(config,
+ GPIOD_LINE_DIRECTION_OUTPUT,
+ 3);
+
+ g_assert_cmpint(gpiod_line_config_get_direction_default(config), ==,
+ GPIOD_LINE_DIRECTION_AS_IS);
+ g_assert_cmpint(gpiod_line_config_get_direction_offset(config, 3), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_true(gpiod_line_config_direction_is_overridden(config, 3));
+ gpiod_line_config_clear_direction_override(config, 3);
+ g_assert_cmpint(gpiod_line_config_get_direction_offset(config, 3), ==,
+ GPIOD_LINE_DIRECTION_AS_IS);
+ g_assert_false(gpiod_line_config_direction_is_overridden(config, 3));
+}
+
+GPIOD_TEST_CASE(invalid_direction)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ gpiod_line_config_set_direction_default(config, INT32_MAX);
+ g_assert_cmpint(gpiod_line_config_get_direction_default(config),
+ ==, GPIOD_LINE_DIRECTION_AS_IS);
+}
+
+GPIOD_TEST_CASE(set_and_clear_edge_detection_override)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpint(gpiod_line_config_get_edge_detection_default(config),
+ ==, GPIOD_LINE_EDGE_NONE);
+ gpiod_line_config_set_edge_detection_override(config,
+ GPIOD_LINE_EDGE_FALLING, 3);
+
+ g_assert_cmpint(gpiod_line_config_get_edge_detection_default(config),
+ ==, GPIOD_LINE_EDGE_NONE);
+ g_assert_cmpint(gpiod_line_config_get_edge_detection_offset(config, 3),
+ ==, GPIOD_LINE_EDGE_FALLING);
+ g_assert_true(gpiod_line_config_edge_detection_is_overridden(config,
+ 3));
+ gpiod_line_config_clear_edge_detection_override(config, 3);
+ g_assert_cmpint(gpiod_line_config_get_edge_detection_offset(config, 3),
+ ==, GPIOD_LINE_EDGE_NONE);
+ g_assert_false(gpiod_line_config_edge_detection_is_overridden(config,
+ 3));
+}
+
+GPIOD_TEST_CASE(invalid_edge)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ gpiod_line_config_set_edge_detection_default(config, INT32_MAX);
+ g_assert_cmpint(gpiod_line_config_get_edge_detection_default(config),
+ ==, GPIOD_LINE_EDGE_NONE);
+}
+
+GPIOD_TEST_CASE(set_and_clear_bias_override)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpint(gpiod_line_config_get_bias_default(config),
+ ==, GPIOD_LINE_BIAS_AS_IS);
+ gpiod_line_config_set_bias_override(config, GPIOD_LINE_BIAS_PULL_UP, 0);
+
+ g_assert_cmpint(gpiod_line_config_get_bias_default(config),
+ ==, GPIOD_LINE_BIAS_AS_IS);
+ g_assert_cmpint(gpiod_line_config_get_bias_offset(config, 0),
+ ==, GPIOD_LINE_BIAS_PULL_UP);
+ g_assert_true(gpiod_line_config_bias_is_overridden(config, 0));
+ gpiod_line_config_clear_bias_override(config, 0);
+ g_assert_cmpint(gpiod_line_config_get_bias_offset(config, 0),
+ ==, GPIOD_LINE_BIAS_AS_IS);
+ g_assert_false(gpiod_line_config_bias_is_overridden(config, 0));
+}
+
+GPIOD_TEST_CASE(invalid_bias)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ gpiod_line_config_set_bias_default(config, INT32_MAX);
+ g_assert_cmpint(gpiod_line_config_get_bias_default(config),
+ ==, GPIOD_LINE_BIAS_AS_IS);
+}
+
+GPIOD_TEST_CASE(set_and_clear_drive_override)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpint(gpiod_line_config_get_drive_default(config),
+ ==, GPIOD_LINE_DRIVE_PUSH_PULL);
+ gpiod_line_config_set_drive_override(config,
+ GPIOD_LINE_DRIVE_OPEN_DRAIN, 3);
+
+ g_assert_cmpint(gpiod_line_config_get_drive_default(config),
+ ==, GPIOD_LINE_DRIVE_PUSH_PULL);
+ g_assert_cmpint(gpiod_line_config_get_drive_offset(config, 3),
+ ==, GPIOD_LINE_DRIVE_OPEN_DRAIN);
+ g_assert_true(gpiod_line_config_drive_is_overridden(config, 3));
+ gpiod_line_config_clear_drive_override(config, 3);
+ g_assert_cmpint(gpiod_line_config_get_drive_offset(config, 3),
+ ==, GPIOD_LINE_DRIVE_PUSH_PULL);
+ g_assert_false(gpiod_line_config_drive_is_overridden(config, 3));
+}
+
+GPIOD_TEST_CASE(invalid_drive)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ gpiod_line_config_set_drive_default(config, INT32_MAX);
+ g_assert_cmpint(gpiod_line_config_get_drive_default(config),
+ ==, GPIOD_LINE_BIAS_AS_IS);
+}
+
+GPIOD_TEST_CASE(set_and_clear_active_low_override)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_false(gpiod_line_config_get_active_low_default(config));
+ gpiod_line_config_set_active_low_override(config, true, 3);
+
+ g_assert_false(gpiod_line_config_get_active_low_default(config));
+ g_assert_true(gpiod_line_config_get_active_low_offset(config, 3));
+ g_assert_true(gpiod_line_config_active_low_is_overridden(config, 3));
+ gpiod_line_config_clear_active_low_override(config, 3);
+ g_assert_false(gpiod_line_config_get_active_low_offset(config, 3));
+ g_assert_false(gpiod_line_config_active_low_is_overridden(config, 3));
+}
+
+GPIOD_TEST_CASE(set_and_clear_debounce_period_override)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpuint(
+ gpiod_line_config_get_debounce_period_us_default(config),
+ ==, 0);
+ gpiod_line_config_set_debounce_period_us_override(config, 5000, 3);
+
+ g_assert_cmpuint(
+ gpiod_line_config_get_debounce_period_us_default(config),
+ ==, 0);
+ g_assert_cmpuint(
+ gpiod_line_config_get_debounce_period_us_offset(config, 3),
+ ==, 5000);
+ g_assert_true(
+ gpiod_line_config_debounce_period_us_is_overridden(config, 3));
+ gpiod_line_config_clear_debounce_period_us_override(config, 3);
+ g_assert_cmpuint(
+ gpiod_line_config_get_debounce_period_us_offset(config, 3),
+ ==, 0);
+ g_assert_false(
+ gpiod_line_config_debounce_period_us_is_overridden(config, 3));
+}
+
+GPIOD_TEST_CASE(set_and_clear_event_clock_override)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpint(gpiod_line_config_get_event_clock_default(config),
+ ==, GPIOD_LINE_EVENT_CLOCK_MONOTONIC);
+ gpiod_line_config_set_event_clock_override(config,
+ GPIOD_LINE_EVENT_CLOCK_REALTIME, 3);
+
+ g_assert_cmpint(gpiod_line_config_get_event_clock_default(config),
+ ==, GPIOD_LINE_EVENT_CLOCK_MONOTONIC);
+ g_assert_cmpint(gpiod_line_config_get_event_clock_offset(config, 3),
+ ==, GPIOD_LINE_EVENT_CLOCK_REALTIME);
+ g_assert_true(gpiod_line_config_event_clock_is_overridden(config, 3));
+ gpiod_line_config_clear_event_clock_override(config, 3);
+ g_assert_cmpint(gpiod_line_config_get_event_clock_offset(config, 3),
+ ==, GPIOD_LINE_EVENT_CLOCK_MONOTONIC);
+ g_assert_false(gpiod_line_config_event_clock_is_overridden(config, 3));
+}
+
+GPIOD_TEST_CASE(invalid_event_clock)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ gpiod_line_config_set_event_clock_default(config, INT32_MAX);
+ g_assert_cmpint(gpiod_line_config_get_event_clock_default(config),
+ ==, GPIOD_LINE_EVENT_CLOCK_MONOTONIC);
+}
+
+GPIOD_TEST_CASE(set_and_clear_output_value_override)
+{
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpint(gpiod_line_config_get_output_value_default(config),
+ ==, GPIOD_LINE_VALUE_INACTIVE);
+ gpiod_line_config_set_output_value_override(config, 3,
+ GPIOD_LINE_VALUE_ACTIVE);
+
+ g_assert_cmpint(gpiod_line_config_get_output_value_default(config),
+ ==, GPIOD_LINE_VALUE_INACTIVE);
+ g_assert_cmpint(gpiod_line_config_get_output_value_offset(config, 3),
+ ==, GPIOD_LINE_VALUE_ACTIVE);
+ g_assert_true(gpiod_line_config_output_value_is_overridden(config, 3));
+ gpiod_line_config_clear_output_value_override(config, 3);
+ g_assert_cmpint(gpiod_line_config_get_output_value_offset(config, 3),
+ ==, 0);
+ g_assert_false(gpiod_line_config_output_value_is_overridden(config, 3));
+}
+
+GPIOD_TEST_CASE(set_multiple_output_values)
+{
+ static const guint offsets[] = { 3, 4, 5, 6 };
+ static const gint values[] = { GPIOD_LINE_VALUE_ACTIVE,
+ GPIOD_LINE_VALUE_INACTIVE,
+ GPIOD_LINE_VALUE_ACTIVE,
+ GPIOD_LINE_VALUE_INACTIVE };
+
+ g_autoptr(struct_gpiod_line_config) config = NULL;
+ guint overridden_offsets[4], i;
+ gint overriden_props[4];
+
+ config = gpiod_test_create_line_config_or_fail();
+
+ gpiod_line_config_set_output_values(config, 4, offsets, values);
+
+ g_assert_cmpint(gpiod_line_config_get_output_value_default(config),
+ ==, 0);
+
+ for (i = 0; i < 4; i++)
+ g_assert_cmpint(
+ gpiod_line_config_get_output_value_offset(config,
+ offsets[i]),
+ ==, values[i]);
+
+ g_assert_cmpuint(gpiod_line_config_get_num_overrides(config),
+ ==, 4);
+ gpiod_line_config_get_overrides(config,
+ overridden_offsets, overriden_props);
+
+ for (i = 0; i < 4; i++) {
+ g_assert_cmpuint(overridden_offsets[i], ==, offsets[i]);
+ g_assert_cmpint(overriden_props[i], ==,
+ GPIOD_LINE_CONFIG_PROP_OUTPUT_VALUE);
+ }
+}
+
+GPIOD_TEST_CASE(config_too_complex)
+{
+ static guint offsets[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 16, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ req_cfg = gpiod_test_create_request_config_or_fail();
+
+ /*
+ * We need to make the line_config structure exceed the kernel's
+ * maximum of 10 attributes.
+ */
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT, 0);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT, 1);
+ gpiod_line_config_set_edge_detection_override(line_cfg,
+ GPIOD_LINE_EDGE_BOTH, 2);
+ gpiod_line_config_set_debounce_period_us_override(line_cfg, 1000, 2);
+ gpiod_line_config_set_active_low_override(line_cfg, true, 3);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT, 4);
+ gpiod_line_config_set_drive_override(line_cfg,
+ GPIOD_LINE_DRIVE_OPEN_DRAIN, 4);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT, 8);
+ gpiod_line_config_set_drive_override(line_cfg,
+ GPIOD_LINE_DRIVE_OPEN_SOURCE, 8);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT, 5);
+ gpiod_line_config_set_bias_override(line_cfg,
+ GPIOD_LINE_BIAS_PULL_DOWN, 5);
+ gpiod_line_config_set_event_clock_override(line_cfg,
+ GPIOD_LINE_EVENT_CLOCK_REALTIME, 6);
+ gpiod_line_config_set_output_value_override(line_cfg, 7,
+ GPIOD_LINE_VALUE_ACTIVE);
+
+ gpiod_request_config_set_offsets(req_cfg, 12, offsets);
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+ g_assert_null(request);
+ gpiod_test_expect_errno(E2BIG);
+}
+
+/*
+ * This triggers the E2BIG error by exhausting the number of overrides in
+ * the line_config structure instead of making the kernel representation too
+ * complex.
+ */
+GPIOD_TEST_CASE(define_too_many_overrides)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 128, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ guint offsets[65], i;
+
+ for (i = 0; i < 65; i++)
+ offsets[i] = i;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ req_cfg = gpiod_test_create_request_config_or_fail();
+
+ for (i = 0; i < 65; i++)
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT, offsets[i]);
+
+ gpiod_request_config_set_offsets(req_cfg, 64, offsets);
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+ g_assert_null(request);
+ gpiod_test_expect_errno(E2BIG);
+}
+
+GPIOD_TEST_CASE(ignore_overrides_for_offsets_not_in_request_config)
+{
+ static guint offsets[] = { 2, 3, 4, 6, 7 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info3 = NULL;
+ g_autoptr(struct_gpiod_line_info) info4 = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ line_cfg = gpiod_test_create_line_config_or_fail();
+ req_cfg = gpiod_test_create_request_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 5, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT, 4);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT, 5);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+ info3 = gpiod_test_get_line_info_or_fail(chip, 3);
+ info4 = gpiod_test_get_line_info_or_fail(chip, 4);
+
+ g_assert_cmpint(gpiod_line_info_get_direction(info3), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+ g_assert_cmpint(gpiod_line_info_get_direction(info4), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT, 0);
+
+ gpiod_test_reconfigure_lines_or_fail(request, line_cfg);
+ /* Nothing to check, value successfully ignored. */
+}
new file mode 100644
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
+
+#include <errno.h>
+#include <glib.h>
+#include <gpiod.h>
+
+#include "gpiod-test.h"
+#include "gpiod-test-helpers.h"
+#include "gpiod-test-sim.h"
+
+#define GPIOD_TEST_GROUP "line-info"
+
+GPIOD_TEST_CASE(get_line_info_good)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ info = gpiod_chip_get_line_info(chip, 3);
+ g_assert_nonnull(info);
+ g_assert_cmpuint(gpiod_line_info_get_offset(info), ==, 3);
+}
+
+GPIOD_TEST_CASE(get_line_info_offset_out_of_range)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ info = gpiod_chip_get_line_info(chip, 8);
+ g_assert_null(info);
+ gpiod_test_expect_errno(EINVAL);
+}
+
+GPIOD_TEST_CASE(line_info_basic_properties)
+{
+ static const struct gpiod_test_line_name names[] = {
+ { .offset = 1, .name = "foo", },
+ { .offset = 2, .name = "bar", },
+ { .offset = 4, .name = "baz", },
+ { .offset = 5, .name = "xyz", },
+ { }
+ };
+
+ static const struct gpiod_test_hog hogs[] = {
+ {
+ .offset = 3,
+ .name = "hog3",
+ .direction = G_GPIOSIM_HOG_DIR_OUTPUT_HIGH,
+ },
+ {
+ .offset = 4,
+ .name = "hog4",
+ .direction = G_GPIOSIM_HOG_DIR_OUTPUT_LOW,
+ },
+ { }
+ };
+
+ g_autoptr(GPIOSimChip) sim = NULL;
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info4 = NULL;
+ g_autoptr(struct_gpiod_line_info) info6 = NULL;
+
+ sim = g_gpiosim_chip_new(
+ "num-lines", 8,
+ "line-names", gpiod_test_package_line_names(names),
+ "hogs", gpiod_test_package_hogs(hogs),
+ NULL);
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ info4 = gpiod_test_get_line_info_or_fail(chip, 4);
+ info6 = gpiod_test_get_line_info_or_fail(chip, 6);
+
+ g_assert_cmpuint(gpiod_line_info_get_offset(info4), ==, 4);
+ g_assert_cmpstr(gpiod_line_info_get_name(info4), ==, "baz");
+ g_assert_cmpstr(gpiod_line_info_get_consumer(info4), ==, "hog4");
+ g_assert_true(gpiod_line_info_is_used(info4));
+ g_assert_cmpint(gpiod_line_info_get_direction(info4), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_info_get_edge_detection(info4), ==,
+ GPIOD_LINE_EDGE_NONE);
+ g_assert_false(gpiod_line_info_is_active_low(info4));
+ g_assert_cmpint(gpiod_line_info_get_bias(info4), ==,
+ GPIOD_LINE_BIAS_UNKNOWN);
+ g_assert_cmpint(gpiod_line_info_get_drive(info4), ==,
+ GPIOD_LINE_DRIVE_PUSH_PULL);
+ g_assert_cmpint(gpiod_line_info_get_event_clock(info4), ==,
+ GPIOD_LINE_EVENT_CLOCK_MONOTONIC);
+ g_assert_false(gpiod_line_info_is_debounced(info4));
+ g_assert_cmpuint(gpiod_line_info_get_debounce_period_us(info4), ==, 0);
+}
+
+GPIOD_TEST_CASE(copy_line_info)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+ g_autoptr(struct_gpiod_line_info) copy = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ info = gpiod_test_get_line_info_or_fail(chip, 3);
+
+ copy = gpiod_line_info_copy(info);
+ g_assert_nonnull(copy);
+ g_assert_true(info != copy);
+ g_assert_cmpuint(gpiod_line_info_get_offset(info), ==,
+ gpiod_line_info_get_offset(copy));
+}
+
+GPIOD_TEST_CASE(active_high)
+{
+ static const guint offset = 5;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_active_low_default(line_cfg, true);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+ info = gpiod_chip_get_line_info(chip, 5);
+
+ g_assert_true(gpiod_line_info_is_active_low(info));
+}
+
+GPIOD_TEST_CASE(edge_detection_settings)
+{
+ static const guint offsets[] = { 0, 1, 2, 3 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info0 = NULL;
+ g_autoptr(struct_gpiod_line_info) info1 = NULL;
+ g_autoptr(struct_gpiod_line_info) info2 = NULL;
+ g_autoptr(struct_gpiod_line_info) info3 = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 4, offsets);
+ gpiod_line_config_set_edge_detection_override(line_cfg,
+ GPIOD_LINE_EDGE_RISING, 1);
+ gpiod_line_config_set_edge_detection_override(line_cfg,
+ GPIOD_LINE_EDGE_FALLING, 2);
+ gpiod_line_config_set_edge_detection_override(line_cfg,
+ GPIOD_LINE_EDGE_BOTH, 3);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+ info0 = gpiod_chip_get_line_info(chip, 0);
+ info1 = gpiod_chip_get_line_info(chip, 1);
+ info2 = gpiod_chip_get_line_info(chip, 2);
+ info3 = gpiod_chip_get_line_info(chip, 3);
+
+ g_assert_cmpint(gpiod_line_info_get_edge_detection(info0), ==,
+ GPIOD_LINE_EDGE_NONE);
+ g_assert_cmpint(gpiod_line_info_get_edge_detection(info1), ==,
+ GPIOD_LINE_EDGE_RISING);
+ g_assert_cmpint(gpiod_line_info_get_edge_detection(info2), ==,
+ GPIOD_LINE_EDGE_FALLING);
+ g_assert_cmpint(gpiod_line_info_get_edge_detection(info3), ==,
+ GPIOD_LINE_EDGE_BOTH);
+}
+
+GPIOD_TEST_CASE(bias_settings)
+{
+ static const guint offsets[] = { 0, 1, 2, 3 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info0 = NULL;
+ g_autoptr(struct_gpiod_line_info) info1 = NULL;
+ g_autoptr(struct_gpiod_line_info) info2 = NULL;
+ g_autoptr(struct_gpiod_line_info) info3 = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 4, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_config_set_bias_override(line_cfg,
+ GPIOD_LINE_BIAS_DISABLED, 1);
+ gpiod_line_config_set_bias_override(line_cfg,
+ GPIOD_LINE_BIAS_PULL_DOWN, 2);
+ gpiod_line_config_set_bias_override(line_cfg,
+ GPIOD_LINE_BIAS_PULL_UP, 3);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+ info0 = gpiod_chip_get_line_info(chip, 0);
+ info1 = gpiod_chip_get_line_info(chip, 1);
+ info2 = gpiod_chip_get_line_info(chip, 2);
+ info3 = gpiod_chip_get_line_info(chip, 3);
+
+ g_assert_cmpint(gpiod_line_info_get_bias(info0), ==,
+ GPIOD_LINE_BIAS_UNKNOWN);
+ g_assert_cmpint(gpiod_line_info_get_bias(info1), ==,
+ GPIOD_LINE_BIAS_DISABLED);
+ g_assert_cmpint(gpiod_line_info_get_bias(info2), ==,
+ GPIOD_LINE_BIAS_PULL_DOWN);
+ g_assert_cmpint(gpiod_line_info_get_bias(info3), ==,
+ GPIOD_LINE_BIAS_PULL_UP);
+}
+
+GPIOD_TEST_CASE(drive_settings)
+{
+ static const guint offsets[] = { 0, 1, 2 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info0 = NULL;
+ g_autoptr(struct_gpiod_line_info) info1 = NULL;
+ g_autoptr(struct_gpiod_line_info) info2 = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 3, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_config_set_drive_override(line_cfg,
+ GPIOD_LINE_DRIVE_OPEN_DRAIN, 1);
+ gpiod_line_config_set_drive_override(line_cfg,
+ GPIOD_LINE_DRIVE_OPEN_SOURCE, 2);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+ info0 = gpiod_chip_get_line_info(chip, 0);
+ info1 = gpiod_chip_get_line_info(chip, 1);
+ info2 = gpiod_chip_get_line_info(chip, 2);
+
+ g_assert_cmpint(gpiod_line_info_get_drive(info0), ==,
+ GPIOD_LINE_DRIVE_PUSH_PULL);
+ g_assert_cmpint(gpiod_line_info_get_drive(info1), ==,
+ GPIOD_LINE_DRIVE_OPEN_DRAIN);
+ g_assert_cmpint(gpiod_line_info_get_drive(info2), ==,
+ GPIOD_LINE_DRIVE_OPEN_SOURCE);
+}
+
+GPIOD_TEST_CASE(debounce_period)
+{
+ static const guint offset = 5;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_edge_detection_default(line_cfg,
+ GPIOD_LINE_EDGE_BOTH);
+ gpiod_line_config_set_debounce_period_us_default(line_cfg, 1000);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+ info = gpiod_chip_get_line_info(chip, 5);
+
+ g_assert_cmpuint(gpiod_line_info_get_debounce_period_us(info),
+ ==, 1000);
+}
+
+GPIOD_TEST_CASE(event_clock)
+{
+ static const guint offsets[] = { 0, 1 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info0 = NULL;
+ g_autoptr(struct_gpiod_line_info) info1 = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 2, offsets);
+ gpiod_line_config_set_event_clock_override(line_cfg,
+ GPIOD_LINE_EVENT_CLOCK_REALTIME, 1);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+ info0 = gpiod_chip_get_line_info(chip, 0);
+ info1 = gpiod_chip_get_line_info(chip, 1);
+
+ g_assert_cmpint(gpiod_line_info_get_event_clock(info0), ==,
+ GPIOD_LINE_EVENT_CLOCK_MONOTONIC);
+ g_assert_cmpint(gpiod_line_info_get_event_clock(info1), ==,
+ GPIOD_LINE_EVENT_CLOCK_REALTIME);
+}
new file mode 100644
@@ -0,0 +1,526 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
+
+#include <glib.h>
+#include <gpiod.h>
+
+#include "gpiod-test.h"
+#include "gpiod-test-helpers.h"
+#include "gpiod-test-sim.h"
+
+#define GPIOD_TEST_GROUP "line-request"
+
+GPIOD_TEST_CASE(request_fails_with_no_offsets)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 4, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ g_assert_cmpuint(gpiod_request_config_get_num_offsets(req_cfg), ==, 0);
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+ g_assert_null(request);
+ gpiod_test_expect_errno(EINVAL);
+}
+
+GPIOD_TEST_CASE(request_fails_with_duplicate_offsets)
+{
+ static const guint offsets[] = { 0, 2, 2, 3 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 4, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 4, offsets);
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+ g_assert_null(request);
+ gpiod_test_expect_errno(EBUSY);
+}
+
+GPIOD_TEST_CASE(request_fails_with_offset_out_of_bounds)
+{
+ static const guint offsets[] = { 2, 6 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 4, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 2, offsets);
+
+ request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);
+ g_assert_null(request);
+ gpiod_test_expect_errno(EINVAL);
+}
+
+GPIOD_TEST_CASE(set_consumer)
+{
+ static const guint offset = 2;
+ static const gchar *const consumer = "foobar";
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 4, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_request_config_set_consumer(req_cfg, consumer);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ info = gpiod_test_get_line_info_or_fail(chip, offset);
+
+ g_assert_cmpstr(gpiod_line_info_get_consumer(info), ==, consumer);
+}
+
+GPIOD_TEST_CASE(empty_consumer)
+{
+ static const guint offset = 2;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 4, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ info = gpiod_test_get_line_info_or_fail(chip, offset);
+
+ g_assert_cmpstr(gpiod_line_info_get_consumer(info), ==, "?");
+}
+
+GPIOD_TEST_CASE(default_output_value)
+{
+ /*
+ * Have a hole in offsets on purpose - make sure it's not set by
+ * accident.
+ */
+ static const guint offsets[] = { 0, 1, 3, 4 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ guint i;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 4, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_config_set_output_value_default(line_cfg,
+ GPIOD_LINE_VALUE_ACTIVE);
+
+ g_gpiosim_chip_set_pull(sim, 2, G_GPIOSIM_PULL_DOWN);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ for (i = 0; i < 4; i++)
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, offsets[i]),
+ ==, GPIOD_LINE_VALUE_ACTIVE);
+
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, 2), ==,
+ GPIOD_LINE_VALUE_INACTIVE);
+}
+
+GPIOD_TEST_CASE(default_and_overridden_output_value)
+{
+ static const guint offsets[] = { 0, 1, 2, 3 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 4, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_config_set_output_value_default(line_cfg, 1);
+ gpiod_line_config_set_output_value_override(line_cfg, 2, 0);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, offsets[0]),
+ ==, GPIOD_LINE_VALUE_ACTIVE);
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, offsets[1]),
+ ==, GPIOD_LINE_VALUE_ACTIVE);
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, offsets[2]),
+ ==, GPIOD_LINE_VALUE_INACTIVE);
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, offsets[3]),
+ ==, GPIOD_LINE_VALUE_ACTIVE);
+}
+
+GPIOD_TEST_CASE(read_all_values)
+{
+ static const guint offsets[] = { 0, 2, 4, 5, 7 };
+ static const gint pulls[] = { 0, 1, 0, 1, 1 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ gint ret, values[5];
+ guint i;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 5, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ for (i = 0; i < 5; i++)
+ g_gpiosim_chip_set_pull(sim, offsets[i],
+ pulls[i] ? G_GPIOSIM_PULL_UP : G_GPIOSIM_PULL_DOWN);
+
+ ret = gpiod_line_request_get_values(request, values);
+ g_assert_cmpint(ret, ==, 0);
+ gpiod_test_return_if_failed();
+
+ for (i = 0; i < 5; i++)
+ g_assert_cmpint(values[i], ==, pulls[i]);
+}
+
+GPIOD_TEST_CASE(request_multiple_values_but_read_one)
+{
+ static const guint offsets[] = { 0, 2, 4, 5, 7 };
+ static const gint pulls[] = { 0, 1, 0, 1, 1 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ gint ret;
+ guint i;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 5, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ for (i = 0; i < 5; i++)
+ g_gpiosim_chip_set_pull(sim, offsets[i],
+ pulls[i] ? G_GPIOSIM_PULL_UP : G_GPIOSIM_PULL_DOWN);
+
+ ret = gpiod_line_request_get_value(request, 5);
+ g_assert_cmpint(ret, ==, 1);
+}
+
+GPIOD_TEST_CASE(set_all_values)
+{
+ static const guint offsets[] = { 0, 2, 4, 5, 6 };
+ static const gint values[] = { GPIOD_LINE_VALUE_ACTIVE,
+ GPIOD_LINE_VALUE_INACTIVE,
+ GPIOD_LINE_VALUE_ACTIVE,
+ GPIOD_LINE_VALUE_ACTIVE,
+ GPIOD_LINE_VALUE_ACTIVE };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ gint ret;
+ guint i;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 5, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ ret = gpiod_line_request_set_values(request, values);
+ g_assert_cmpint(ret, ==, 0);
+ gpiod_test_return_if_failed();
+
+ for (i = 0; i < 5; i++)
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, offsets[i]),
+ ==, values[i]);
+}
+
+GPIOD_TEST_CASE(request_survives_parent_chip)
+{
+ static const guint offset = 0;
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 4, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ gint ret;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 1, &offset);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_config_set_output_value_default(line_cfg,
+ GPIOD_LINE_VALUE_ACTIVE);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ g_assert_cmpint(gpiod_line_request_get_value(request, offset), ==,
+ GPIOD_LINE_VALUE_ACTIVE);
+
+ gpiod_chip_close(chip);
+ chip = NULL;
+
+ ret = gpiod_line_request_set_value(request, offset,
+ GPIOD_LINE_VALUE_ACTIVE);
+ g_assert_cmpint(ret, ==, 0);
+ gpiod_test_return_if_failed();
+
+ ret = gpiod_line_request_set_value(request, offset,
+ GPIOD_LINE_VALUE_ACTIVE);
+ g_assert_cmpint(ret, ==, 0);
+ gpiod_test_return_if_failed();
+}
+
+GPIOD_TEST_CASE(request_with_overridden_direction)
+{
+ static const guint offsets[] = { 0, 1, 2, 3 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 4, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ g_autoptr(struct_gpiod_line_info) info0 = NULL;
+ g_autoptr(struct_gpiod_line_info) info1 = NULL;
+ g_autoptr(struct_gpiod_line_info) info2 = NULL;
+ g_autoptr(struct_gpiod_line_info) info3 = NULL;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 4, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT, 3);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+ info0 = gpiod_test_get_line_info_or_fail(chip, 0);
+ info1 = gpiod_test_get_line_info_or_fail(chip, 1);
+ info2 = gpiod_test_get_line_info_or_fail(chip, 2);
+ info3 = gpiod_test_get_line_info_or_fail(chip, 3);
+
+ g_assert_cmpint(gpiod_line_info_get_direction(info0), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_info_get_direction(info1), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_info_get_direction(info2), ==,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ g_assert_cmpint(gpiod_line_info_get_direction(info3), ==,
+ GPIOD_LINE_DIRECTION_INPUT);
+}
+
+GPIOD_TEST_CASE(num_lines)
+{
+ static const guint offsets[] = { 0, 1, 2, 3, 7, 8, 11, 14 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 16, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ guint read_back[8], i;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 8, offsets);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ g_assert_cmpuint(gpiod_line_request_get_num_lines(request), ==, 8);
+ gpiod_test_return_if_failed();
+ gpiod_line_request_get_offsets(request, read_back);
+ for (i = 0; i < 8; i++)
+ g_assert_cmpuint(read_back[i], ==, offsets[i]);
+}
+
+GPIOD_TEST_CASE(active_low_read_value)
+{
+ static const guint offsets[] = { 2, 3 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ gint value;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 2, offsets);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_INPUT, 2);
+ gpiod_line_config_set_direction_override(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT, 3);
+ gpiod_line_config_set_active_low_default(line_cfg, true);
+ gpiod_line_config_set_output_value_default(line_cfg,
+ GPIOD_LINE_VALUE_ACTIVE);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ g_gpiosim_chip_set_pull(sim, 2, G_GPIOSIM_PULL_DOWN);
+ value = gpiod_line_request_get_value(request, 2);
+ g_assert_cmpint(value, ==, GPIOD_LINE_VALUE_ACTIVE);
+
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, 3), ==, 0);
+}
+
+GPIOD_TEST_CASE(reconfigure_lines)
+{
+ static const guint offsets[] = { 0, 1, 2, 3 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 4, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ gint values[4], ret;
+ guint i;
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 4, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+
+ values[0] = 1;
+ values[1] = 0;
+ values[2] = 1;
+ values[3] = 0;
+ gpiod_line_config_set_output_values(line_cfg, 4, offsets, values);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ for (i = 0; i < 4; i++)
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, offsets[i]),
+ ==, values[i]);
+
+ values[0] = 0;
+ values[1] = 1;
+ values[2] = 0;
+ values[3] = 1;
+ gpiod_line_config_set_output_values(line_cfg, 4, offsets, values);
+
+ ret = gpiod_line_request_reconfigure_lines(request, line_cfg);
+ g_assert_cmpint(ret, ==, 0);
+ gpiod_test_return_if_failed();
+
+ for (i = 0; i < 4; i++)
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, offsets[i]),
+ ==, values[i]);
+}
+
+GPIOD_TEST_CASE(request_lines_with_unordered_offsets)
+{
+ static const guint offsets[] = { 5, 1, 7, 2, 0, 6 };
+
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new("num-lines", 8, NULL);
+ g_autoptr(struct_gpiod_chip) chip = NULL;
+ g_autoptr(struct_gpiod_request_config) req_cfg = NULL;
+ g_autoptr(struct_gpiod_line_config) line_cfg = NULL;
+ g_autoptr(struct_gpiod_line_request) request = NULL;
+ guint cfg_offsets[4];
+ gint values[4];
+
+ chip = gpiod_test_open_chip_or_fail(g_gpiosim_chip_get_dev_path(sim));
+ req_cfg = gpiod_test_create_request_config_or_fail();
+ line_cfg = gpiod_test_create_line_config_or_fail();
+
+ gpiod_request_config_set_offsets(req_cfg, 6, offsets);
+ gpiod_line_config_set_direction_default(line_cfg,
+ GPIOD_LINE_DIRECTION_OUTPUT);
+ gpiod_line_config_set_output_value_default(line_cfg, 1);
+
+ values[0] = 0;
+ values[1] = 1;
+ values[2] = 0;
+ values[3] = 0;
+ cfg_offsets[0] = 7;
+ cfg_offsets[1] = 1;
+ cfg_offsets[2] = 6;
+ cfg_offsets[3] = 0;
+ gpiod_line_config_set_output_values(line_cfg, 4, cfg_offsets, values);
+
+ request = gpiod_test_request_lines_or_fail(chip, req_cfg, line_cfg);
+
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, 0), ==,
+ GPIOD_LINE_VALUE_INACTIVE);
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, 1), ==,
+ GPIOD_LINE_VALUE_ACTIVE);
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, 2), ==,
+ GPIOD_LINE_VALUE_ACTIVE);
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, 5), ==,
+ GPIOD_LINE_VALUE_ACTIVE);
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, 6), ==,
+ GPIOD_LINE_VALUE_INACTIVE);
+ g_assert_cmpint(g_gpiosim_chip_get_value(sim, 7), ==,
+ GPIOD_LINE_VALUE_INACTIVE);
+}
deleted file mode 100644
@@ -1,1091 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-
-#include <errno.h>
-#include <string.h>
-
-#include "gpiod-test.h"
-
-#define GPIOD_TEST_GROUP "line"
-
-GPIOD_TEST_CASE(request_output, 0, { 8 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line *line0;
- struct gpiod_line *line1;
- 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, 2);
- line1 = gpiod_chip_get_line(chip, 5);
- g_assert_nonnull(line0);
- g_assert_nonnull(line1);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_request_output(line0, GPIOD_TEST_CONSUMER, 0);
- g_assert_cmpint(ret, ==, 0);
- ret = gpiod_line_request_output(line1, GPIOD_TEST_CONSUMER, 1);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
- g_assert_cmpint(gpiod_test_chip_get_value(0, 5), ==, 1);
-}
-
-GPIOD_TEST_CASE(request_already_requested, 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, 0);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, -1);
- g_assert_cmpint(errno, ==, EBUSY);
-}
-
-GPIOD_TEST_CASE(consumer, 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, 0);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- g_assert_null(gpiod_line_consumer(line));
-
- ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpstr(gpiod_line_consumer(line), ==, GPIOD_TEST_CONSUMER);
-}
-
-GPIOD_TEST_CASE(consumer_long_string, 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, 0);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- g_assert_null(gpiod_line_consumer(line));
-
- ret = gpiod_line_request_input(line,
- "consumer string over 32 characters long");
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
- g_assert_cmpstr(gpiod_line_consumer(line), ==,
- "consumer string over 32 charact");
- g_assert_cmpuint(strlen(gpiod_line_consumer(line)), ==, 31);
-}
-
-GPIOD_TEST_CASE(request_bulk_output, 0, { 8, 8 })
-{
- g_autoptr(gpiod_line_bulk_struct) bulkA = NULL;
- g_autoptr(gpiod_line_bulk_struct) bulkB = NULL;
- g_autoptr(gpiod_chip_struct) chipA = NULL;
- g_autoptr(gpiod_chip_struct) chipB = NULL;
- struct gpiod_line *lineA0, *lineA1, *lineA2, *lineA3,
- *lineB0, *lineB1, *lineB2, *lineB3;
- gint valA[4], valB[4], ret;
-
- chipA = gpiod_chip_open(gpiod_test_chip_path(0));
- chipB = gpiod_chip_open(gpiod_test_chip_path(1));
- g_assert_nonnull(chipA);
- g_assert_nonnull(chipB);
- gpiod_test_return_if_failed();
-
- lineA0 = gpiod_chip_get_line(chipA, 0);
- lineA1 = gpiod_chip_get_line(chipA, 1);
- lineA2 = gpiod_chip_get_line(chipA, 2);
- lineA3 = gpiod_chip_get_line(chipA, 3);
- lineB0 = gpiod_chip_get_line(chipB, 0);
- lineB1 = gpiod_chip_get_line(chipB, 1);
- lineB2 = gpiod_chip_get_line(chipB, 2);
- lineB3 = gpiod_chip_get_line(chipB, 3);
-
- g_assert_nonnull(lineA0);
- g_assert_nonnull(lineA1);
- g_assert_nonnull(lineA2);
- g_assert_nonnull(lineA3);
- g_assert_nonnull(lineB0);
- g_assert_nonnull(lineB1);
- g_assert_nonnull(lineB2);
- g_assert_nonnull(lineB3);
- gpiod_test_return_if_failed();
-
- bulkA = gpiod_line_bulk_new(4);
- bulkB = gpiod_line_bulk_new(4);
- g_assert_nonnull(bulkA);
- g_assert_nonnull(bulkB);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulkA, lineA0);
- gpiod_line_bulk_add_line(bulkA, lineA1);
- gpiod_line_bulk_add_line(bulkA, lineA2);
- gpiod_line_bulk_add_line(bulkA, lineA3);
- gpiod_line_bulk_add_line(bulkB, lineB0);
- gpiod_line_bulk_add_line(bulkB, lineB1);
- gpiod_line_bulk_add_line(bulkB, lineB2);
- gpiod_line_bulk_add_line(bulkB, lineB3);
-
- valA[0] = 1;
- valA[1] = 0;
- valA[2] = 0;
- valA[3] = 1;
- ret = gpiod_line_request_bulk_output(bulkA,
- GPIOD_TEST_CONSUMER, valA);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- valB[0] = 0;
- valB[1] = 1;
- valB[2] = 0;
- valB[3] = 1;
- ret = gpiod_line_request_bulk_output(bulkB,
- GPIOD_TEST_CONSUMER, valB);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- g_assert_cmpint(gpiod_test_chip_get_value(0, 0), ==, 1);
- g_assert_cmpint(gpiod_test_chip_get_value(0, 1), ==, 0);
- g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
- g_assert_cmpint(gpiod_test_chip_get_value(0, 3), ==, 1);
-
- g_assert_cmpint(gpiod_test_chip_get_value(1, 0), ==, 0);
- g_assert_cmpint(gpiod_test_chip_get_value(1, 1), ==, 1);
- g_assert_cmpint(gpiod_test_chip_get_value(1, 2), ==, 0);
- g_assert_cmpint(gpiod_test_chip_get_value(1, 3), ==, 1);
-}
-
-GPIOD_TEST_CASE(request_null_default_vals_for_output, 0, { 8 })
-{
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- 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();
-
- bulk = gpiod_line_bulk_new(3);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulk, line0);
- gpiod_line_bulk_add_line(bulk, line1);
- gpiod_line_bulk_add_line(bulk, line2);
-
- ret = gpiod_line_request_bulk_output(bulk, GPIOD_TEST_CONSUMER, NULL);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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_value, 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);
- gpiod_test_return_if_failed();
- 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_value(line, 0);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0);
-}
-
-GPIOD_TEST_CASE(set_value_bulk, 0, { 8 })
-{
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- 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();
-
- bulk = gpiod_line_bulk_new(3);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulk, line0);
- gpiod_line_bulk_add_line(bulk, line1);
- gpiod_line_bulk_add_line(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);
- gpiod_test_return_if_failed();
- 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_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- 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();
-
- bulk = gpiod_line_bulk_new(3);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulk, line0);
- gpiod_line_bulk_add_line(bulk, line1);
- gpiod_line_bulk_add_line(bulk, line2);
-
- ret = gpiod_line_request_bulk_output(bulk, GPIOD_TEST_CONSUMER, 0);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
- g_assert_false(gpiod_line_is_active_low(line0));
- g_assert_false(gpiod_line_is_active_low(line1));
- g_assert_false(gpiod_line_is_active_low(line2));
-
- 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_true(gpiod_line_is_active_low(line0));
- g_assert_true(gpiod_line_is_active_low(line1));
- g_assert_true(gpiod_line_is_active_low(line2));
- 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_false(gpiod_line_is_active_low(line0));
- g_assert_false(gpiod_line_is_active_low(line1));
- g_assert_false(gpiod_line_is_active_low(line2));
- 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);
- gpiod_test_return_if_failed();
- g_assert_false(gpiod_line_is_active_low(line));
- 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_true(gpiod_line_is_active_low(line));
- 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_false(gpiod_line_is_active_low(line));
- 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);
- gpiod_test_return_if_failed();
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_UNKNOWN);
-
- ret = gpiod_line_set_flags(line,
- GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLED);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_DISABLED);
-
- 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);
- gpiod_test_return_if_failed();
- g_assert_cmpint(gpiod_line_drive(line), ==, GPIOD_LINE_DRIVE_PUSH_PULL);
-
- ret = gpiod_line_set_flags(line,
- GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(gpiod_line_drive(line), ==,
- GPIOD_LINE_DRIVE_OPEN_DRAIN);
-
- ret = gpiod_line_set_flags(line,
- GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(gpiod_line_drive(line), ==,
- GPIOD_LINE_DRIVE_OPEN_SOURCE);
-}
-
-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);
- gpiod_test_return_if_failed();
- 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_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- 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();
-
- bulk = gpiod_line_bulk_new(3);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulk, line0);
- gpiod_line_bulk_add_line(bulk, line1);
- gpiod_line_bulk_add_line(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);
- gpiod_test_return_if_failed();
- 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_input_bulk(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_output_bulk(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_output_bulk(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_line_bulk_struct) bulk = NULL;
- 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();
-
- /* check cached by request... */
- ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
- 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);
-
- bulk = gpiod_line_bulk_new(1);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(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(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, 5);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_request_output(line, GPIOD_TEST_CONSUMER, 1);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
- 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_input(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpint(gpiod_line_direction(line), ==,
- GPIOD_LINE_DIRECTION_INPUT);
-}
-
-GPIOD_TEST_CASE(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, 5);
- g_assert_nonnull(line);
- gpiod_test_return_if_failed();
-
- ret = gpiod_line_request_input(line, GPIOD_TEST_CONSUMER);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- g_assert_false(gpiod_line_is_active_low(line));
-
- gpiod_line_release(line);
-
- ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
- GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- 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);
- gpiod_test_return_if_failed();
-
- 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);
- gpiod_test_return_if_failed();
-
- 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 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line_request_config config;
- 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();
-
- g_assert_false(gpiod_line_is_used(line));
- g_assert_cmpint(gpiod_line_drive(line), ==, GPIOD_LINE_DRIVE_PUSH_PULL);
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_UNKNOWN);
-
- config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
- config.consumer = GPIOD_TEST_CONSUMER;
- config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN;
-
- ret = gpiod_line_request(line, &config, 0);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- g_assert_true(gpiod_line_is_used(line));
- g_assert_cmpint(gpiod_line_drive(line), ==,
- GPIOD_LINE_DRIVE_OPEN_DRAIN);
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_UNKNOWN);
- g_assert_cmpint(gpiod_line_direction(line), ==,
- GPIOD_LINE_DIRECTION_OUTPUT);
-
- gpiod_line_release(line);
-
- config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE;
-
- ret = gpiod_line_request(line, &config, 0);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- g_assert_true(gpiod_line_is_used(line));
- g_assert_cmpint(gpiod_line_drive(line), ==,
- GPIOD_LINE_DRIVE_OPEN_SOURCE);
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_UNKNOWN);
- g_assert_cmpint(gpiod_line_direction(line), ==,
- GPIOD_LINE_DIRECTION_OUTPUT);
-
- gpiod_line_release(line);
-}
-
-GPIOD_TEST_CASE(misc_flags_work_together, 0, { 8 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line_request_config config;
- 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();
-
- /*
- * Verify that open drain/source flags work together
- * with active_low.
- */
-
- config.request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT;
- config.consumer = GPIOD_TEST_CONSUMER;
- config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN |
- GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
-
- ret = gpiod_line_request(line, &config, 0);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- g_assert_true(gpiod_line_is_used(line));
- g_assert_cmpint(gpiod_line_drive(line), ==,
- GPIOD_LINE_DRIVE_OPEN_DRAIN);
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_UNKNOWN);
- g_assert_true(gpiod_line_is_active_low(line));
- g_assert_cmpint(gpiod_line_direction(line), ==,
- GPIOD_LINE_DIRECTION_OUTPUT);
-
- gpiod_line_release(line);
-
- config.flags = GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE |
- GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW;
-
- ret = gpiod_line_request(line, &config, 0);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- g_assert_true(gpiod_line_is_used(line));
- g_assert_cmpint(gpiod_line_drive(line), ==,
- GPIOD_LINE_DRIVE_OPEN_SOURCE);
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_UNKNOWN);
- g_assert_true(gpiod_line_is_active_low(line));
-
- 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);
- gpiod_test_return_if_failed();
-
- g_assert_true(gpiod_line_is_used(line));
- g_assert_cmpint(gpiod_line_drive(line), ==, GPIOD_LINE_DRIVE_PUSH_PULL);
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_DOWN);
- g_assert_true(gpiod_line_is_active_low(line));
- g_assert_cmpint(gpiod_line_direction(line), ==,
- GPIOD_LINE_DIRECTION_INPUT);
-
- ret = gpiod_line_get_value(line);
- g_assert_cmpint(ret, ==, 1);
-
- 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);
- gpiod_test_return_if_failed();
-
- g_assert_true(gpiod_line_is_used(line));
- g_assert_cmpint(gpiod_line_drive(line), ==, GPIOD_LINE_DRIVE_PUSH_PULL);
- g_assert_cmpint(gpiod_line_bias(line), ==, GPIOD_LINE_BIAS_PULL_UP);
- g_assert_true(gpiod_line_is_active_low(line));
- g_assert_cmpint(gpiod_line_direction(line), ==,
- GPIOD_LINE_DIRECTION_INPUT);
-
- ret = gpiod_line_get_value(line);
- g_assert_cmpint(ret, ==, 0);
-
- gpiod_line_release(line);
-}
-
-GPIOD_TEST_CASE(open_source_open_drain_input_mode, 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_OPEN_DRAIN);
- g_assert_cmpint(ret, ==, -1);
- g_assert_cmpint(errno, ==, EINVAL);
-
- ret = gpiod_line_request_input_flags(line, GPIOD_TEST_CONSUMER,
- GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE);
- g_assert_cmpint(ret, ==, -1);
- g_assert_cmpint(errno, ==, EINVAL);
-}
-
-GPIOD_TEST_CASE(open_source_open_drain_simultaneously, 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_flags(line, GPIOD_TEST_CONSUMER,
- GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE |
- GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN, 1);
- g_assert_cmpint(ret, ==, -1);
- 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_DISABLED |
- 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_DISABLED |
- 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_DISABLED |
- 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 })
-{
- g_autoptr(gpiod_line_bulk_struct) bulk = NULL;
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line *line0;
- struct gpiod_line *line1;
- gint ret, vals[2];
-
- chip = gpiod_chip_open(gpiod_test_chip_path(0));
- g_assert_nonnull(chip);
- gpiod_test_return_if_failed();
-
- line0 = gpiod_chip_get_line(chip, 2);
- line1 = gpiod_chip_get_line(chip, 3);
- g_assert_nonnull(line0);
- g_assert_nonnull(line1);
- gpiod_test_return_if_failed();
-
- bulk = gpiod_line_bulk_new(2);
- g_assert_nonnull(bulk);
- gpiod_test_return_if_failed();
-
- gpiod_line_bulk_add_line(bulk, line0);
- gpiod_line_bulk_add_line(bulk, line1);
-
- vals[0] = vals[1] = 1;
-
- ret = gpiod_line_request_bulk_output(bulk, GPIOD_TEST_CONSUMER, vals);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
-
- gpiod_line_release(line0);
-
- ret = gpiod_line_get_value(line0);
- g_assert_cmpint(ret, ==, -1);
- g_assert_cmpint(errno, ==, EPERM);
-}
-
-GPIOD_TEST_CASE(null_consumer, 0, { 8 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line_request_config config;
- 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();
-
- config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
- config.consumer = NULL;
- config.flags = 0;
-
- ret = gpiod_line_request(line, &config, 0);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
- g_assert_cmpstr(gpiod_line_consumer(line), ==, "?");
-
- gpiod_line_release(line);
-
- /*
- * Internally we use different structures for event requests, so we
- * need to test that explicitly too.
- */
- config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES;
-
- ret = gpiod_line_request(line, &config, 0);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpstr(gpiod_line_consumer(line), ==, "?");
-}
-
-GPIOD_TEST_CASE(empty_consumer, 0, { 8 })
-{
- g_autoptr(gpiod_chip_struct) chip = NULL;
- struct gpiod_line_request_config config;
- 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();
-
- config.request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT;
- config.consumer = "";
- config.flags = 0;
-
- ret = gpiod_line_request(line, &config, 0);
- g_assert_cmpint(ret, ==, 0);
- gpiod_test_return_if_failed();
- g_assert_cmpstr(gpiod_line_consumer(line), ==, "?");
-
- gpiod_line_release(line);
-
- /*
- * Internally we use different structures for event requests, so we
- * need to test that explicitly too.
- */
- config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES;
-
- ret = gpiod_line_request(line, &config, 0);
- g_assert_cmpint(ret, ==, 0);
- g_assert_cmpstr(gpiod_line_consumer(line), ==, "?");
-}
@@ -1,25 +1,91 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
-#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <gpiod.h>
+#include <unistd.h>
#include "gpiod-test.h"
+#include "gpiod-test-helpers.h"
+#include "gpiod-test-sim.h"
#define GPIOD_TEST_GROUP "misc"
-GPIOD_TEST_CASE(version_string, 0, { 1 })
+GPIOD_TEST_CASE(is_gpiochip_bad)
{
+ g_assert_false(gpiod_is_gpiochip_device("/dev/null"));
+ g_assert_false(gpiod_is_gpiochip_device("/dev/nonexistent"));
+}
+
+GPIOD_TEST_CASE(is_gpiochip_good)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new(NULL);
+
+ g_assert_true(gpiod_is_gpiochip_device(
+ g_gpiosim_chip_get_dev_path(sim)));
+}
+
+GPIOD_TEST_CASE(is_gpiochip_link_bad)
+{
+ g_autofree gchar *link = NULL;
+ gint ret;
+
+ link = g_strdup_printf("/tmp/gpiod-test-link.%u", getpid());
+ ret = symlink("/dev/null", link);
+ g_assert_cmpint(ret, ==, 0);
+ gpiod_test_return_if_failed();
+
+ g_assert_false(gpiod_is_gpiochip_device(link));
+ ret = unlink(link);
+ g_assert_cmpint(ret, ==, 0);
+}
+
+GPIOD_TEST_CASE(is_gpiochip_link_good)
+{
+ g_autoptr(GPIOSimChip) sim = g_gpiosim_chip_new(NULL);
+ g_autofree gchar *link = NULL;
+ gint ret;
+
+ link = g_strdup_printf("/tmp/gpiod-test-link.%u", getpid());
+ ret = symlink(g_gpiosim_chip_get_dev_path(sim), link);
+ g_assert_cmpint(ret, ==, 0);
+ gpiod_test_return_if_failed();
+
+ g_assert_true(gpiod_is_gpiochip_device(link));
+ ret = unlink(link);
+ g_assert_cmpint(ret, ==, 0);
+}
+
+GPIOD_TEST_CASE(version_string)
+{
+ static const gchar *const pattern = "^[0-9][1-9]?\\.[0-9][1-9]?([\\.0-9]?|\\-devel)$";
+
+ g_autoptr(GError) err = NULL;
g_autoptr(GRegex) regex = NULL;
- GError *err = NULL;
+ g_autoptr(GMatchInfo) match = NULL;
+ g_autofree gchar *res = NULL;
const gchar *ver;
+ gboolean ret;
ver = gpiod_version_string();
g_assert_nonnull(ver);
gpiod_test_return_if_failed();
- g_assert_cmpuint(strlen(ver), >, 0);
- regex = g_regex_new("^[0-9]+\\.[0-9]+[0-9a-zA-Z\\.-]*$", 0, 0, &err);
- g_assert_null(err);
+ regex = g_regex_new(pattern, 0, 0, &err);
+ g_assert_nonnull(regex);
+ g_assert_no_error(err);
gpiod_test_return_if_failed();
- g_assert_true(g_regex_match(regex, ver, 0, NULL));
+
+ ret = g_regex_match(regex, ver, 0, &match);
+ g_assert_true(ret);
+ gpiod_test_return_if_failed();
+
+ g_assert_true(g_match_info_matches(match));
+ res = g_match_info_fetch(match, 0);
+ g_assert_nonnull(res);
+ g_assert_cmpstr(res, ==, ver);
+ g_match_info_next(match, &err);
+ g_assert_no_error(err);
+ g_assert_false(g_match_info_matches(match));
}
new file mode 100644
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski <bartekgola@gmail.com>
+
+#include <glib.h>
+#include <gpiod.h>
+
+#include "gpiod-test.h"
+#include "gpiod-test-helpers.h"
+
+#define GPIOD_TEST_GROUP "request-config"
+
+GPIOD_TEST_CASE(default_config)
+{
+ g_autoptr(struct_gpiod_request_config) config = NULL;
+
+ config = gpiod_test_create_request_config_or_fail();
+
+ g_assert_null(gpiod_request_config_get_consumer(config));
+ g_assert_cmpuint(gpiod_request_config_get_num_offsets(config), ==, 0);
+ g_assert_cmpuint(gpiod_request_config_get_event_buffer_size(config),
+ ==, 0);
+}
+
+GPIOD_TEST_CASE(consumer)
+{
+ g_autoptr(struct_gpiod_request_config) config = NULL;
+
+ config = gpiod_test_create_request_config_or_fail();
+
+ gpiod_request_config_set_consumer(config, "foobar");
+ g_assert_cmpstr(gpiod_request_config_get_consumer(config),
+ ==, "foobar");
+}
+
+GPIOD_TEST_CASE(offsets)
+{
+ static const guint offsets[] = { 0, 3, 4, 7 };
+
+ g_autoptr(struct_gpiod_request_config) config = NULL;
+ guint read_back[4], i;
+
+ config = gpiod_test_create_request_config_or_fail();
+
+ gpiod_request_config_set_offsets(config, 4, offsets);
+ g_assert_cmpuint(gpiod_request_config_get_num_offsets(config), ==, 4);
+ memset(read_back, 0, sizeof(read_back));
+ gpiod_request_config_get_offsets(config, read_back);
+ for (i = 0; i < 4; i++)
+ g_assert_cmpuint(read_back[i], ==, offsets[i]);
+}
+
+GPIOD_TEST_CASE(max_offsets)
+{
+ static const guint offsets_good[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
+ };
+
+ static const guint offsets_bad[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64
+ };
+
+ g_autoptr(struct_gpiod_request_config) config = NULL;
+
+ config = gpiod_test_create_request_config_or_fail();
+
+ gpiod_request_config_set_offsets(config, 64, offsets_good);
+ g_assert_cmpuint(gpiod_request_config_get_num_offsets(config), ==, 64);
+
+ gpiod_request_config_set_offsets(config, 65, offsets_bad);
+ /* Should get truncated. */
+ g_assert_cmpuint(gpiod_request_config_get_num_offsets(config), ==, 64);
+}
+
+GPIOD_TEST_CASE(event_buffer_size)
+{
+ g_autoptr(struct_gpiod_request_config) config = NULL;
+
+ config = gpiod_test_create_request_config_or_fail();
+
+ gpiod_request_config_set_event_buffer_size(config, 128);
+ g_assert_cmpuint(gpiod_request_config_get_event_buffer_size(config),
+ ==, 128);
+}
This replaces the old tests for the C API v1 based on gpio-mockup with a test suite based on gpio-sim that covers around 95% of the libgpiod v2 codebase. The test harness has been rebuilt and shrank significantly as well. The libgpiosim API has been wrapped in a gobject interface. Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl> --- configure.ac | 8 +- tests/Makefile.am | 22 +- tests/gpiod-test-helpers.c | 49 ++ tests/gpiod-test-helpers.h | 139 +++++ tests/gpiod-test-sim.c | 308 ++++++++++ tests/gpiod-test-sim.h | 42 ++ tests/gpiod-test.c | 233 +------- tests/gpiod-test.h | 83 +-- tests/gpiosim/gpiosim.c | 1 + tests/mockup/Makefile.am | 11 - tests/mockup/gpio-mockup.c | 496 ---------------- tests/mockup/gpio-mockup.h | 36 -- tests/tests-chip.c | 282 ++++----- tests/tests-edge-event.c | 490 +++++++++++++++ tests/tests-event.c | 908 ---------------------------- tests/tests-info-event.c | 301 ++++++++++ tests/tests-line-config.c | 457 ++++++++++++++ tests/tests-line-info.c | 318 ++++++++++ tests/tests-line-request.c | 526 ++++++++++++++++ tests/tests-line.c | 1091 ---------------------------------- tests/tests-misc.c | 80 ++- tests/tests-request-config.c | 90 +++ 22 files changed, 2948 insertions(+), 3023 deletions(-) create mode 100644 tests/gpiod-test-helpers.c create mode 100644 tests/gpiod-test-helpers.h create mode 100644 tests/gpiod-test-sim.c create mode 100644 tests/gpiod-test-sim.h delete mode 100644 tests/mockup/Makefile.am delete mode 100644 tests/mockup/gpio-mockup.c delete mode 100644 tests/mockup/gpio-mockup.h create mode 100644 tests/tests-edge-event.c delete mode 100644 tests/tests-event.c create mode 100644 tests/tests-info-event.c create mode 100644 tests/tests-line-config.c create mode 100644 tests/tests-line-info.c create mode 100644 tests/tests-line-request.c delete mode 100644 tests/tests-line.c create mode 100644 tests/tests-request-config.c