From patchwork Thu Apr 29 09:47:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 429437 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3D071C433B4 for ; Thu, 29 Apr 2021 09:47:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E70C46144E for ; Thu, 29 Apr 2021 09:47:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237770AbhD2Js2 (ORCPT ); Thu, 29 Apr 2021 05:48:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34490 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231543AbhD2Js2 (ORCPT ); Thu, 29 Apr 2021 05:48:28 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ED501C06138B for ; Thu, 29 Apr 2021 02:47:41 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id a4so66219273wrr.2 for ; Thu, 29 Apr 2021 02:47:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=2h0QVn/oL473IB8Q1NaktiOKDyPIbAgcnbg+Mk2qzbA=; b=CjQdbSl9SPxef22NMHAltRZKZ63HMZYxnkBD6HRx/TJKhuJOE/ejzQmTRArlKjZx8R O2NXl6J4WdG6orP/Xgg1WHbtXgtfRhIROFMETeh/6GsDQivqA/MdY/bNWaj7SjoXO+mB cyYi6LQPKgx3xIRQYmxOqNaWNnBiLx4mhRtOcjnKDiDFFmCCyiaJg8D5OUyhW6SMIzkG LIgO6fKfTkcVt7T+1TyOVRdvtybdihYLQMMMaLk3JWTfFanlTHFwo3tJx+epA1dhQN3r m76yAz6KbWZrPoR17J4KCpRTQrQ4z+UBGMxRAWUugxv0U3JQ7/ljaheGzuAi3FlsL3wb I6KA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=2h0QVn/oL473IB8Q1NaktiOKDyPIbAgcnbg+Mk2qzbA=; b=sFy8CNVUNy3j/1eoe7q02aYHr9BAiaBPlY1mByDRzcnl4wOIPe7zUaSXy6sQRAlJuh +v2COkNd4RIwSH21cFtjVeBy0cApAvQ6ycslpsTVk/7c4RH7pYEN+e+SIG0+ydxiCRRl lBfWjVgiI43y0G9VQFv4D4oajIszJ9Iqwe3p3u/dCeLJkoqxBW41uKPF7gAnSE3+7/9G UqWRkLsK+8J9yLojBWJmtCSR7RYDF63pg9vcsOlZlNjqgeKPM5drXa6WD16OPxa1OXHW g8lZk1KKRYCb7wX85hSOaAvh3FCZCQYQhr/FWRwZbGZxQ55yHN1Dd1fb9deS46Aqh63y dnmA== X-Gm-Message-State: AOAM530mjSQ7DzMMuZClm+BKIOvblpdeyQRo0fT49j+M4r3qHmMTw2Ie pf/NaXAVx4hcfHJkDYHh5HzmCg== X-Google-Smtp-Source: ABdhPJwzbxsdxO31viLRA++o1eVQauZDTxPUXLwAqKkLKP7lQ4yNAHDszsuJLk7PmU79vuMzwYNtwA== X-Received: by 2002:adf:dd4f:: with SMTP id u15mr27514431wrm.308.1619689660796; Thu, 29 Apr 2021 02:47:40 -0700 (PDT) Received: from debian-brgl.home (lfbn-nic-1-149-6.w2-15.abo.wanadoo.fr. [2.15.231.6]) by smtp.gmail.com with ESMTPSA id j22sm4101247wra.46.2021.04.29.02.47.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Apr 2021 02:47:40 -0700 (PDT) From: Bartosz Golaszewski To: Kent Gibson , Linus Walleij , Andy Shevchenko Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 1/3] tests: remove gpiod_test_chip_num() Date: Thu, 29 Apr 2021 11:47:32 +0200 Message-Id: <20210429094734.9585-2-brgl@bgdev.pl> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210429094734.9585-1-brgl@bgdev.pl> References: <20210429094734.9585-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org This function is no longer used, remove it. Signed-off-by: Bartosz Golaszewski --- tests/gpiod-test.c | 12 ------------ tests/gpiod-test.h | 1 - 2 files changed, 13 deletions(-) diff --git a/tests/gpiod-test.c b/tests/gpiod-test.c index 2681278..ca5cdb3 100644 --- a/tests/gpiod-test.c +++ b/tests/gpiod-test.c @@ -149,18 +149,6 @@ const gchar *gpiod_test_chip_name(guint idx) return name; } -gint gpiod_test_chip_num(unsigned int idx) -{ - gint num; - - num = gpio_mockup_chip_num(globals.mockup, idx); - if (num < 0) - g_error("unable to retrieve the chip number: %s", - g_strerror(errno)); - - return num; -} - gint gpiod_test_chip_get_value(guint chip_index, guint line_offset) { gint ret; diff --git a/tests/gpiod-test.h b/tests/gpiod-test.h index a093f83..61735d9 100644 --- a/tests/gpiod-test.h +++ b/tests/gpiod-test.h @@ -80,7 +80,6 @@ enum { /* Wrappers around libgpiomockup helpers. */ const gchar *gpiod_test_chip_path(guint idx); const gchar *gpiod_test_chip_name(guint idx); -gint gpiod_test_chip_num(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); From patchwork Thu Apr 29 09:47:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 429436 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B6A30C433ED for ; Thu, 29 Apr 2021 09:47:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 356326144E for ; Thu, 29 Apr 2021 09:47:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237788AbhD2Jsa (ORCPT ); Thu, 29 Apr 2021 05:48:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34498 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231543AbhD2Jsa (ORCPT ); Thu, 29 Apr 2021 05:48:30 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CB379C06138B for ; Thu, 29 Apr 2021 02:47:42 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id x5so15926113wrv.13 for ; Thu, 29 Apr 2021 02:47:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wVB4u4MAAXR/zcjuQ67DXb4v0/xTY/muAtgeR8vGm6o=; b=d+2iJHwx8CAuuf9G6GlvQsP6NaIMrw6qCwWf1RkntB69YZGbN/8oVtS4J6fQ8OTOuf +j5Sl5wwbXn3Gz6xKcW6mHBENlpi3iV4dJ7Rh8YT5bAJbBbifSvcuQTQ2s5q/F7racVf /oyjnMDj+yPNEfYEznYmnVpeMwn/oDo22wzplLjDs+3BopehtlIaDT40Op3iMRQOrRZ9 mv7CZRJoKYUNK6kTX/WR2UVULAIr+sAWT95Tr4doCpkzeSF52BPtRYpsLRHvKGNTl/Uz EJM3XVldc2dTtg4xL4gg8GGXm+xEHciKV7tCwuKB97qwMgULmks/WdHPerZ1ETtk1Wvo nOBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wVB4u4MAAXR/zcjuQ67DXb4v0/xTY/muAtgeR8vGm6o=; b=JFMmwvJN9ha9w3KAinU1TsKUYA83auyFdqovacPOyCLexBn2bH5/3Cl0Zulxnp+UMY vcB8f9yx6LE4Ov5OoiEhrWlfrqb2nFy8Zc3mHvUn1mY+Xg1kmPSHMh7MT1LKZVEcQQlt Bnq7NkmdKc1O4RsG36kyOMLTwfA6w+5g7mfmbYNjCka+rmtUKL09g893gx8KHRl5aXkW OLh+QZXeXasWV2pV1pBfDwOadDpONzvPy4LirwIr91anN0rlrnnyfhT3oHYd+vUMHwwn SOo8Bsrmdnk/34RipxUK6JmP82srvfEQKv8URxoQsBMBAYAzO64YNJIyAU2Na7KdxNHf ei1w== X-Gm-Message-State: AOAM532QNJHCQ6Lp4Lxjk/BWIRh126581Om8yvdbmIPgR+hxPO4V6eIR Gnm8MkC8eJuIdEV7OeSv0XjVSA== X-Google-Smtp-Source: ABdhPJztSdBz6OxX0Y/Rz8Rqo/I3i0BnqykkwY2wNoRHG2piUqi/lI1a6KwhLPxieYlttwzefuH8lg== X-Received: by 2002:adf:ed07:: with SMTP id a7mr28085979wro.113.1619689661509; Thu, 29 Apr 2021 02:47:41 -0700 (PDT) Received: from debian-brgl.home (lfbn-nic-1-149-6.w2-15.abo.wanadoo.fr. [2.15.231.6]) by smtp.gmail.com with ESMTPSA id j22sm4101247wra.46.2021.04.29.02.47.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Apr 2021 02:47:41 -0700 (PDT) From: Bartosz Golaszewski To: Kent Gibson , Linus Walleij , Andy Shevchenko Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 2/3] libgpiosim: new library for controlling the gpio-sim module Date: Thu, 29 Apr 2021 11:47:33 +0200 Message-Id: <20210429094734.9585-3-brgl@bgdev.pl> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210429094734.9585-1-brgl@bgdev.pl> References: <20210429094734.9585-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Add a C library for controlling the gpio-sim kernel module from various libgpiod test suites. This aims at replacing the old gpio-mockup module and its user-space library - libgpio-mockup - in the project's tree. Signed-off-by: Bartosz Golaszewski --- configure.ac | 5 +- tests/Makefile.am | 2 +- tests/gpiosim/.gitignore | 4 + tests/gpiosim/Makefile.am | 16 + tests/gpiosim/gpiosim-selftest.c | 103 +++++ tests/gpiosim/gpiosim.c | 743 +++++++++++++++++++++++++++++++ tests/gpiosim/gpiosim.h | 42 ++ 7 files changed, 913 insertions(+), 2 deletions(-) create mode 100644 tests/gpiosim/.gitignore create mode 100644 tests/gpiosim/Makefile.am create mode 100644 tests/gpiosim/gpiosim-selftest.c create mode 100644 tests/gpiosim/gpiosim.c create mode 100644 tests/gpiosim/gpiosim.h diff --git a/configure.ac b/configure.ac index e0a917f..af8249c 100644 --- a/configure.ac +++ b/configure.ac @@ -31,6 +31,7 @@ AC_SUBST(ABI_CXX_VERSION, [2.1.1]) # ABI version for libgpiomockup (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]) AC_CONFIG_MACRO_DIRS([m4]) @@ -126,10 +127,11 @@ AC_DEFUN([FUNC_NOT_FOUND_TESTS], if test "x$with_tests" = xtrue then - # For libgpiomockup + # For libgpiomockup & 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]) @@ -224,6 +226,7 @@ AC_CONFIG_FILES([Makefile tools/Makefile tests/Makefile tests/mockup/Makefile + tests/gpiosim/Makefile bindings/cxx/libgpiodcxx.pc bindings/Makefile bindings/cxx/Makefile diff --git a/tests/Makefile.am b/tests/Makefile.am index 43b215e..760aefa 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski -SUBDIRS = mockup +SUBDIRS = mockup gpiosim AM_CFLAGS = -I$(top_srcdir)/include/ -I$(top_srcdir)/tests/mockup/ AM_CFLAGS += -include $(top_builddir)/config.h diff --git a/tests/gpiosim/.gitignore b/tests/gpiosim/.gitignore new file mode 100644 index 0000000..16b38d2 --- /dev/null +++ b/tests/gpiosim/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# SPDX-FileCopyrightText: 2017-2021 Bartosz Golaszewski + +gpiosim-selftest diff --git a/tests/gpiosim/Makefile.am b/tests/gpiosim/Makefile.am new file mode 100644 index 0000000..ca08f6e --- /dev/null +++ b/tests/gpiosim/Makefile.am @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# SPDX-FileCopyrightText: 2021 Bartosz Golaszewski + +lib_LTLIBRARIES = libgpiosim.la +noinst_PROGRAMS = gpiosim-selftest + +AM_CFLAGS = -Wall -Wextra -g -fvisibility=hidden -std=gnu89 +AM_CFLAGS += -include $(top_builddir)/config.h + +libgpiosim_la_SOURCES = gpiosim.c gpiosim.h +libgpiosim_la_CFLAGS = $(AM_CFLAGS) $(KMOD_CFLAGS) $(UDEV_CFLAGS) $(MOUNT_CFLAGS) +libgpiosim_la_LDFLAGS = -version-info $(subst .,:,$(ABI_GPIOSIM_VERSION)) +libgpiosim_la_LDFLAGS += $(KMOD_LIBS) $(UDEV_LIBS) $(MOUNT_LIBS) + +gpiosim_selftest_SOURCES = gpiosim-selftest.c +gpiosim_selftest_LDADD = libgpiosim.la diff --git a/tests/gpiosim/gpiosim-selftest.c b/tests/gpiosim/gpiosim-selftest.c new file mode 100644 index 0000000..db87dd8 --- /dev/null +++ b/tests/gpiosim/gpiosim-selftest.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2021 Bartosz Golaszewski + +#include +#include + +#include "gpiosim.h" + +#define UNUSED __attribute__((unused)) + +static char *line_names[] = { + "foo", + "bar", + "foobar", + NULL, + "barfoo", +}; + +int main(int argc UNUSED, char **argv UNUSED) +{ + const char *devpath, *chip_name; + struct gpiosim_ctx *sim_ctx; + struct gpiosim_chip *chip; + int ret; + + printf("Creating gpiosim context\n"); + + sim_ctx = gpiosim_ctx_new(); + if (!sim_ctx) { + perror("unable to create the gpios-sim context"); + return EXIT_FAILURE; + } + + printf("Creating a chip with random name\n"); + + chip = gpiosim_chip_new(sim_ctx, NULL); + if (!chip) { + perror("Unable to create a chip with random name"); + return EXIT_FAILURE; + } + + printf("Setting the number of lines to 16\n"); + + ret = gpiosim_chip_set_num_lines(chip, 16); + if (ret) { + perror("Unable to set the number of lines"); + return EXIT_FAILURE; + } + + printf("Setting the chip label\n"); + + ret = gpiosim_chip_set_label(chip, "foobar"); + if (ret) { + perror("Unable to set the chip label"); + return EXIT_FAILURE; + } + + printf("Setting the line names\n"); + + ret = gpiosim_chip_set_line_names(chip, 5, line_names); + if (ret) { + perror("Unable to set GPIO line names"); + return EXIT_FAILURE; + } + + printf("Committing the chip\n"); + + ret = gpiosim_chip_commit_sync(chip); + if (ret) { + perror("Unable to commit the chip"); + return EXIT_FAILURE; + } + + printf("Reading the device path\n"); + + devpath = gpiosim_chip_get_dev(chip); + if (!devpath) { + perror("Unable to read the device path"); + return EXIT_FAILURE; + } + + printf("The device path is: '%s'\n", devpath); + printf("Reading the chip name\n"); + + chip_name = gpiosim_chip_get_name(chip); + if (!chip_name) { + perror("Unable to read the chip name"); + return EXIT_FAILURE; + } + + printf("The chip name is: '%s'\n", chip_name); + + ret = gpiosim_chip_uncommit(chip); + if (ret) { + perror("Unable to uncommit the chip"); + return EXIT_FAILURE; + } + + gpiosim_chip_unref(chip); + gpiosim_ctx_unref(sim_ctx); + + return EXIT_SUCCESS; +} diff --git a/tests/gpiosim/gpiosim.c b/tests/gpiosim/gpiosim.c new file mode 100644 index 0000000..169ccc6 --- /dev/null +++ b/tests/gpiosim/gpiosim.c @@ -0,0 +1,743 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2021 Bartosz Golaszewski + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gpiosim.h" + +#define GPIOSIM_API __attribute__((visibility("default"))) +#define GPIOSIM_ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +/* FIXME Bump to 5.13 once released. */ +#define MIN_KERNEL_VERSION KERNEL_VERSION(5, 12, 0) + +struct gpiosim_ctx { + unsigned int refcnt; + int pending_dir_fd; + int live_dir_fd; + char *cfs_mnt_dir; +}; + +struct gpiosim_chip { + unsigned int refcnt; + struct gpiosim_ctx *ctx; + bool live; + char *item_name; + char *devname; + char *chipname; + char *devnode; + int configfs_dir_fd; + int sysfs_dir_fd; +}; + +static int check_kernel_version(void) +{ + unsigned int major, minor, release; + struct utsname un; + int rv; + + rv = uname(&un); + if (rv) + return -1; + + rv = sscanf(un.release, "%u.%u.%u", &major, &minor, &release); + if (rv != 3) { + errno = EFAULT; + return -1; + } + + if (KERNEL_VERSION(major, minor, release) < MIN_KERNEL_VERSION) { + errno = EOPNOTSUPP; + return -1; + } + + return 0; +} + +static int check_gpiosim_module(void) +{ + struct kmod_module *module; + struct kmod_ctx *kmod; + const char *modpath; + int ret, initstate; + + kmod = kmod_new(NULL, NULL); + if (!kmod) + return -1; + + ret = kmod_module_new_from_name(kmod, "gpio-sim", &module); + if (ret) + goto out_unref_kmod; + +again: + /* First check if the module is already loaded or built-in. */ + initstate = kmod_module_get_initstate(module); + if (initstate < 0) { + if (errno == ENOENT) { + /* + * It's not loaded, let's see if we can do it manually. + * See if we can find the module. + */ + modpath = kmod_module_get_path(module); + if (!modpath) { + /* libkmod doesn't set errno. */ + errno = ENOENT; + ret = -1; + goto out_unref_module; + } + + ret = kmod_module_probe_insert_module(module, + KMOD_PROBE_IGNORE_LOADED, + NULL, NULL, NULL, NULL); + if (ret) + goto out_unref_module; + + goto again; + } else { + if (errno == 0) + errno = EOPNOTSUPP; + + goto out_unref_module; + } + } + + if (initstate != KMOD_MODULE_BUILTIN && + initstate != KMOD_MODULE_LIVE && + initstate != KMOD_MODULE_COMING) { + errno = EPERM; + goto out_unref_module; + } + + ret = 0; + +out_unref_module: + kmod_module_unref(module); +out_unref_kmod: + kmod_unref(kmod); + return ret; +} + +static int ctx_open_configfs_dirs(struct gpiosim_ctx *ctx, const char *cfs_path) +{ + int fd; + + fd = open(cfs_path, O_RDONLY); + if (fd < 0) + return -1; + + ctx->pending_dir_fd = openat(fd, "gpio-sim/pending", O_RDONLY); + if (ctx->pending_dir_fd < 0) { + close(fd); + return -1; + } + + ctx->live_dir_fd = openat(fd, "gpio-sim/live", O_RDONLY); + close(fd); + if (ctx->live_dir_fd < 0) { + close(ctx->pending_dir_fd); + return -1; + } + + return 0; +} + +/* + * We don't need to check the configfs module as loading gpio-sim will pull it + * in but we need to find out if and where configfs was mounted. If it wasn't + * then as a last resort we'll try to mount it ourselves. + */ +static int ctx_get_configfs_fds(struct gpiosim_ctx *ctx) +{ + struct libmnt_context *mntctx; + struct libmnt_iter *iter; + struct libmnt_table *tb; + struct libmnt_fs *fs; + const char *type; + int ret; + + /* Try to find out if and where configfs is mounted. */ + mntctx = mnt_new_context(); + if (!mntctx) + return -1; + + ret = mnt_context_get_mtab(mntctx, &tb); + if (ret) + goto out_free_ctx; + + iter = mnt_new_iter(MNT_ITER_FORWARD); + if (!iter) + goto out_free_ctx; + + while (mnt_table_next_fs(tb, iter, &fs) == 0) { + type = mnt_fs_get_fstype(fs); + + if (strcmp(type, "configfs") == 0) { + ret = ctx_open_configfs_dirs(ctx, + mnt_fs_get_target(fs)); + if (ret) + goto out_free_iter; + + ret = 0; + goto out_free_iter; + } + } + + /* Didn't find any configfs mounts - let's try to do it ourselves. */ + ctx->cfs_mnt_dir = strdup("/tmp/gpiosim-configfs-XXXXXX"); + if (!ctx->cfs_mnt_dir) + goto out_free_iter; + + ctx->cfs_mnt_dir = mkdtemp(ctx->cfs_mnt_dir); + if (!ctx->cfs_mnt_dir) + goto out_free_tmpdir; + + ret = mount(NULL, ctx->cfs_mnt_dir, "configfs", MS_RELATIME, NULL); + if (ret) + goto out_rm_tmpdir; + + ret = ctx_open_configfs_dirs(ctx, ctx->cfs_mnt_dir); + if (ret == 0) + /* Skip unmounting & deleting the tmp directory on success. */ + goto out_free_iter; + + umount(ctx->cfs_mnt_dir); +out_rm_tmpdir: + rmdir(ctx->cfs_mnt_dir); +out_free_tmpdir: + free(ctx->cfs_mnt_dir); + ctx->cfs_mnt_dir = NULL; +out_free_iter: + mnt_free_iter(iter); +out_free_ctx: + mnt_free_context(mntctx); + + return ret; +} + +GPIOSIM_API struct gpiosim_ctx *gpiosim_ctx_new(void) +{ + struct gpiosim_ctx *ctx; + int ret; + + ret = check_kernel_version(); + if (ret) + return NULL; + + ret = check_gpiosim_module(); + if (ret) + return NULL; + + ctx = malloc(sizeof(*ctx)); + if (!ctx) + return NULL; + + memset(ctx, 0, sizeof(*ctx)); + ctx->refcnt = 1; + + ret = ctx_get_configfs_fds(ctx); + if (ret) { + free(ctx); + return NULL; + } + + return ctx; +} + +GPIOSIM_API struct gpiosim_ctx *gpiosim_ctx_ref(struct gpiosim_ctx *ctx) +{ + ctx->refcnt++; + return ctx; +} + +GPIOSIM_API void gpiosim_ctx_unref(struct gpiosim_ctx *ctx) +{ + if (--ctx->refcnt == 0) { + close(ctx->pending_dir_fd); + close(ctx->live_dir_fd); + + if (ctx->cfs_mnt_dir) { + umount(ctx->cfs_mnt_dir); + rmdir(ctx->cfs_mnt_dir); + free(ctx->cfs_mnt_dir); + } + + free(ctx); + } +} + +static int open_write_close(int base_fd, const char *where, const char *what) +{ + ssize_t written, size = strlen(what); + int fd; + + fd = openat(base_fd, where, O_WRONLY); + if (fd < 0) + return -1; + + written = write(fd, what, size); + close(fd); + if (written < 0) { + return -1; + } else if (written != size) { + errno = EIO; + return -1; + } + + return 0; +} + +static int open_read_close(int base_fd, const char *where, + char *buf, size_t bufsize) +{ + ssize_t rd; + int fd; + + fd = openat(base_fd, where, O_RDONLY); + if (fd < 0) + return -1; + + memset(buf, 0, bufsize); + rd = read(fd, buf, bufsize); + close(fd); + if (rd < 0) + return -1; + + if (buf[rd - 1] == '\n') + buf[rd - 1] = '\0'; + + return 0; +} + +/* We don't have mkdtempat()... :( */ +static char *make_random_dir_at(int at) +{ + static const char chars[] = "abcdefghijklmnoprstquvwxyz" + "ABCDEFGHIJKLMNOPRSTQUVWXYZ" + "0123456789"; + static const unsigned int namelen = 16; + + unsigned int idx, i; + char *name; + int ret; + + name = malloc(namelen); + if (!name) + return NULL; + +again: + for (i = 0; i < namelen; i++) { + ret = getrandom(&idx, sizeof(idx), GRND_NONBLOCK); + if (ret != sizeof(idx)) { + if (ret >= 0) + errno = EAGAIN; + + free(name); + return NULL; + } + + name[i] = chars[idx % (GPIOSIM_ARRAY_SIZE(chars) - 1)]; + } + + ret = mkdirat(at, name, 0600); + if (ret) { + if (errno == EEXIST) + goto again; + + free(name); + return NULL; + } + + return name; +} + +GPIOSIM_API struct gpiosim_chip * +gpiosim_chip_new(struct gpiosim_ctx *ctx, const char *item_name) +{ + struct gpiosim_chip *chip; + int configfs_fd, ret; + char devname[128]; + char *name; + + if (item_name) { + name = strdup(item_name); + if (!name) + return NULL; + + ret = mkdirat(ctx->pending_dir_fd, name, 0600); + if (ret) + goto err_free_name; + } else { + name = make_random_dir_at(ctx->pending_dir_fd); + if (!name) + return NULL; + } + + configfs_fd = openat(ctx->pending_dir_fd, name, O_RDONLY); + if (configfs_fd < 0) + goto err_unlink; + + chip = malloc(sizeof(*chip)); + if (!chip) + goto err_close_fd; + + ret = open_read_close(configfs_fd, "dev_name", + devname, sizeof(devname)); + if (ret) + goto err_free_chip; + + memset(chip, 0, sizeof(*chip)); + chip->refcnt = 1; + chip->configfs_dir_fd = configfs_fd; + chip->sysfs_dir_fd = -1; + chip->item_name = name; + + chip->devname = strdup(devname); + if (!chip->devname) + goto err_free_chip; + + chip->ctx = gpiosim_ctx_ref(ctx); + + return chip; + +err_free_chip: + free(chip); +err_close_fd: + close(configfs_fd); +err_unlink: + unlinkat(ctx->pending_dir_fd, name, AT_REMOVEDIR); +err_free_name: + free(name); + + return NULL; +} + +GPIOSIM_API struct gpiosim_chip *gpiosim_chip_ref(struct gpiosim_chip *chip) +{ + chip->refcnt++; + return chip; +} + +GPIOSIM_API void gpiosim_chip_unref(struct gpiosim_chip *chip) +{ + struct gpiosim_ctx *ctx = chip->ctx; + + if (--chip->refcnt == 0) { + if (chip->live) + gpiosim_chip_uncommit(chip); + + close(chip->configfs_dir_fd); + unlinkat(ctx->pending_dir_fd, chip->item_name, AT_REMOVEDIR); + free(chip->devname); + free(chip->item_name); + gpiosim_ctx_unref(ctx); + free(chip); + } +} + +static bool chip_check_pending(struct gpiosim_chip *chip) +{ + if (chip->live) + errno = EBUSY; + + return !chip->live; +} + +static bool chip_check_live(struct gpiosim_chip *chip) +{ + if (!chip->live) + errno = ENODEV; + + return chip->live; +} + +GPIOSIM_API int gpiosim_chip_set_label(struct gpiosim_chip *chip, + const char *label) +{ + if (!chip_check_pending(chip)) + return -1; + + return open_write_close(chip->configfs_dir_fd, "label", label); +} + +GPIOSIM_API int gpiosim_chip_set_num_lines(struct gpiosim_chip *chip, + unsigned int num_lines) +{ + char buf[32]; + + if (!chip_check_pending(chip)) + return -1; + + snprintf(buf, sizeof(buf), "%u", num_lines); + + return open_write_close(chip->configfs_dir_fd, "num_lines", buf); +} + +GPIOSIM_API int gpiosim_chip_set_line_names(struct gpiosim_chip *chip, + unsigned int num_names, + char **names) +{ + int ret, written = 0; + size_t size = 0, len; + unsigned int i; + char *buf; + + if (!chip_check_pending(chip)) + return -1; + + if (!num_names) + return 0; + + for (i = 0; i < num_names; i++) { + len = names[i] ? strlen(names[i]) : 0; + /* Length of the name + '"'x2 + ', '. */ + size += len + 4; + } + + buf = malloc(size); + if (!buf) + return -1; + + memset(buf, 0, size); + + for (i = 0; i < num_names; i++) + written += snprintf(buf + written, size - written, + "\"%s\", ", names[i] ?: ""); + buf[size - 2] = '\0'; + + ret = open_write_close(chip->configfs_dir_fd, "line_names", buf); + free(buf); + return ret; +} + +static int chip_open_sysfs_dir(struct gpiosim_chip *chip) +{ + int ret, fd; + char *path; + + ret = asprintf(&path, + "/sys/devices/platform/%s/line-ctrl", chip->devname); + if (ret < 0) + return -1; + + fd = open(path, O_RDONLY); + free(path); + if (fd < 0) + return -1; + + return fd; +} + +/* Check if this is the device we're waiting for. */ +static bool check_gpiosim_devpath(struct gpiosim_chip *chip, + const char *devpath, const char *sysname) +{ + char expected[128]; + + snprintf(expected, sizeof(expected), + "/devices/platform/%s/%s", chip->devname, sysname); + + return !strcmp(devpath, expected); +} + +/* + * This version is called _sync because it synchronously waits for the chip + * to appear in the system. There's no _async variant for now but using the + * suffix here will make it easier to add it if we ever need it. + */ +GPIOSIM_API int gpiosim_chip_commit_sync(struct gpiosim_chip *chip) +{ + const char *devpath, *devnode, *sysname, *action; + struct gpiosim_ctx *ctx = chip->ctx; + struct udev_monitor *udev_mon; + struct udev_device *dev; + unsigned int tries = 10; + struct udev *udev; + struct pollfd pfd; + int ret; + + if (!chip_check_pending(chip)) + return -1; + + udev = udev_new(); + if (!udev) + return -1; + + udev_mon = udev_monitor_new_from_netlink(udev, "udev"); + if (!udev_mon) { + ret = -1; + goto out_unref_udev; + } + + ret = udev_monitor_filter_add_match_subsystem_devtype(udev_mon, + "gpio", NULL); + if (ret < 0) + goto out_unref_udev_mon; + + ret = udev_monitor_enable_receiving(udev_mon); + if (ret < 0) + goto out_unref_udev_mon; + + ret = renameat(ctx->pending_dir_fd, chip->item_name, + ctx->live_dir_fd, chip->item_name); + if (ret) + goto out_unref_udev_mon; + + while (--tries) { + pfd.fd = udev_monitor_get_fd(udev_mon); + pfd.events = POLLIN | POLLPRI; + + ret = poll(&pfd, 1, 5000); + if (ret <= 0) { + if (ret == 0) + errno = EAGAIN; + goto out_rename_back; + } + + dev = udev_monitor_receive_device(udev_mon); + if (!dev) { + ret = -1; + goto out_rename_back; + } + + 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 || + !check_gpiosim_devpath(chip, devpath, sysname) || + strcmp(action, "add") != 0) { + udev_device_unref(dev); + continue; + } + + chip->devnode = strdup(devnode); + if (!chip->devnode) { + udev_device_unref(dev); + goto out_rename_back; + } + + chip->chipname = strdup(sysname); + udev_device_unref(dev); + if (!chip->chipname) { + free(chip->devnode); + goto out_rename_back; + } + + chip->sysfs_dir_fd = chip_open_sysfs_dir(chip); + if (chip->sysfs_dir_fd < 0) { + free(chip->chipname); + free(chip->devnode); + goto out_rename_back; + } + + chip->live = true; + ret = 0; + goto out_unref_udev_mon; + } + + errno = ENODEV; + ret = -1; + +out_rename_back: + renameat(ctx->live_dir_fd, chip->item_name, + ctx->pending_dir_fd, chip->item_name); +out_unref_udev_mon: + udev_monitor_unref(udev_mon); +out_unref_udev: + udev_unref(udev); + + return ret; +} + +GPIOSIM_API int gpiosim_chip_uncommit(struct gpiosim_chip *chip) +{ + int ret; + + if (!chip_check_live(chip)) + return -1; + + ret = renameat(chip->ctx->live_dir_fd, chip->item_name, + chip->ctx->pending_dir_fd, chip->item_name); + if (ret) + return ret; + + close(chip->sysfs_dir_fd); + free(chip->chipname); + free(chip->devnode); + chip->live = false; + + return 0; +} + +GPIOSIM_API const char *gpiosim_chip_get_dev(struct gpiosim_chip *chip) +{ + if (!chip_check_live(chip)) + return NULL; + + return chip->devnode; +} + +GPIOSIM_API const char *gpiosim_chip_get_name(struct gpiosim_chip *chip) +{ + if (!chip_check_live(chip)) + return NULL; + + return chip->chipname; +} + +GPIOSIM_API int gpiosim_chip_get_value(struct gpiosim_chip *chip, + unsigned int offset) +{ + char where[32], what[3]; + int ret; + + if (!chip_check_live(chip)) + return -1; + + snprintf(where, sizeof(where), "gpio%u", offset); + + ret = open_read_close(chip->sysfs_dir_fd, where, what, sizeof(what)); + if (ret) + return ret; + + if (what[0] == '0') + return 0; + if (what[0] == '1') + return 1; + + errno = EIO; + return -1; +} + +GPIOSIM_API int gpiosim_chip_set_pull(struct gpiosim_chip *chip, + unsigned int offset, int value) +{ + char where[32], what[2]; + + if (!chip_check_live(chip)) + return -1; + + if (value != 0 && value != 1) { + errno = EINVAL; + return -1; + } + + snprintf(where, sizeof(where), "gpio%u", offset); + snprintf(what, sizeof(what), value ? "1" : "0"); + + return open_write_close(chip->sysfs_dir_fd, where, what); +} diff --git a/tests/gpiosim/gpiosim.h b/tests/gpiosim/gpiosim.h new file mode 100644 index 0000000..bdfb5a3 --- /dev/null +++ b/tests/gpiosim/gpiosim.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* SPDX-FileCopyrightText: 2021 Bartosz Golaszewski */ + +#ifndef __GPIOD_GPIOSIM_H__ +#define __GPIOD_GPIOSIM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct gpiosim_ctx; +struct gpiosim_chip; + +struct gpiosim_ctx *gpiosim_ctx_new(void); +struct gpiosim_ctx *gpiosim_ctx_ref(struct gpiosim_ctx *ctx); +void gpiosim_ctx_unref(struct gpiosim_ctx *ctx); + +struct gpiosim_chip * +gpiosim_chip_new(struct gpiosim_ctx *ctx, const char *item_name); +struct gpiosim_chip *gpiosim_chip_ref(struct gpiosim_chip *chip); +void gpiosim_chip_unref(struct gpiosim_chip *chip); + +int gpiosim_chip_set_label(struct gpiosim_chip *chip, const char *label); +int gpiosim_chip_set_num_lines(struct gpiosim_chip *chip, + unsigned int num_lines); +int gpiosim_chip_set_line_names(struct gpiosim_chip *chip, + unsigned int num_names, char **names); + +int gpiosim_chip_commit_sync(struct gpiosim_chip *chip); +int gpiosim_chip_uncommit(struct gpiosim_chip *chip); + +const char *gpiosim_chip_get_dev(struct gpiosim_chip *chip); +const char *gpiosim_chip_get_name(struct gpiosim_chip *chip); +int gpiosim_chip_get_value(struct gpiosim_chip *chip, unsigned int offset); +int gpiosim_chip_set_pull(struct gpiosim_chip *chip, + unsigned int offset, int value); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __GPIOD_GPIOSIM_H__ */ From patchwork Thu Apr 29 09:47:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 430053 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8CFB1C43461 for ; Thu, 29 Apr 2021 09:47:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 51B1461445 for ; Thu, 29 Apr 2021 09:47:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237774AbhD2Jsa (ORCPT ); Thu, 29 Apr 2021 05:48:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34500 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231543AbhD2Js3 (ORCPT ); Thu, 29 Apr 2021 05:48:29 -0400 Received: from mail-wm1-x32f.google.com (mail-wm1-x32f.google.com [IPv6:2a00:1450:4864:20::32f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 56E4FC06138C for ; Thu, 29 Apr 2021 02:47:43 -0700 (PDT) Received: by mail-wm1-x32f.google.com with SMTP id n127so23629367wmb.5 for ; Thu, 29 Apr 2021 02:47:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bgdev-pl.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=jb+UMbU0qw47lnMtR/pIbI05X1SQoANciUKyOGZ4oKc=; b=GSURITssduxp/EOS7xNhzQJkaFQu/PKZxMy1ycltAcjwyHWUsPPbheU6KBZcZp/zWC pl9Mk5vvMxtDq8+YS9eQKpyvrMnhU601EkfMlVjeRgicBPovik8PcAdsxSDhY7b//CnZ tpZrCxNRp5sXnkES1E+apwxHYZmjrG9eMXrYFqFVwjHpfrzzLGmgo5q7Ty8ngZzG7h+8 QFlN65Auja1MeBEojPfHMQdbM2dLfCz8slbB0OOBhjpSfOpbjF8is4UT4saT4zvwWJbX ay/MCEi+qoig4TLuwHui4HPqIEfsdi+fkl8WcdThSUK0wvV20w8zdauUKTEirNkQMxtp ctvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=jb+UMbU0qw47lnMtR/pIbI05X1SQoANciUKyOGZ4oKc=; b=ZvTZoxr+xhejFTJzybVDQYqkJsVeFWtxlSCKDDlCLwmnW9k2oIX8j5I2ubeLHcF1G1 BEP/UPGA3qLx2iDyhwOQJh8I4uO+OH2/3yjCRIONZw2QA8e4HQHmsOyWkoJdCKWR89E4 HJBp1cerGBADewIPxZEjaA7KxwSs+6kurqHVqidhUDaXVKihgTDBy7PP0XgJw8THqafJ pNP+5RKw2F7fn/SfBl11a3nf3Ar0F+0DBrDwExVSgAf8JEP24WgLDKXAtc1bSaW5W4ng oiNFZCiaa+Pj7sp11EI8c1kGB/GQ69vgW9+S+qR+SVxayPMejPak3Wi0xighWrvNez+J Xfaw== X-Gm-Message-State: AOAM5339ThhPlC7KowSEmU19YP/el537LTzpPqBhpOzEZHjtQtXjXkQD fobQeNY9lQAxbn/5D0HWf2HLwQ== X-Google-Smtp-Source: ABdhPJwpilzEVbLICOC6qKxNINTGrDF5e54v7XF8iCiVkME/iDAaOcsnU3ZiXayzWgKiyRTSvCvBrQ== X-Received: by 2002:a1c:2786:: with SMTP id n128mr9657836wmn.82.1619689662067; Thu, 29 Apr 2021 02:47:42 -0700 (PDT) Received: from debian-brgl.home (lfbn-nic-1-149-6.w2-15.abo.wanadoo.fr. [2.15.231.6]) by smtp.gmail.com with ESMTPSA id j22sm4101247wra.46.2021.04.29.02.47.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Apr 2021 02:47:41 -0700 (PDT) From: Bartosz Golaszewski To: Kent Gibson , Linus Walleij , Andy Shevchenko Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 3/3] tests: port C tests to libgpiosim Date: Thu, 29 Apr 2021 11:47:34 +0200 Message-Id: <20210429094734.9585-4-brgl@bgdev.pl> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210429094734.9585-1-brgl@bgdev.pl> References: <20210429094734.9585-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org This converts the core library tests to using libgpiosim instead of libgpiod-mockup while keeping the same interface for tests. Signed-off-by: Bartosz Golaszewski --- tests/Makefile.am | 4 +- tests/gpiod-test.c | 122 +++++++++++++++++++++++++++++++++++---------- tests/gpiod-test.h | 2 +- 3 files changed, 99 insertions(+), 29 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 760aefa..c8754ea 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,13 +3,13 @@ SUBDIRS = mockup gpiosim -AM_CFLAGS = -I$(top_srcdir)/include/ -I$(top_srcdir)/tests/mockup/ +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 += -DG_LOG_DOMAIN=\"gpiod-test\" AM_LDFLAGS = -pthread LDADD = $(top_builddir)/lib/libgpiod.la -LDADD += $(top_builddir)/tests/mockup/libgpiomockup.la +LDADD += $(top_builddir)/tests/gpiosim/libgpiosim.la LDADD += $(GLIB_LIBS) bin_PROGRAMS = gpiod-test diff --git a/tests/gpiod-test.c b/tests/gpiod-test.c index ca5cdb3..b279989 100644 --- a/tests/gpiod-test.c +++ b/tests/gpiod-test.c @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -30,7 +30,8 @@ struct gpiod_test_event_thread { static struct { GList *tests; - struct gpio_mockup *mockup; + struct gpiosim_ctx *gpiosim; + GPtrArray *sim_chips; } globals; static void check_kernel(void) @@ -61,29 +62,93 @@ static void check_kernel(void) return; } +static gchar **make_line_names(guint num_lines, char chip_idx) +{ + gchar **line_names; + guint i; + + line_names = g_malloc0_n(num_lines + 1, sizeof(gchar *)); + + for (i = 0; i < num_lines; i++) + line_names[i] = g_strdup_printf("gpio-mockup-%c-%u", + chip_idx, i); + + return line_names; +} + +static void remove_gpiosim_chip(gpointer data) +{ + struct gpiosim_chip *chip = data; + gint ret; + + ret = gpiosim_chip_uncommit(chip); + if (ret) + g_error("unable to uncommit a simulated chip: %s", + g_strerror(errno)); + + gpiosim_chip_unref(chip); +} + static void test_func_wrapper(gconstpointer data) { const _GpiodTestCase *test = data; - gint ret, flags = 0; + struct gpiosim_chip *sim_chip; + gchar **line_names, *label; + gchar chip_idx; + gint ret; + guint i; + + globals.sim_chips = g_ptr_array_new_full(test->num_chips, + remove_gpiosim_chip); + + for (i = 0; i < test->num_chips; i++) { + chip_idx = i + 65; + + sim_chip = gpiosim_chip_new(globals.gpiosim, NULL); + if (!sim_chip) + g_error("unable to create a simulated GPIO chip: %s", + g_strerror(errno)); + + label = g_strdup_printf("gpio-mockup-%c", chip_idx); + ret = gpiosim_chip_set_label(sim_chip, label); + g_free(label); + if (ret) + g_error("unable to set simulated chip label: %s", + g_strerror(errno)); + + ret = gpiosim_chip_set_num_lines(sim_chip, 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) { + line_names = make_line_names(test->chip_sizes[i], + chip_idx); + ret = gpiosim_chip_set_line_names(sim_chip, + test->chip_sizes[i], + line_names); + g_strfreev(line_names); + if (ret) + g_error("unable to set the line names for a simulated chip: %s", + g_strerror(errno)); + } - if (test->flags & GPIOD_TEST_FLAG_NAMED_LINES) - flags |= GPIO_MOCKUP_FLAG_NAMED_LINES; + ret = gpiosim_chip_commit_sync(sim_chip); + if (ret) + g_error("unable to commit the simulated chip: %s", + g_strerror(errno)); - ret = gpio_mockup_probe(globals.mockup, test->num_chips, - test->chip_sizes, flags); - if (ret) - g_error("unable to probe gpio-mockup: %s", g_strerror(errno)); + g_ptr_array_add(globals.sim_chips, sim_chip); + } test->func(); - ret = gpio_mockup_remove(globals.mockup); - if (ret) - g_error("unable to remove gpio_mockup: %s", g_strerror(errno)); + g_ptr_array_unref(globals.sim_chips); } -static void unref_mockup(void) +static void unref_gpiosim(void) { - gpio_mockup_unref(globals.mockup); + gpiosim_ctx_unref(globals.gpiosim); } static void add_test_from_list(gpointer element, gpointer data G_GNUC_UNUSED) @@ -102,15 +167,15 @@ int main(gint argc, gchar **argv) g_debug("%u tests registered", g_list_length(globals.tests)); /* - * Setup libgpiomockup first so that it runs its own kernel version + * 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.mockup = gpio_mockup_new(); - if (!globals.mockup) - g_error("unable to initialize gpio-mockup library: %s", + globals.gpiosim = gpiosim_ctx_new(); + if (!globals.gpiosim) + g_error("unable to initialize gpiosim library: %s", g_strerror(errno)); - atexit(unref_mockup); + atexit(unref_gpiosim); check_kernel(); @@ -127,9 +192,10 @@ void _gpiod_test_register(_GpiodTestCase *test) const gchar *gpiod_test_chip_path(guint idx) { + struct gpiosim_chip *chip = g_ptr_array_index(globals.sim_chips, idx); const gchar *path; - path = gpio_mockup_chip_path(globals.mockup, idx); + path = gpiosim_chip_get_dev(chip); if (!path) g_error("unable to retrieve the chip path: %s", g_strerror(errno)); @@ -139,9 +205,10 @@ const gchar *gpiod_test_chip_path(guint idx) const gchar *gpiod_test_chip_name(guint idx) { + struct gpiosim_chip *chip = g_ptr_array_index(globals.sim_chips, idx); const gchar *name; - name = gpio_mockup_chip_name(globals.mockup, idx); + name = gpiosim_chip_get_name(chip); if (!name) g_error("unable to retrieve the chip name: %s", g_strerror(errno)); @@ -151,11 +218,13 @@ const gchar *gpiod_test_chip_name(guint idx) gint gpiod_test_chip_get_value(guint chip_index, guint line_offset) { + struct gpiosim_chip *chip = g_ptr_array_index(globals.sim_chips, + chip_index); gint ret; - ret = gpio_mockup_get_value(globals.mockup, chip_index, line_offset); + ret = gpiosim_chip_get_value(chip, line_offset); if (ret < 0) - g_error("unable to read line value from gpio-mockup: %s", + g_error("unable to read line value from gpiosim: %s", g_strerror(errno)); return ret; @@ -163,12 +232,13 @@ 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) { + struct gpiosim_chip *chip = g_ptr_array_index(globals.sim_chips, + chip_index); gint ret; - ret = gpio_mockup_set_pull(globals.mockup, chip_index, - line_offset, pull); + ret = gpiosim_chip_set_pull(chip, line_offset, pull); if (ret) - g_error("unable to set line pull in gpio-mockup: %s", + g_error("unable to set line pull in gpiosim: %s", g_strerror(errno)); } diff --git a/tests/gpiod-test.h b/tests/gpiod-test.h index 61735d9..f2e8b02 100644 --- a/tests/gpiod-test.h +++ b/tests/gpiod-test.h @@ -50,7 +50,7 @@ enum { /* * Register a test case function. The last argument is the array of numbers - * of lines per mockup chip. + * of lines per simulated chip. */ #define GPIOD_TEST_CASE(_name, _flags, ...) \ static void _name(void); \