From patchwork Thu Dec 10 13:23:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 341379 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 A5EDFC2BB9A for ; Thu, 10 Dec 2020 13:24:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7AA7D204EF for ; Thu, 10 Dec 2020 13:24:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730429AbgLJNYM (ORCPT ); Thu, 10 Dec 2020 08:24:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50478 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728462AbgLJNYF (ORCPT ); Thu, 10 Dec 2020 08:24:05 -0500 Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B20B7C0613D6 for ; Thu, 10 Dec 2020 05:23:24 -0800 (PST) Received: by mail-wm1-x331.google.com with SMTP id g185so5292162wmf.3 for ; Thu, 10 Dec 2020 05:23:24 -0800 (PST) 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=6xN2KudYr05J6jbAqEoEctu2in84QIGf0FfBwBh+8FM=; b=hvLOoJenNJR/YFRS4ru6cMtIJQOLI30Ncqt0V3AUInqtOTgR6KggrJRaxPqpT7RTq+ B5LuDL9czS4ozvMuWju404E6eDbJKpEs9/32j0lHTcPJ4CJOqLGXewjzjSPrTojGb0JF SdKXo9vJdll3GhkUqsgeUNPdG1yOTt8XZ0Gb29l6ltVlBjBbhhyXTKqSqT/JH3eMdCkU cyvbEgAwa4gVINOODavTcCWj1ypqa9Z4uxDpjgKypZfjbwnU5M81+ahiXoL6aq6aKgtY im7lbPlgjQSp57R3C1PjxDL+AiZbJ6H4pH1+WN4IMvIrvZjLu4/51Rm/+IZlvkjxmXze vbPg== 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=6xN2KudYr05J6jbAqEoEctu2in84QIGf0FfBwBh+8FM=; b=dSdmEWLA1Y9h9IVuZbQy3w/cVtKVshxgXWafwivZCP1JaPOHiVfftnw6bNa52wQbT2 zXkcU4bHDYPwwkXW6VdU28JgclgwYRPLsAbsGCrZMQOCyiIprc5Fk5puctIOaydXH1/V 2marvjuMqJ6TMVa+B8BPuEPpbTzldHKAid6vgspyQc/AgkLkJJYd1amsaa9f89cuW5W6 qRJ9S+bOskQd7erbQZl3a+hStbxGk3sHpCkRNwNk3wTKUvOK3ZHNrcUoI0pGHeplLeSt 0+7v1bTkjfNP/yQVVfWJ6ke5rqHc+dFxPtB4VyClRhhN/wdPqLiJYWQdVfnoakMgZpr3 GsDg== X-Gm-Message-State: AOAM532rEWHNjEyoFQguQHT0XA2OI1Ss1HGtFBttmKWLVaZud+VJjyvc aYkeujJyxKdSZB/pkXo++jgLaQ== X-Google-Smtp-Source: ABdhPJzblrvS6dmmC8Apjbxvkjwd3qCXJAC7j5K4JYm0Odnv6jUAvURkVBjeL+2qYNee0Wy4WSj+4w== X-Received: by 2002:a1c:2288:: with SMTP id i130mr8344480wmi.78.1607606603426; Thu, 10 Dec 2020 05:23:23 -0800 (PST) Received: from localhost.localdomain (lfbn-nic-1-190-206.w2-15.abo.wanadoo.fr. [2.15.39.206]) by smtp.gmail.com with ESMTPSA id n14sm9444811wmi.1.2020.12.10.05.23.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 05:23:22 -0800 (PST) From: Bartosz Golaszewski To: Kent Gibson , Andy Shevchenko , Geert Uytterhoeven , Jack Winch , Helmut Grohne , Linus Walleij Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 01/14] bindings: cxx: check for error from gpiod_line_bulk_new() Date: Thu, 10 Dec 2020 14:23:02 +0100 Message-Id: <20201210132315.5785-2-brgl@bgdev.pl> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201210132315.5785-1-brgl@bgdev.pl> References: <20201210132315.5785-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Bartosz Golaszewski We call gpiod_line_bulk_new() in C++ bindings but never check its return value. This function can fail so add a private method to line_bulk that calls it and throws an exception if it returns NULL. Signed-off-by: Bartosz Golaszewski --- bindings/cxx/gpiod.hpp | 1 + bindings/cxx/line_bulk.cpp | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp index a4ef7c9..8c8e6c9 100644 --- a/bindings/cxx/gpiod.hpp +++ b/bindings/cxx/gpiod.hpp @@ -869,6 +869,7 @@ private: using line_bulk_ptr = ::std::unique_ptr<::gpiod_line_bulk, line_bulk_deleter>; + line_bulk_ptr make_line_bulk_ptr(void) const; line_bulk_ptr to_line_bulk(void) const; ::std::vector _m_bulk; diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp index c24e91d..1de90eb 100644 --- a/bindings/cxx/line_bulk.cpp +++ b/bindings/cxx/line_bulk.cpp @@ -256,8 +256,7 @@ line_bulk line_bulk::event_wait(const ::std::chrono::nanoseconds& timeout) const this->throw_if_empty(); line::chip_guard lock_chip(this->_m_bulk.front()); - auto ev_bulk = ::gpiod_line_bulk_new(this->size()); - line_bulk_ptr ev_bulk_deleter(ev_bulk); + auto ev_bulk = this->make_line_bulk_ptr(); auto bulk = this->to_line_bulk(); ::timespec ts; line_bulk ret; @@ -266,16 +265,16 @@ line_bulk line_bulk::event_wait(const ::std::chrono::nanoseconds& timeout) const ts.tv_sec = timeout.count() / 1000000000ULL; ts.tv_nsec = timeout.count() % 1000000000ULL; - rv = ::gpiod_line_event_wait_bulk(bulk.get(), ::std::addressof(ts), ev_bulk); + rv = ::gpiod_line_event_wait_bulk(bulk.get(), ::std::addressof(ts), ev_bulk.get()); if (rv < 0) { throw ::std::system_error(errno, ::std::system_category(), "error polling for events"); } else if (rv > 0) { auto chip = this->_m_bulk[0].get_chip(); - auto num_lines = ::gpiod_line_bulk_num_lines(ev_bulk); + auto num_lines = ::gpiod_line_bulk_num_lines(ev_bulk.get()); for (unsigned int i = 0; i < num_lines; i++) - ret.append(line(::gpiod_line_bulk_get_line(ev_bulk, i), chip)); + ret.append(line(::gpiod_line_bulk_get_line(ev_bulk.get(), i), chip)); } return ret; @@ -340,10 +339,21 @@ void line_bulk::throw_if_empty(void) const throw ::std::logic_error("line_bulk not holding any GPIO lines"); } -line_bulk::line_bulk_ptr line_bulk::to_line_bulk(void) const +line_bulk::line_bulk_ptr line_bulk::make_line_bulk_ptr(void) const { line_bulk_ptr bulk(::gpiod_line_bulk_new(this->size())); + if (!bulk) + throw ::std::system_error(errno, ::std::system_category(), + "unable to allocate new bulk object"); + + return bulk; +} + +line_bulk::line_bulk_ptr line_bulk::to_line_bulk(void) const +{ + line_bulk_ptr bulk = this->make_line_bulk_ptr(); + for (auto& it: this->_m_bulk) ::gpiod_line_bulk_add_line(bulk.get(), it._m_line); From patchwork Thu Dec 10 13:23:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 341380 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.8 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, 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 2C563C1B0D9 for ; Thu, 10 Dec 2020 13:24:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D99B8204EF for ; Thu, 10 Dec 2020 13:24:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732217AbgLJNYL (ORCPT ); Thu, 10 Dec 2020 08:24:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50494 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732941AbgLJNYJ (ORCPT ); Thu, 10 Dec 2020 08:24:09 -0500 Received: from mail-wm1-x343.google.com (mail-wm1-x343.google.com [IPv6:2a00:1450:4864:20::343]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9DB5FC0617A6 for ; Thu, 10 Dec 2020 05:23:28 -0800 (PST) Received: by mail-wm1-x343.google.com with SMTP id a6so4644865wmc.2 for ; Thu, 10 Dec 2020 05:23:28 -0800 (PST) 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=HrigySWoPLF+8s6ayGXgi4TAQuMuX/SPIQ5//z+/jHs=; b=ux55E9ubBwM7xvJdkWZdBDFSkk6QzRlDjqoIxTfNjgvZFMnzKZ+s0dFKmBfqTfzCJi MuR7MQNgkQlWA5cO+JtOJP87mMQHWGO/EylTs/skpiuxfPDtByGmbQjbqTdsKG7biW0d 0baXwisWQb6lryrWsaEHTiHJjckUXKgfnj5qFiN1OIVM6fJKQH/xDuZrlqqG0cWSHM3F ldKuUGyFlyPM96PGraQZHnsc7WNzznNOaScaieZu5BXcGC+5h6qfzwkIe3m8YYvmBnZs TPc6J1WErV2tDOq5XY+5WaJurq/IEMTNfm01IZimt1ukTQ0RFUjy37My56vz3/d2IBBM /cZA== 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=HrigySWoPLF+8s6ayGXgi4TAQuMuX/SPIQ5//z+/jHs=; b=Da/pTnhKbNH9O2xBkC2OM/d4jURjAXc4ifzh6G9y5abk+zkV+obaqr8A9mgvwsTD9+ woGoAuKpl55J3aGmCNWuKiPjh9Cv+f9jQIxU4BIF+s1fpVNW0Dw7n6Yxu6BltWUFtqPi 9DXyBmrO4H2n9h7IqxDLER5yLZO8Ub8tGwSPDC1mLQOMSdFSJHSHNfsQ1oNeSOkecp3A /vPaH1ihUV4RKtazfS1EDm2ST48MSiT1jjBveRIr9Hu6c1BAWvm3TErLZo8PQEoaXRes 6FDaP0CGhyXuJIogEnEzLUf/iczLtuu0IvWbR9fs+bTeyZ2IwxvLr7h0naA1DgK4thso SVlA== X-Gm-Message-State: AOAM530yG0/Y9lDKPB6nBNmWot2RFS0sy9Em+n9oXeRQYbRP1IpXR9jF DAh5oLAsdJzyvEY6s3aD2moarQ== X-Google-Smtp-Source: ABdhPJxbpCLv+cugayOMHb91aEODaoloDclzUoLQ0xSCvre5GrTnqfYfXrSm3daI41a+k1UFFSJVqw== X-Received: by 2002:a1c:80c3:: with SMTP id b186mr8000914wmd.20.1607606607419; Thu, 10 Dec 2020 05:23:27 -0800 (PST) Received: from localhost.localdomain (lfbn-nic-1-190-206.w2-15.abo.wanadoo.fr. [2.15.39.206]) by smtp.gmail.com with ESMTPSA id n14sm9444811wmi.1.2020.12.10.05.23.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 05:23:26 -0800 (PST) From: Bartosz Golaszewski To: Kent Gibson , Andy Shevchenko , Geert Uytterhoeven , Jack Winch , Helmut Grohne , Linus Walleij Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 04/14] bulk: drop the limit on the max number of lines Date: Thu, 10 Dec 2020 14:23:05 +0100 Message-Id: <20201210132315.5785-5-brgl@bgdev.pl> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201210132315.5785-1-brgl@bgdev.pl> References: <20201210132315.5785-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Bartosz Golaszewski The limit of 64 lines max per bulk object is wrong. We may want to retrieve all lines from a chip exporting more than 64. We'll be reducing the role of bulk objects soon so drop this limit now. Signed-off-by: Bartosz Golaszewski --- bindings/cxx/line_bulk.cpp | 2 +- bindings/python/gpiodmodule.c | 14 ++++++++------ include/gpiod.h | 7 ------- lib/core.c | 8 +++++--- tests/tests-bulk.c | 9 --------- tools/gpiomon.c | 5 ++++- 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/bindings/cxx/line_bulk.cpp b/bindings/cxx/line_bulk.cpp index 1de90eb..6e88d21 100644 --- a/bindings/cxx/line_bulk.cpp +++ b/bindings/cxx/line_bulk.cpp @@ -48,7 +48,7 @@ const ::std::map<::std::bitset<32>, int, bitset_cmp> reqflag_mapping = { } /* namespace */ -const unsigned int line_bulk::MAX_LINES = GPIOD_LINE_BULK_MAX_LINES; +const unsigned int line_bulk::MAX_LINES = 64; line_bulk::line_bulk(const ::std::vector& lines) : _m_bulk() diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c index b5e69a5..b9b5770 100644 --- a/bindings/python/gpiodmodule.c +++ b/bindings/python/gpiodmodule.c @@ -8,6 +8,8 @@ #include #include +#define LINE_REQUEST_MAX_LINES 64 + typedef struct { PyObject_HEAD struct gpiod_chip *chip; @@ -1138,7 +1140,7 @@ static int gpiod_LineBulk_init(gpiod_LineBulkObject *self, "Argument must be a non-empty sequence"); return -1; } - if (self->num_lines > GPIOD_LINE_BULK_MAX_LINES) { + if (self->num_lines > LINE_REQUEST_MAX_LINES) { PyErr_SetString(PyExc_TypeError, "Too many objects in the sequence"); return -1; @@ -1334,7 +1336,7 @@ static PyObject *gpiod_LineBulk_request(gpiod_LineBulkObject *self, NULL }; int rv, type = gpiod_LINE_REQ_DIR_AS_IS, flags = 0, - default_vals[GPIOD_LINE_BULK_MAX_LINES], val; + default_vals[LINE_REQUEST_MAX_LINES], val; PyObject *def_vals_obj = NULL, *iter, *next; struct gpiod_line_request_config conf; struct gpiod_line_bulk *bulk; @@ -1413,7 +1415,7 @@ PyDoc_STRVAR(gpiod_LineBulk_get_values_doc, static PyObject *gpiod_LineBulk_get_values(gpiod_LineBulkObject *self, PyObject *Py_UNUSED(ignored)) { - int rv, vals[GPIOD_LINE_BULK_MAX_LINES]; + int rv, vals[LINE_REQUEST_MAX_LINES]; struct gpiod_line_bulk *bulk; PyObject *val_list, *val; Py_ssize_t i; @@ -1506,7 +1508,7 @@ PyDoc_STRVAR(gpiod_LineBulk_set_values_doc, static PyObject *gpiod_LineBulk_set_values(gpiod_LineBulkObject *self, PyObject *args) { - int rv, vals[GPIOD_LINE_BULK_MAX_LINES]; + int rv, vals[LINE_REQUEST_MAX_LINES]; struct gpiod_line_bulk *bulk; PyObject *val_list; @@ -1556,7 +1558,7 @@ PyDoc_STRVAR(gpiod_LineBulk_set_config_doc, static PyObject *gpiod_LineBulk_set_config(gpiod_LineBulkObject *self, PyObject *args) { - int rv, vals[GPIOD_LINE_BULK_MAX_LINES]; + int rv, vals[LINE_REQUEST_MAX_LINES]; struct gpiod_line_bulk *bulk; PyObject *val_list; const int *valp; @@ -1672,7 +1674,7 @@ static PyObject *gpiod_LineBulk_set_direction_output( gpiod_LineBulkObject *self, PyObject *args) { - int rv, vals[GPIOD_LINE_BULK_MAX_LINES]; + int rv, vals[LINE_REQUEST_MAX_LINES]; struct gpiod_line_bulk *bulk; PyObject *val_list; const int *valp; diff --git a/include/gpiod.h b/include/gpiod.h index 742dfc2..9ffb446 100644 --- a/include/gpiod.h +++ b/include/gpiod.h @@ -225,17 +225,10 @@ gpiod_chip_find_lines(struct gpiod_chip *chip, const char **names) GPIOD_API; * on multiple lines at once. */ -/** - * @brief Maximum number of GPIO lines that can be requested at once or stored - * in a line bulk object at the same time. - */ -#define GPIOD_LINE_BULK_MAX_LINES 64 - /** * @brief Allocate and initialize a new line bulk object. * @param max_lines Maximum number of lines this object can hold. * @return New line bulk object or NULL on error. - * @note max_lines must not exceed ::GPIOD_LINE_BULK_MAX_LINES. */ struct gpiod_line_bulk *gpiod_line_bulk_new(unsigned int max_lines) GPIOD_API; diff --git a/lib/core.c b/lib/core.c index efba959..d96e6cf 100644 --- a/lib/core.c +++ b/lib/core.c @@ -22,6 +22,8 @@ #include #include +#define LINE_REQUEST_MAX_LINES 64 + enum { LINE_FREE = 0, LINE_REQUESTED_VALUES, @@ -94,7 +96,7 @@ struct gpiod_line_bulk *gpiod_line_bulk_new(unsigned int max_lines) struct gpiod_line_bulk *bulk; size_t size; - if (max_lines < 1 || max_lines > GPIOD_LINE_BULK_MAX_LINES) { + if (max_lines == 0) { errno = EINVAL; return NULL; } @@ -1066,7 +1068,7 @@ int gpiod_line_set_flags(struct gpiod_line *line, int flags) int gpiod_line_set_flags_bulk(struct gpiod_line_bulk *bulk, int flags) { struct gpiod_line *line; - int values[GPIOD_LINE_BULK_MAX_LINES]; + int values[LINE_REQUEST_MAX_LINES]; unsigned int i; int direction; @@ -1129,7 +1131,7 @@ int gpiod_line_event_wait_bulk(struct gpiod_line_bulk *bulk, const struct timespec *timeout, struct gpiod_line_bulk *event_bulk) { - struct pollfd fds[GPIOD_LINE_BULK_MAX_LINES]; + struct pollfd fds[LINE_REQUEST_MAX_LINES]; unsigned int off, num_lines; struct gpiod_line *line; int rv; diff --git a/tests/tests-bulk.c b/tests/tests-bulk.c index e2520fc..22cae84 100644 --- a/tests/tests-bulk.c +++ b/tests/tests-bulk.c @@ -20,15 +20,6 @@ GPIOD_TEST_CASE(alloc_zero_lines, 0, { 1 }) g_assert_cmpint(errno, ==, EINVAL); } -GPIOD_TEST_CASE(alloc_too_many_lines, 0, { 1 }) -{ - struct gpiod_line_bulk *bulk; - - bulk = gpiod_line_bulk_new(GPIOD_LINE_BULK_MAX_LINES + 1); - g_assert_null(bulk); - g_assert_cmpint(errno, ==, EINVAL); -} - GPIOD_TEST_CASE(add_too_many_lines, 0, { 8 }) { g_autoptr(gpiod_line_bulk_struct) bulk = NULL; diff --git a/tools/gpiomon.c b/tools/gpiomon.c index 44fb431..c271913 100644 --- a/tools/gpiomon.c +++ b/tools/gpiomon.c @@ -157,7 +157,7 @@ static void handle_signal(int signum UNUSED) int main(int argc, char **argv) { - unsigned int offsets[GPIOD_LINE_BULK_MAX_LINES], num_lines = 0, offset, + unsigned int offsets[64], num_lines = 0, offset, events_wanted = 0, events_done = 0, x; bool watch_rising = false, watch_falling = false; int flags = 0; @@ -241,6 +241,9 @@ int main(int argc, char **argv) if (argc < 2) die("at least one GPIO line offset must be specified"); + if (argc > 65) + die("too many offsets given"); + for (i = 1; i < argc; i++) { offset = strtoul(argv[i], &end, 10); if (*end != '\0' || offset > INT_MAX) From patchwork Thu Dec 10 13:23:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 341377 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 BA8EBC4361B for ; Thu, 10 Dec 2020 13:24:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 72EC220769 for ; Thu, 10 Dec 2020 13:24:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389111AbgLJNYk (ORCPT ); Thu, 10 Dec 2020 08:24:40 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50564 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732921AbgLJNYd (ORCPT ); Thu, 10 Dec 2020 08:24:33 -0500 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 17EF2C0617B0 for ; Thu, 10 Dec 2020 05:23:31 -0800 (PST) Received: by mail-wm1-x344.google.com with SMTP id a6so4644967wmc.2 for ; Thu, 10 Dec 2020 05:23:31 -0800 (PST) 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=Vr0/xJiQ1Lpaa2VdevHyu3D4CdrfcR8dmeD/7QGxzKc=; b=wTmf8F1qG1g/H65It7tiLlZNhrX5eYd8O/Gsp2ifF1X2nGWUyHcanCFcYbBv2eXTb4 TlIJ4hzci3CHo/eNdTVXowOgHYAybRydW9nUCUp+zVGsxy4DdH8vkamux14UnCaL6Baz /JnpGF65QFnmmGnHSkPxWg7wq2nJCTIAB8eSuHvOQXtL3ZoWn2nNhZwPQZh039ulIhon Jz+AS7dIAylD9/qCYbZq0CDE0qmJQ2WGqg2PMMT84yovx4LH7HYgenq/DA07XrB4gBUU iDbFdGi6ZxfbExMoeTz6HYY1Bg8srsORHWsbx5ANavzOCNf6uprFPq350hXIrdT+culP Qk6g== 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=Vr0/xJiQ1Lpaa2VdevHyu3D4CdrfcR8dmeD/7QGxzKc=; b=X7rz16YjxFHnCtb+jQfj1U9AiShuv+gPDcxR5nkRPDSM54KHo22G07vMb6JtEv66OC UKMKJJ3Kwer5Ul7/ywTfC0yMmp/HylcLpORNUK/7nops5WszSOUeDlys6loZbzkH4Rx1 enQeuDi8NOH+8qKQT50JG8vkZKBdV6sakgEFLDGHkmTyqtKiVKUbeY4QF0Z84Sq8NH61 YteiSUodk+NrrF0lSzomxPejYzV6o+Zbbea8YvA/bgEnLWei6n1sDLVA2KhHUNQvCxj1 wubycN01N9K0v+zJQYBvIVWpvduny14ypJE+k8wKqcnIB9Nh/XX9oqVX3mN7uorAQ3lB 1U3g== X-Gm-Message-State: AOAM532cG0Z/epw41T39bnvodHIPjTTy8H9g2dX6dUzL5CHnQnJk6S4x XU//RQQJ0lSVJCrNXLxeH/mzHQ== X-Google-Smtp-Source: ABdhPJwH4kJ0lGLKOJPMnA7nyTaFqtFx8Z+4J+NPXM0GRsbqHpmF9/5+2LFINp9u2w533eQ3cRShuQ== X-Received: by 2002:a1c:1bc6:: with SMTP id b189mr8015997wmb.71.1607606609797; Thu, 10 Dec 2020 05:23:29 -0800 (PST) Received: from localhost.localdomain (lfbn-nic-1-190-206.w2-15.abo.wanadoo.fr. [2.15.39.206]) by smtp.gmail.com with ESMTPSA id n14sm9444811wmi.1.2020.12.10.05.23.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 05:23:29 -0800 (PST) From: Bartosz Golaszewski To: Kent Gibson , Andy Shevchenko , Geert Uytterhoeven , Jack Winch , Helmut Grohne , Linus Walleij Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 06/14] treewide: kill opening chips by label Date: Thu, 10 Dec 2020 14:23:07 +0100 Message-Id: <20201210132315.5785-7-brgl@bgdev.pl> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201210132315.5785-1-brgl@bgdev.pl> References: <20201210132315.5785-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Bartosz Golaszewski Chip labels are not unique - opening chips by label may lead to errors or to ignoring chips with duplicate labels. Users can easily implement chip lookup by label themselves so remove this part from the core library and all bindings. Signed-off-by: Bartosz Golaszewski --- bindings/cxx/chip.cpp | 6 ----- bindings/cxx/gpiod.hpp | 2 -- bindings/cxx/tests/tests-chip.cpp | 20 ---------------- bindings/python/gpiodmodule.c | 17 ++++--------- bindings/python/tests/gpiod_py_test.py | 8 ------- include/gpiod.h | 14 ++--------- lib/helpers.c | 33 ++++---------------------- tests/tests-chip.c | 24 ------------------- 8 files changed, 10 insertions(+), 114 deletions(-) diff --git a/bindings/cxx/chip.cpp b/bindings/cxx/chip.cpp index 1fc0723..dffa7a2 100644 --- a/bindings/cxx/chip.cpp +++ b/bindings/cxx/chip.cpp @@ -30,11 +30,6 @@ namespace { return ::gpiod_chip_open_by_name(device.c_str()); } -::gpiod_chip* open_by_label(const ::std::string& device) -{ - return ::gpiod_chip_open_by_label(device.c_str()); -} - ::gpiod_chip* open_by_number(const ::std::string& device) { return ::gpiod_chip_open_by_number(::std::stoul(device)); @@ -46,7 +41,6 @@ const ::std::map open_funcs = { { chip::OPEN_LOOKUP, open_lookup, }, { chip::OPEN_BY_PATH, open_by_path, }, { chip::OPEN_BY_NAME, open_by_name, }, - { chip::OPEN_BY_LABEL, open_by_label, }, { chip::OPEN_BY_NUMBER, open_by_number, }, }; diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp index 0f1d9b2..0d443b0 100644 --- a/bindings/cxx/gpiod.hpp +++ b/bindings/cxx/gpiod.hpp @@ -190,8 +190,6 @@ public: /**< Assume the string is a path to the GPIO chardev. */ OPEN_BY_NAME, /**< Assume the string is the name of the chip */ - OPEN_BY_LABEL, - /**< Assume the string is the label of the GPIO chip. */ OPEN_BY_NUMBER, /**< Assume the string is the number of the GPIO chip. */ }; diff --git a/bindings/cxx/tests/tests-chip.cpp b/bindings/cxx/tests/tests-chip.cpp index 1c69872..4c9f113 100644 --- a/bindings/cxx/tests/tests-chip.cpp +++ b/bindings/cxx/tests/tests-chip.cpp @@ -28,11 +28,6 @@ TEST_CASE("GPIO chip device can be opened in different modes", "[chip]") ::gpiod::chip::OPEN_BY_PATH)); } - SECTION("open by label") - { - REQUIRE_NOTHROW(::gpiod::chip("gpio-mockup-B", ::gpiod::chip::OPEN_BY_LABEL)); - } - SECTION("open by number") { REQUIRE_NOTHROW(::gpiod::chip(::std::to_string(mockup::instance().chip_num(1)), @@ -54,11 +49,6 @@ TEST_CASE("GPIO chip device can be opened with implicit lookup", "[chip]") REQUIRE_NOTHROW(::gpiod::chip(mockup::instance().chip_path(1))); } - SECTION("lookup by label") - { - REQUIRE_NOTHROW(::gpiod::chip("gpio-mockup-B")); - } - SECTION("lookup by number") { REQUIRE_NOTHROW(::gpiod::chip(::std::to_string(mockup::instance().chip_num(1)))); @@ -84,11 +74,6 @@ TEST_CASE("GPIO chip can be opened with the open() method in different modes", " ::gpiod::chip::OPEN_BY_PATH)); } - SECTION("open by label") - { - REQUIRE_NOTHROW(chip.open("gpio-mockup-B", ::gpiod::chip::OPEN_BY_LABEL)); - } - SECTION("open by number") { REQUIRE_NOTHROW(chip.open(::std::to_string(mockup::instance().chip_num(1)), @@ -126,11 +111,6 @@ TEST_CASE("GPIO chip can be opened with the open() method with implicit lookup", REQUIRE_NOTHROW(chip.open(mockup::instance().chip_path(1))); } - SECTION("lookup by label") - { - REQUIRE_NOTHROW(chip.open("gpio-mockup-B")); - } - SECTION("lookup by number") { REQUIRE_NOTHROW(chip.open(::std::to_string(mockup::instance().chip_num(1)))); diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c index 11d1407..17a58b1 100644 --- a/bindings/python/gpiodmodule.c +++ b/bindings/python/gpiodmodule.c @@ -1961,7 +1961,6 @@ enum { gpiod_OPEN_LOOKUP = 1, gpiod_OPEN_BY_NAME, gpiod_OPEN_BY_PATH, - gpiod_OPEN_BY_LABEL, gpiod_OPEN_BY_NUMBER, }; @@ -1987,9 +1986,6 @@ static int gpiod_Chip_init(gpiod_ChipObject *self, case gpiod_OPEN_BY_PATH: self->chip = gpiod_chip_open(descr); break; - case gpiod_OPEN_BY_LABEL: - self->chip = gpiod_chip_open_by_label(descr); - break; case gpiod_OPEN_BY_NUMBER: self->chip = gpiod_chip_open_by_number(atoi(descr)); break; @@ -2503,10 +2499,10 @@ PyDoc_STRVAR(gpiod_ChipType_doc, "The Chip object's constructor takes a description string as argument the\n" "meaning of which depends on the second, optional parameter which defines\n" "the way the description string should be interpreted. The available\n" -"options are: OPEN_BY_LABEL, OPEN_BY_NAME, OPEN_BY_NUMBER, OPEN_BY_PATH,\n" -"and OPEN_LOOKUP. The last option means that libgpiod should open the chip\n" -"based on the best guess what the path is. This is also the default if the\n" -"second argument is missing.\n" +"options are: OPEN_BY_NAME, OPEN_BY_NUMBER, OPEN_BY_PATH and OPEN_LOOKUP.\n" +"The last option means that libgpiod should open the chip based on the best\n" +"guess what the path is. This is also the default if the second argument is\n" +"missing.\n" "\n" "Callers must close the chip by calling the close() method when it's no\n" "longer used.\n" @@ -2786,11 +2782,6 @@ static gpiod_ConstDescr gpiod_ConstList[] = { .name = "OPEN_BY_NAME", .val = gpiod_OPEN_BY_NAME, }, - { - .typeobj = &gpiod_ChipType, - .name = "OPEN_BY_LABEL", - .val = gpiod_OPEN_BY_LABEL, - }, { .typeobj = &gpiod_ChipType, .name = "OPEN_BY_NUMBER", diff --git a/bindings/python/tests/gpiod_py_test.py b/bindings/python/tests/gpiod_py_test.py index cb15fdc..e4aaadc 100755 --- a/bindings/python/tests/gpiod_py_test.py +++ b/bindings/python/tests/gpiod_py_test.py @@ -96,10 +96,6 @@ class ChipOpen(MockupTestCase): gpiod.Chip.OPEN_BY_NUMBER) as chip: self.assertEqual(chip.name(), mockup.chip_name(1)) - def test_open_chip_by_label(self): - with gpiod.Chip('gpio-mockup-B', gpiod.Chip.OPEN_BY_LABEL) as chip: - self.assertEqual(chip.name(), mockup.chip_name(1)) - def test_lookup_chip_by_name(self): with gpiod.Chip(mockup.chip_name(1)) as chip: self.assertEqual(chip.name(), mockup.chip_name(1)) @@ -112,10 +108,6 @@ class ChipOpen(MockupTestCase): with gpiod.Chip('{}'.format(mockup.chip_num(1))) as chip: self.assertEqual(chip.name(), mockup.chip_name(1)) - def test_lookup_chip_by_label(self): - with gpiod.Chip('gpio-mockup-B') as chip: - self.assertEqual(chip.name(), mockup.chip_name(1)) - def test_nonexistent_chip(self): with self.assertRaises(FileNotFoundError): chip = gpiod.Chip('nonexistent-chip') diff --git a/include/gpiod.h b/include/gpiod.h index b5965ed..b28cc92 100644 --- a/include/gpiod.h +++ b/include/gpiod.h @@ -103,24 +103,14 @@ struct gpiod_chip *gpiod_chip_open_by_name(const char *name) GPIOD_API; */ struct gpiod_chip *gpiod_chip_open_by_number(unsigned int num) GPIOD_API; -/** - * @brief Open a gpiochip by label. - * @param label Label of the gpiochip to open. - * @return GPIO chip handle or NULL if the chip with given label was not found - * or an error occured. - * @note If the chip cannot be found but no other error occurred, errno is set - * to ENOENT. - */ -struct gpiod_chip *gpiod_chip_open_by_label(const char *label) GPIOD_API; - /** * @brief Open a gpiochip based on the best guess what the path is. * @param descr String describing the gpiochip. * @return GPIO chip handle or NULL if an error occurred. * * This routine tries to figure out whether the user passed it the path to the - * GPIO chip, its name, label or number as a string. Then it tries to open it - * using one of the gpiod_chip_open** variants. + * GPIO chip, its name or number as a string. Then it tries to open it using + * one of the gpiod_chip_open** variants. */ struct gpiod_chip *gpiod_chip_open_lookup(const char *descr) GPIOD_API; diff --git a/lib/helpers.c b/lib/helpers.c index 3b7428b..3ec6c96 100644 --- a/lib/helpers.c +++ b/lib/helpers.c @@ -56,28 +56,6 @@ struct gpiod_chip *gpiod_chip_open_by_number(unsigned int num) return chip; } -struct gpiod_chip *gpiod_chip_open_by_label(const char *label) -{ - struct gpiod_chip_iter *iter; - struct gpiod_chip *chip; - - iter = gpiod_chip_iter_new(); - if (!iter) - return NULL; - - gpiod_foreach_chip(iter, chip) { - if (strcmp(label, gpiod_chip_label(chip)) == 0) { - gpiod_chip_iter_free_noclose(iter); - return chip; - } - } - - errno = ENOENT; - gpiod_chip_iter_free(iter); - - return NULL; -} - struct gpiod_chip *gpiod_chip_open_lookup(const char *descr) { struct gpiod_chip *chip; @@ -85,13 +63,10 @@ struct gpiod_chip *gpiod_chip_open_lookup(const char *descr) if (isuint(descr)) { chip = gpiod_chip_open_by_number(strtoul(descr, NULL, 10)); } else { - chip = gpiod_chip_open_by_label(descr); - if (!chip) { - if (strncmp(descr, "/dev/", 5)) - chip = gpiod_chip_open_by_name(descr); - else - chip = gpiod_chip_open(descr); - } + if (strncmp(descr, "/dev/", 5)) + chip = gpiod_chip_open_by_name(descr); + else + chip = gpiod_chip_open(descr); } return chip; diff --git a/tests/tests-chip.c b/tests/tests-chip.c index 2f19c49..0c2948a 100644 --- a/tests/tests-chip.c +++ b/tests/tests-chip.c @@ -68,28 +68,8 @@ GPIOD_TEST_CASE(open_by_number_good, 0, { 8 }) g_assert_nonnull(chip); } -GPIOD_TEST_CASE(open_by_label_good, 0, { 4, 4, 4, 4, 4 }) -{ - g_autoptr(gpiod_chip_struct) chip = NULL; - - chip = gpiod_chip_open_by_label("gpio-mockup-D"); - g_assert_nonnull(chip); - gpiod_test_return_if_failed(); - g_assert_cmpstr(gpiod_chip_name(chip), ==, gpiod_test_chip_name(3)); -} - -GPIOD_TEST_CASE(open_by_label_bad, 0, { 4, 4, 4, 4, 4 }) -{ - struct gpiod_chip *chip; - - chip = gpiod_chip_open_by_label("nonexistent_gpio_chip"); - g_assert_null(chip); - g_assert_cmpint(errno, ==, ENOENT); -} - GPIOD_TEST_CASE(open_lookup_good, 0, { 8, 8, 8}) { - g_autoptr(gpiod_chip_struct) chip_by_label = NULL; g_autoptr(gpiod_chip_struct) chip_by_name = NULL; g_autoptr(gpiod_chip_struct) chip_by_path = NULL; g_autoptr(gpiod_chip_struct) chip_by_num = NULL; @@ -99,12 +79,10 @@ GPIOD_TEST_CASE(open_lookup_good, 0, { 8, 8, 8}) chip_by_name = gpiod_chip_open_lookup(gpiod_test_chip_name(1)); chip_by_path = gpiod_chip_open_lookup(gpiod_test_chip_path(1)); chip_by_num = gpiod_chip_open_lookup(chip_num_str); - chip_by_label = gpiod_chip_open_lookup("gpio-mockup-B"); g_assert_nonnull(chip_by_name); g_assert_nonnull(chip_by_path); g_assert_nonnull(chip_by_num); - g_assert_nonnull(chip_by_label); gpiod_test_return_if_failed(); g_assert_cmpstr(gpiod_chip_name(chip_by_name), @@ -113,8 +91,6 @@ GPIOD_TEST_CASE(open_lookup_good, 0, { 8, 8, 8}) ==, gpiod_test_chip_name(1)); g_assert_cmpstr(gpiod_chip_name(chip_by_num), ==, gpiod_test_chip_name(1)); - g_assert_cmpstr(gpiod_chip_name(chip_by_label), - ==, gpiod_test_chip_name(1)); } GPIOD_TEST_CASE(get_name, 0, { 8, 8, 8}) From patchwork Thu Dec 10 13:23:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 341375 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 267C3C4167B for ; Thu, 10 Dec 2020 13:24:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D419822E01 for ; Thu, 10 Dec 2020 13:24:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389202AbgLJNYy (ORCPT ); Thu, 10 Dec 2020 08:24:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50592 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389114AbgLJNYp (ORCPT ); Thu, 10 Dec 2020 08:24:45 -0500 Received: from mail-wr1-x441.google.com (mail-wr1-x441.google.com [IPv6:2a00:1450:4864:20::441]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2282BC061285 for ; Thu, 10 Dec 2020 05:23:35 -0800 (PST) Received: by mail-wr1-x441.google.com with SMTP id k14so5481237wrn.1 for ; Thu, 10 Dec 2020 05:23:35 -0800 (PST) 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=Lb5AeKppZ+OB7xrPFrogKVvDyFShpykJR5gK9BWPsIA=; b=Onagba7v55bps3OjXuqlR7+cc5q8MMO8FizbeGjjN3zf9rGoo/+HJ4LNOlzVtjXP/g ia5ffNwtC9SKIIkHv5bLFS+1lq8B5mqKu05D+cNzcVlxB3ti1CQqDkTWBjX8opmAiJvy uea2P3dSBOIVTYgugdFn3Fd3JM8dWuv8vQDXaIkLHR4E5QWwgQQPuCF6+VjkcKHFxO96 ln/MUDwSuYqazk9rPMPbQLI2POsPK5CLHJE++IkA2KBMq3B2FU41a7dumKYMb5i2cpb8 4tvgFU2Wg0N6Ox9+SARESH+UZc0WxrItEA6DjMMlxZAMzriqMk05E6ugnJOKb5mpZ/LY 2WMw== 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=Lb5AeKppZ+OB7xrPFrogKVvDyFShpykJR5gK9BWPsIA=; b=tnFgjMpm7WiviSCCPT7DC24/syBrysm8gM+T8mBXRrmEx9X4j8slfDKdN7Jt4wXykk NCVXIklz1qaq9h4ACVGG176IM4soHyZ/q55tkYVp1DsUPI9IHZ6bu3cN15VkRu7Wa0La k3qBJfeSpJgEBu1VVjKLNE7q5+B2vYXj5Pohy3KLAJjgSwEENhRaqPRh2VfrWDzuea4X c69GijsuRjSxfctNeL4H9HqJ1wbiJ0oTGujlxNdIG1iUdzDF1ppNdJawBNE3ynIos7Fm Baf29o4mpLOxzhgoK5jxySA79EXOdamXtwqSXWM72UDFagwTRdtFvm/A7WS0gg/+xXwa HRGA== X-Gm-Message-State: AOAM532T+Nx3BaibOcpVmiykuuifI9p/2Aqt82fv7XI33MJuLwdqceal zz9m22tToPlOPChG+IqXwYBJRQ== X-Google-Smtp-Source: ABdhPJxOsr/utKoy9h93eFeuVCOF2TXEzehSwBLBl/oNqBuu1WVIiQ72Q63cA/LtnOFIuoKvM2ae/Q== X-Received: by 2002:a5d:4209:: with SMTP id n9mr8103818wrq.128.1607606613943; Thu, 10 Dec 2020 05:23:33 -0800 (PST) Received: from localhost.localdomain (lfbn-nic-1-190-206.w2-15.abo.wanadoo.fr. [2.15.39.206]) by smtp.gmail.com with ESMTPSA id n14sm9444811wmi.1.2020.12.10.05.23.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 05:23:33 -0800 (PST) From: Bartosz Golaszewski To: Kent Gibson , Andy Shevchenko , Geert Uytterhoeven , Jack Winch , Helmut Grohne , Linus Walleij Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 09/14] core: kill gpiod_line_get() Date: Thu, 10 Dec 2020 14:23:10 +0100 Message-Id: <20201210132315.5785-10-brgl@bgdev.pl> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201210132315.5785-1-brgl@bgdev.pl> References: <20201210132315.5785-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Bartosz Golaszewski We're dropping all interfaces for global line lookup and accessing. Lines should be always accessed via their owning chip object. Signed-off-by: Bartosz Golaszewski --- include/gpiod.h | 15 --------------- lib/helpers.c | 18 ------------------ tests/tests-line.c | 21 --------------------- 3 files changed, 54 deletions(-) diff --git a/include/gpiod.h b/include/gpiod.h index 2e8323a..c1113bf 100644 --- a/include/gpiod.h +++ b/include/gpiod.h @@ -1062,21 +1062,6 @@ int gpiod_line_event_read_fd_multiple(int fd, struct gpiod_line_event *events, * Functions that didn't fit anywhere else. */ -/** - * @brief Get a GPIO line handle by GPIO chip description and offset. - * @param device String describing the gpiochip. - * @param offset The offset of the GPIO line. - * @return GPIO line handle or NULL if an error occurred. - * - * This routine provides a shorter alternative to calling - * ::gpiod_chip_open_lookup and ::gpiod_chip_get_line. - * - * If this function succeeds, the caller is responsible for closing the - * associated GPIO chip. - */ -struct gpiod_line * -gpiod_line_get(const char *device, unsigned int offset) GPIOD_API; - /** * @brief Find a GPIO line by its name. * @param name Name of the GPIO line. diff --git a/lib/helpers.c b/lib/helpers.c index b3050ca..2063c3f 100644 --- a/lib/helpers.c +++ b/lib/helpers.c @@ -378,24 +378,6 @@ int gpiod_line_request_bulk_both_edges_events_flags( GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES); } -struct gpiod_line *gpiod_line_get(const char *device, unsigned int offset) -{ - struct gpiod_chip *chip; - struct gpiod_line *line; - - chip = gpiod_chip_open_lookup(device); - if (!chip) - return NULL; - - line = gpiod_chip_get_line(chip, offset); - if (!line) { - gpiod_chip_close(chip); - return NULL; - } - - return line; -} - struct gpiod_line *gpiod_line_find(const char *name) { struct gpiod_chip_iter *iter; diff --git a/tests/tests-line.c b/tests/tests-line.c index 4bb5f0f..235df0f 100644 --- a/tests/tests-line.c +++ b/tests/tests-line.c @@ -716,27 +716,6 @@ GPIOD_TEST_CASE(output_value_caching, 0, { 8 }) g_assert_cmpint(gpiod_test_chip_get_value(0, 2), ==, 0); } -GPIOD_TEST_CASE(get_line_helper, 0, { 16, 16, 32, 16 }) -{ - g_autoptr(gpiod_chip_struct) chip = NULL; - struct gpiod_line *line; - - line = gpiod_line_get(gpiod_test_chip_name(2), 18); - g_assert_nonnull(line); - gpiod_test_return_if_failed(); - chip = gpiod_line_get_chip(line); - g_assert_cmpint(gpiod_line_offset(line), ==, 18); -} - -GPIOD_TEST_CASE(get_line_helper_invalid_offset, 0, { 16, 16, 32, 16 }) -{ - struct gpiod_line *line; - - line = gpiod_line_get(gpiod_test_chip_name(3), 18); - g_assert_null(line); - g_assert_cmpint(errno, ==, EINVAL); -} - GPIOD_TEST_CASE(find_good, GPIOD_TEST_FLAG_NAMED_LINES, { 16, 16, 32, 16 }) { g_autoptr(gpiod_chip_struct) chip = NULL; From patchwork Thu Dec 10 13:23:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 341376 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.8 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, 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 899AAC433FE for ; Thu, 10 Dec 2020 13:24:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 363D320780 for ; Thu, 10 Dec 2020 13:24:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732921AbgLJNYl (ORCPT ); Thu, 10 Dec 2020 08:24:41 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50492 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389204AbgLJNY0 (ORCPT ); Thu, 10 Dec 2020 08:24:26 -0500 Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6C293C0611CA for ; Thu, 10 Dec 2020 05:23:38 -0800 (PST) Received: by mail-wr1-x42e.google.com with SMTP id c5so1838357wrp.6 for ; Thu, 10 Dec 2020 05:23:38 -0800 (PST) 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=VpRsQjpStu4l6nV3G4ZMof8VlEvMdxIOr8Ajegvbtvg=; b=vDfX7deGunILG+8qKkgrD52Tw4fUaV2pvWi54/HdsZsKzYzZVetz5T5OM3rjg0H8At 6BWIYRHu3KCBNS4MVVld2FB6n9USH1oGWgsWPaDiJKY1W9eh2Y7vodIN4upv+4a0tuZo DoEA7R5C11y/AwX9nXkp+Se2msDKN3jDBbgyarxYhhqNPwzZyA4Fx5Cl7jD+5UekFBGT OCDeqfmW46NZOsfPs/6LsdaJPIOf5xe5qSkAkclXK6g9P3dWQ+GsPpYbMZDEqmM0sJh/ nfxzkV6DsWTWfb+BQdHrYgVJWpQ9JeyEJtj875to0B9P2PJndQdQpWIHLcocRt6zveMy PRMA== 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=VpRsQjpStu4l6nV3G4ZMof8VlEvMdxIOr8Ajegvbtvg=; b=fvK1JRZ86gTXsfkXokm64LcVRyMgW3z4Cd0tdy6TsY/7gUzAIxprCKeL/QgjPcN+b6 hrgbPvlEkV08OmF9WfB6RkJ+QJJxp6TIQI+rilCu8bq2TPIUc4Au41DWgf42FnLojCLM nDBNYljvBFiHNwn6cwTC2u8jZtmH1Vnb/ljO/F97TBHhmvN5/SjXACaUIIO1HjFeX0Lo kDMZ9TEK6VaAAvs4NQjRMokaY8qm/wCS8dPjj4uMOhFMZwhYBDU6lWRcTER8GDYWGSSi nx4pw+foc0tFgWHz7cpUpcUff+7BYbmSaWHwlVg53dNeYyTKkuD5CUS/VSdXX4TG5jtU jZOQ== X-Gm-Message-State: AOAM533wfFOP8A9r+yubfhlCvBzfz0bjp9UEBfon20SxFyvzT6p7ZlYQ SAw/mLvu5VIYXLY/0hi4pnReOA== X-Google-Smtp-Source: ABdhPJzbeKZxev3MLCZTkeVR2iPpbJJ7P2Q5caSMxHfHjQSGnLjKQggw+o/03gx5hIRZyx6He3iozQ== X-Received: by 2002:a5d:60c1:: with SMTP id x1mr3071839wrt.271.1607606617047; Thu, 10 Dec 2020 05:23:37 -0800 (PST) Received: from localhost.localdomain (lfbn-nic-1-190-206.w2-15.abo.wanadoo.fr. [2.15.39.206]) by smtp.gmail.com with ESMTPSA id n14sm9444811wmi.1.2020.12.10.05.23.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 05:23:36 -0800 (PST) From: Bartosz Golaszewski To: Kent Gibson , Andy Shevchenko , Geert Uytterhoeven , Jack Winch , Helmut Grohne , Linus Walleij Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 12/14] core: rework gpiod_chip_find_line() Date: Thu, 10 Dec 2020 14:23:13 +0100 Message-Id: <20201210132315.5785-13-brgl@bgdev.pl> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201210132315.5785-1-brgl@bgdev.pl> References: <20201210132315.5785-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Bartosz Golaszewski GPIO line names are not unique and the library has been incorrectly making such assumption in v1.x series. We've already dropped interfaces that would be too complicated to maintain when taking this into account. Let's now rework the remaming API. This introduces a new function to the C API: gpiod_chip_find_line_unique() which assumes that the line name is unique and signals an error if it's not. The previous gpiod_chip_find_line() function now returns a bulk object containing all matching lines. Python and C++ bindings are updated: their find_line() functions return bulk objects (or an ::std::vector> too now and they take an additional argument specifying whether we're looking for a unique line or not. Signed-off-by: Bartosz Golaszewski --- bindings/cxx/chip.cpp | 18 ++- bindings/cxx/examples/gpiofindcxx.cpp | 6 +- bindings/cxx/gpiod.hpp | 10 +- bindings/cxx/tests/tests-chip.cpp | 4 +- bindings/python/gpiodmodule.c | 150 ++++++++++++++----------- bindings/python/tests/gpiod_py_test.py | 9 +- include/gpiod.h | 28 +++-- lib/helpers.c | 57 +++++++++- tests/tests-chip.c | 9 +- tools/gpiofind.c | 2 +- 10 files changed, 193 insertions(+), 100 deletions(-) diff --git a/bindings/cxx/chip.cpp b/bindings/cxx/chip.cpp index ff35e53..82ba559 100644 --- a/bindings/cxx/chip.cpp +++ b/bindings/cxx/chip.cpp @@ -122,16 +122,22 @@ line chip::get_line(unsigned int offset) const return line(line_handle, *this); } -line chip::find_line(const ::std::string& name) const +::std::vector chip::find_line(const ::std::string& name, bool unique) const { this->throw_if_noref(); - ::gpiod_line* handle = ::gpiod_chip_find_line(this->_m_chip.get(), name.c_str()); - if (!handle && errno != ENOENT) - throw ::std::system_error(errno, ::std::system_category(), - "error looking up GPIO line by name"); + ::std::vector lines; + + for (auto& line: ::gpiod::line_iter(*this)) { + if (line.name() == name) + lines.push_back(line); + } - return handle ? line(handle, *this) : line(); + if (unique && lines.size() > 1) + throw ::std::system_error(ERANGE, ::std::system_category(), + "multiple lines with the same name found"); + + return lines; } line_bulk chip::get_lines(const ::std::vector& offsets) const diff --git a/bindings/cxx/examples/gpiofindcxx.cpp b/bindings/cxx/examples/gpiofindcxx.cpp index e9ab64a..c817378 100644 --- a/bindings/cxx/examples/gpiofindcxx.cpp +++ b/bindings/cxx/examples/gpiofindcxx.cpp @@ -20,9 +20,9 @@ int main(int argc, char **argv) } for (auto& chip: ::gpiod::make_chip_iter()) { - auto line = chip.find_line(argv[1]); - if (line) { - ::std::cout << line.name() << " " << line.offset() << ::std::endl; + auto lines = chip.find_line(argv[1], true); + if (!lines.empty()) { + ::std::cout << lines.front().name() << " " << lines.front().offset() << ::std::endl; return EXIT_SUCCESS; } } diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp index a16a27c..9d081fe 100644 --- a/bindings/cxx/gpiod.hpp +++ b/bindings/cxx/gpiod.hpp @@ -127,11 +127,15 @@ public: GPIOD_API line get_line(unsigned int offset) const; /** - * @brief Get the line exposed by this chip by name. + * @brief Find all GPIO lines by name among lines exposed by this GPIO + * chip. * @param name Line name. - * @return Line object. + * @param unique If set to true: throw an error if multiple lines match + * the name. + * @return Vector of all matching lines. */ - GPIOD_API line find_line(const ::std::string& name) const; + GPIOD_API ::std::vector find_line(const ::std::string& name, + bool unique = false) const; /** * @brief Get a set of lines exposed by this chip at given offsets. diff --git a/bindings/cxx/tests/tests-chip.cpp b/bindings/cxx/tests/tests-chip.cpp index 90ebc1b..c45f2df 100644 --- a/bindings/cxx/tests/tests-chip.cpp +++ b/bindings/cxx/tests/tests-chip.cpp @@ -168,7 +168,7 @@ TEST_CASE("Lines can be retrieved from chip objects", "[chip]") SECTION("find single line by name") { - auto line = chip.find_line("gpio-mockup-B-3"); + auto line = chip.find_line("gpio-mockup-B-3", true).front(); REQUIRE(line.offset() == 3); } @@ -223,6 +223,6 @@ TEST_CASE("Errors occurring when retrieving lines are correctly reported", "[chi SECTION("line not found by name") { - REQUIRE_FALSE(chip.find_line("nonexistent-line")); + REQUIRE(chip.find_line("nonexistent-line").empty()); } } diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c index 4948d5d..d183e6f 100644 --- a/bindings/python/gpiodmodule.c +++ b/bindings/python/gpiodmodule.c @@ -2148,61 +2148,115 @@ gpiod_Chip_get_line(gpiod_ChipObject *self, PyObject *args) return gpiod_MakeLineObject(self, line); } +static gpiod_LineBulkObject *gpiod_ListToLineBulk(PyObject *lines) +{ + gpiod_LineBulkObject *bulk; + PyObject *arg; + + arg = PyTuple_Pack(1, lines); + if (!arg) + return NULL; + + bulk = (gpiod_LineBulkObject *)PyObject_CallObject( + (PyObject *)&gpiod_LineBulkType, + arg); + Py_DECREF(arg); + + return bulk; +} + +static gpiod_LineBulkObject * +gpiod_LineBulkObjectFromBulk(gpiod_ChipObject *chip, struct gpiod_line_bulk *bulk) +{ + gpiod_LineBulkObject *bulk_obj; + gpiod_LineObject *line_obj; + struct gpiod_line *line; + unsigned int idx; + PyObject *list; + int rv; + + list = PyList_New(gpiod_line_bulk_num_lines(bulk)); + if (!list) + return NULL; + + for (idx = 0; idx < gpiod_line_bulk_num_lines(bulk); idx++) { + line = gpiod_line_bulk_get_line(bulk, idx); + line_obj = gpiod_MakeLineObject(chip, line); + if (!line_obj) { + Py_DECREF(list); + return NULL; + } + + rv = PyList_SetItem(list, idx, (PyObject *)line_obj); + if (rv < 0) { + Py_DECREF(line_obj); + Py_DECREF(list); + return NULL; + } + } + + bulk_obj = gpiod_ListToLineBulk(list); + Py_DECREF(list); + if (!bulk_obj) + return NULL; + + return bulk_obj; +} + PyDoc_STRVAR(gpiod_Chip_find_line_doc, -"find_line(name) -> gpiod.Line object or None\n" +"find_line(name) -> gpiod.LineBulk object or None\n" "\n" -"Get the GPIO line by name.\n" +"Find all GPIO lines by name among lines exposed by this GPIO chip..\n" "\n" " name\n" " Line name (string)\n" +" unique\n" +" Indicates whether an exception should be raised if more than one lines\n" +" matches the name\n" "\n" -"Returns a gpiod.Line object or None if line with given name is not\n" -"associated with this chip."); +"Returns a gpiod.LineBulk object containing all matching lines or None if\n" +"line with given name is not associated with this chip."); -static gpiod_LineObject * -gpiod_Chip_find_line(gpiod_ChipObject *self, PyObject *args) +static gpiod_LineBulkObject * +gpiod_Chip_find_line(gpiod_ChipObject *self, PyObject *args, PyObject *kwds) { - struct gpiod_line *line; + static char *kwlist[] = { "unique", NULL }; + + gpiod_LineBulkObject *bulk_obj; + struct gpiod_line_bulk *bulk; + int rv, unique = 0; const char *name; - int rv; if (gpiod_ChipIsClosed(self)) return NULL; - rv = PyArg_ParseTuple(args, "s", &name); + rv = PyArg_ParseTupleAndKeywords(args, kwds, "s|p", + kwlist, &name, &unique); if (!rv) return NULL; Py_BEGIN_ALLOW_THREADS; - line = gpiod_chip_find_line(self->chip, name); + bulk = gpiod_chip_find_line(self->chip, name); Py_END_ALLOW_THREADS; - if (!line) { + if (!bulk) { if (errno == ENOENT) { Py_INCREF(Py_None); - return (gpiod_LineObject *)Py_None; + return (gpiod_LineBulkObject *)Py_None; } - return (gpiod_LineObject *)PyErr_SetFromErrno(PyExc_OSError); + return (gpiod_LineBulkObject *)PyErr_SetFromErrno( + PyExc_OSError); } - return gpiod_MakeLineObject(self, line); -} - -static gpiod_LineBulkObject *gpiod_ListToLineBulk(PyObject *lines) -{ - gpiod_LineBulkObject *bulk; - PyObject *arg; - - arg = PyTuple_Pack(1, lines); - if (!arg) + if (unique && gpiod_line_bulk_num_lines(bulk) > 1) { + gpiod_line_bulk_free(bulk); + PyErr_SetString(PyExc_RuntimeError, "line not unique"); return NULL; + } - bulk = (gpiod_LineBulkObject *)PyObject_CallObject( - (PyObject *)&gpiod_LineBulkType, - arg); - Py_DECREF(arg); - - return bulk; + bulk_obj = gpiod_LineBulkObjectFromBulk(self, bulk); + gpiod_line_bulk_free(bulk); + return bulk_obj; } PyDoc_STRVAR(gpiod_Chip_get_lines_doc, @@ -2293,10 +2347,6 @@ gpiod_Chip_get_all_lines(gpiod_ChipObject *self, PyObject *Py_UNUSED(ignored)) { gpiod_LineBulkObject *bulk_obj; struct gpiod_line_bulk *bulk; - gpiod_LineObject *line_obj; - unsigned int idx; - PyObject *list; - int rv; if (gpiod_ChipIsClosed(self)) return NULL; @@ -2306,36 +2356,8 @@ gpiod_Chip_get_all_lines(gpiod_ChipObject *self, PyObject *Py_UNUSED(ignored)) return (gpiod_LineBulkObject *)PyErr_SetFromErrno( PyExc_OSError); - list = PyList_New(gpiod_line_bulk_num_lines(bulk)); - if (!list) { - gpiod_line_bulk_free(bulk); - return NULL; - } - - for (idx = 0; idx < gpiod_line_bulk_num_lines(bulk); idx++) { - line_obj = gpiod_MakeLineObject(self, gpiod_line_bulk_get_line(bulk, idx)); - if (!line_obj) { - gpiod_line_bulk_free(bulk); - Py_DECREF(list); - return NULL; - } - - rv = PyList_SetItem(list, idx, (PyObject *)line_obj); - if (rv < 0) { - gpiod_line_bulk_free(bulk); - Py_DECREF(line_obj); - Py_DECREF(list); - return NULL; - } - } - + bulk_obj = gpiod_LineBulkObjectFromBulk(self, bulk); gpiod_line_bulk_free(bulk); - - bulk_obj = gpiod_ListToLineBulk(list); - Py_DECREF(list); - if (!bulk_obj) - return NULL; - return bulk_obj; } @@ -2384,8 +2406,8 @@ static PyMethodDef gpiod_Chip_methods[] = { }, { .ml_name = "find_line", - .ml_meth = (PyCFunction)gpiod_Chip_find_line, - .ml_flags = METH_VARARGS, + .ml_meth = (PyCFunction)(void (*)(void))gpiod_Chip_find_line, + .ml_flags = METH_VARARGS | METH_KEYWORDS, .ml_doc = gpiod_Chip_find_line_doc, }, { diff --git a/bindings/python/tests/gpiod_py_test.py b/bindings/python/tests/gpiod_py_test.py index 6ee72a9..c490933 100755 --- a/bindings/python/tests/gpiod_py_test.py +++ b/bindings/python/tests/gpiod_py_test.py @@ -149,8 +149,9 @@ class ChipGetLines(MockupTestCase): def test_find_single_line_by_name(self): with gpiod.Chip(mockup.chip_name(1)) as chip: - line = chip.find_line('gpio-mockup-B-4') - self.assertEqual(line.offset(), 4) + lines = chip.find_line('gpio-mockup-B-4').to_list() + self.assertEqual(len(lines), 1) + self.assertEqual(lines[0].offset(), 4) def test_get_single_line_invalid_offset(self): with gpiod.Chip(mockup.chip_name(1)) as chip: @@ -161,8 +162,8 @@ class ChipGetLines(MockupTestCase): def test_find_single_line_nonexistent(self): with gpiod.Chip(mockup.chip_name(1)) as chip: - line = chip.find_line('nonexistent-line') - self.assertEqual(line, None) + lines = chip.find_line('nonexistent-line') + self.assertEqual(lines, None) def test_get_multiple_lines_by_offsets_in_tuple(self): with gpiod.Chip(mockup.chip_name(1)) as chip: diff --git a/include/gpiod.h b/include/gpiod.h index 34313ed..fc50fe8 100644 --- a/include/gpiod.h +++ b/include/gpiod.h @@ -170,19 +170,31 @@ struct gpiod_line_bulk * gpiod_chip_get_all_lines(struct gpiod_chip *chip) GPIOD_API; /** - * @brief Find a GPIO line by name among lines associated with given GPIO chip. + * @brief Find all GPIO lines by name among lines exposed by this GPIO chip. * @param chip The GPIO chip object. - * @param name The name of the GPIO line. + * @param name GPIO line name to look for. + * @return New line bulk object containing all matching lines or NULL on error. + * + * If no line with given name is associated with this chip, the function sets + * errno to ENOENT. + */ +struct gpiod_line_bulk * +gpiod_chip_find_line(struct gpiod_chip *chip, const char *name) GPIOD_API; + +/** + * @brief Find a unique line by name among lines exposed by this GPIO chip. + * @param chip The GPIO chip object. + * @param name Name of the GPIO line. * @return Pointer to the GPIO line handle or NULL if the line could not be * found or an error occurred. - * @note In case a line with given name is not associated with given chip, the - * function sets errno to ENOENT. - * @attention GPIO line names are not unique in the linux kernel, neither - * globally nor within a single chip. This function finds the first - * line with given name. + * + * If no line with given name is associated with this chip, the function sets + * errno to ENOENT. If more than one line with given name is associated with + * this chip, the function sets errno to ERANGE. */ struct gpiod_line * -gpiod_chip_find_line(struct gpiod_chip *chip, const char *name) GPIOD_API; +gpiod_chip_find_line_unique(struct gpiod_chip *chip, + const char *name) GPIOD_API; /** * @} diff --git a/lib/helpers.c b/lib/helpers.c index 509a1c8..ec2575d 100644 --- a/lib/helpers.c +++ b/lib/helpers.c @@ -120,11 +120,48 @@ struct gpiod_line_bulk *gpiod_chip_get_all_lines(struct gpiod_chip *chip) return bulk; } -struct gpiod_line * +struct gpiod_line_bulk * gpiod_chip_find_line(struct gpiod_chip *chip, const char *name) { + struct gpiod_line_bulk *bulk = NULL; + unsigned int offset, num_lines; struct gpiod_line *line; - unsigned int offset; + const char *tmp; + + num_lines = gpiod_chip_num_lines(chip); + + for (offset = 0; offset < num_lines; offset++) { + line = gpiod_chip_get_line(chip, offset); + if (!line) { + if (bulk) + gpiod_line_bulk_free(bulk); + + return NULL; + } + + tmp = gpiod_line_name(line); + if (tmp && strcmp(tmp, name) == 0) { + if (!bulk) { + bulk = gpiod_line_bulk_new(num_lines); + if (!bulk) + return NULL; + } + + gpiod_line_bulk_add_line(bulk, line); + } + } + + if (!bulk) + errno = ENOENT; + + return bulk; +} + +struct gpiod_line * +gpiod_chip_find_line_unique(struct gpiod_chip *chip, const char *name) +{ + struct gpiod_line *line, *matching = NULL; + unsigned int offset, num_found = 0; const char *tmp; for (offset = 0; offset < gpiod_chip_num_lines(chip); offset++) { @@ -133,12 +170,22 @@ gpiod_chip_find_line(struct gpiod_chip *chip, const char *name) return NULL; tmp = gpiod_line_name(line); - if (tmp && strcmp(tmp, name) == 0) - return line; + if (tmp && strcmp(tmp, name) == 0) { + matching = line; + num_found++; + } } - errno = ENOENT; + if (matching) { + if (num_found > 1) { + errno = ERANGE; + return NULL; + } + return matching; + } + + errno = ENOENT; return NULL; } diff --git a/tests/tests-chip.c b/tests/tests-chip.c index 543c103..1c365b9 100644 --- a/tests/tests-chip.c +++ b/tests/tests-chip.c @@ -235,7 +235,7 @@ GPIOD_TEST_CASE(get_all_lines, 0, { 4 }) g_assert_cmpuint(gpiod_line_offset(line3), ==, 3); } -GPIOD_TEST_CASE(find_line_good, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) +GPIOD_TEST_CASE(find_line_good_unique, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; @@ -244,14 +244,15 @@ GPIOD_TEST_CASE(find_line_good, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) g_assert_nonnull(chip); gpiod_test_return_if_failed(); - line = gpiod_chip_find_line(chip, "gpio-mockup-B-4"); + line = gpiod_chip_find_line_unique(chip, "gpio-mockup-B-4"); g_assert_nonnull(line); gpiod_test_return_if_failed(); g_assert_cmpuint(gpiod_line_offset(line), ==, 4); g_assert_cmpstr(gpiod_line_name(line), ==, "gpio-mockup-B-4"); } -GPIOD_TEST_CASE(find_line_not_found, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) +GPIOD_TEST_CASE(find_line_unique_not_found, + GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) { g_autoptr(gpiod_chip_struct) chip = NULL; struct gpiod_line *line; @@ -260,7 +261,7 @@ GPIOD_TEST_CASE(find_line_not_found, GPIOD_TEST_FLAG_NAMED_LINES, { 8, 8, 8 }) g_assert_nonnull(chip); gpiod_test_return_if_failed(); - line = gpiod_chip_find_line(chip, "nonexistent"); + line = gpiod_chip_find_line_unique(chip, "nonexistent"); g_assert_null(line); g_assert_cmpint(errno, ==, ENOENT); } diff --git a/tools/gpiofind.c b/tools/gpiofind.c index 489cf33..ffb8fc0 100644 --- a/tools/gpiofind.c +++ b/tools/gpiofind.c @@ -69,7 +69,7 @@ int main(int argc, char **argv) die_perror("unable to access GPIO chips"); gpiod_foreach_chip(iter, chip) { - line = gpiod_chip_find_line(chip, argv[0]); + line = gpiod_chip_find_line_unique(chip, argv[0]); if (line) { printf("%s %u\n", gpiod_chip_name(chip), gpiod_line_offset(line)); From patchwork Thu Dec 10 13:23:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 341378 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 4E582C433FE for ; Thu, 10 Dec 2020 13:24:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 032D220769 for ; Thu, 10 Dec 2020 13:24:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389219AbgLJNYe (ORCPT ); Thu, 10 Dec 2020 08:24:34 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50494 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389209AbgLJNY0 (ORCPT ); Thu, 10 Dec 2020 08:24:26 -0500 Received: from mail-wr1-x443.google.com (mail-wr1-x443.google.com [IPv6:2a00:1450:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4B4BFC0611CB for ; Thu, 10 Dec 2020 05:23:39 -0800 (PST) Received: by mail-wr1-x443.google.com with SMTP id i9so5469839wrc.4 for ; Thu, 10 Dec 2020 05:23:39 -0800 (PST) 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=op6go9cA91PDGEg+5OPc9LgcgqX87Gp5iVITUw7CtWM=; b=YS90i0zivAxEEThilPHY58uUAH++x2RX09e3hlIvTCswoG0/uKS4sJUpEOdzO1Rz8l PfxANagkotqXjUxUTXzehhdRaV+5/6QDq3NvaF7EvHztbutYNM//8gPGGt865iiV1MKj OD5zgyOEtL/bQClxFXP8m1ccUw0BS5JoWHs3ozgAAXQGEky8QWiItRCIjIEqoHrCe0Aa eZCypS0+8R2IniEBNwW5aDO96Rm5FtrAU7DISvFzesulYKFHAi9HN6PQjpfU+fKPlx+j SVOwHqfOieutCjbmx7c0NzLUfLxWCyovVRbL7Bwn26ih6VcJ4Cu7GLbASWKPzkBOpXsC G1eA== 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=op6go9cA91PDGEg+5OPc9LgcgqX87Gp5iVITUw7CtWM=; b=Dd8YjpNrkfl+nsugBpmEEy0KLeUZNRqWEmeIYcUdveIJH7cmHM+tTh47pl+5w/mekX 5u29mUORzH5GAr25ujNX1g1DtlUkp3cfvSkSrMp6V8ELzFvvj4Kx1mjnkFCYs+ANnFsS tuUqchfnOXsqxUoR1CTvUFbY82PzwfDjzaPt/yyoiVIkIy5lPOAChuHi3SvW5eJGCilr mzxP10Rz47VHsJMyVyeKvklVAlyY6zrpnmKtKhfA8UQTfIf7KjNk2BDTgXVLcaEfTpIB SAwjYPog0v09XC0NlsO2pswwthw2PfJoSeUYMhI7cwwCO86vEwUzzqSQ4C0KA7Ztxt+g Sm6A== X-Gm-Message-State: AOAM533t492SXCAfCZUMJ52/Tz30Lh30iaN3nIHwB5qLOlrVV5wlzTwn 5ryt8ghXGl1m228OHw9kljVvlw== X-Google-Smtp-Source: ABdhPJz4OYhIX+gjyAgF87McvTEqFv3Mwzf6HS5Dg8YrJ5HF3rd/uAlECOo0N+6iOYPxrAFlDF8oAQ== X-Received: by 2002:a5d:548b:: with SMTP id h11mr8292444wrv.306.1607606618114; Thu, 10 Dec 2020 05:23:38 -0800 (PST) Received: from localhost.localdomain (lfbn-nic-1-190-206.w2-15.abo.wanadoo.fr. [2.15.39.206]) by smtp.gmail.com with ESMTPSA id n14sm9444811wmi.1.2020.12.10.05.23.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 05:23:37 -0800 (PST) From: Bartosz Golaszewski To: Kent Gibson , Andy Shevchenko , Geert Uytterhoeven , Jack Winch , Helmut Grohne , Linus Walleij Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 13/14] build: add a configure switch for building examples Date: Thu, 10 Dec 2020 14:23:14 +0100 Message-Id: <20201210132315.5785-14-brgl@bgdev.pl> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201210132315.5785-1-brgl@bgdev.pl> References: <20201210132315.5785-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Bartosz Golaszewski Example code for bindings is currently always built if bindings are enabled. Make it conditional with a new configure switch. Signed-off-by: Bartosz Golaszewski --- bindings/cxx/Makefile.am | 8 +++++++- bindings/python/Makefile.am | 10 ++++++++-- configure.ac | 6 ++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/bindings/cxx/Makefile.am b/bindings/cxx/Makefile.am index 5c40ceb..87463b0 100644 --- a/bindings/cxx/Makefile.am +++ b/bindings/cxx/Makefile.am @@ -18,10 +18,16 @@ include_HEADERS = gpiod.hpp pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libgpiodcxx.pc -SUBDIRS = . examples +SUBDIRS = . if WITH_TESTS SUBDIRS += tests endif + +if WITH_EXAMPLES + +SUBDIRS += examples + +endif diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am index 124f152..5403bcb 100644 --- a/bindings/python/Makefile.am +++ b/bindings/python/Makefile.am @@ -6,8 +6,6 @@ # Copyright (C) 2017-2018 Bartosz Golaszewski # -SUBDIRS = . examples - pyexec_LTLIBRARIES = gpiod.la gpiod_la_SOURCES = gpiodmodule.c @@ -17,8 +15,16 @@ gpiod_la_CFLAGS += -Wall -Wextra -g -std=gnu89 $(PYTHON_CPPFLAGS) gpiod_la_LDFLAGS = -module -avoid-version gpiod_la_LIBADD = $(top_builddir)/lib/libgpiod.la $(PYTHON_LIBS) +SUBDIRS = . + if WITH_TESTS SUBDIRS += tests endif + +if WITH_EXAMPLES + +SUBDIRS += examples + +endif diff --git a/configure.ac b/configure.ac index 57c99a8..90a6324 100644 --- a/configure.ac +++ b/configure.ac @@ -155,6 +155,12 @@ then fi fi +AC_ARG_ENABLE([examples], + [AS_HELP_STRING([--enable-examples], [enable building code examples[default=no]])], + [if test "x$enableval" = xyes; then with_examples=true; fi], + [with_examples=false]) +AM_CONDITIONAL([WITH_EXAMPLES], [test "x$with_examples" = xtrue]) + AC_ARG_ENABLE([bindings-cxx], [AS_HELP_STRING([--enable-bindings-cxx],[enable C++ bindings [default=no]])], [if test "x$enableval" = xyes; then with_bindings_cxx=true; fi], From patchwork Thu Dec 10 13:23:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bartosz Golaszewski X-Patchwork-Id: 341374 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 559E9C1B0D9 for ; Thu, 10 Dec 2020 13:24:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0AE6623105 for ; Thu, 10 Dec 2020 13:24:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389114AbgLJNYy (ORCPT ); Thu, 10 Dec 2020 08:24:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50610 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389204AbgLJNYv (ORCPT ); Thu, 10 Dec 2020 08:24:51 -0500 Received: from mail-wr1-x429.google.com (mail-wr1-x429.google.com [IPv6:2a00:1450:4864:20::429]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DECB2C0611CC for ; Thu, 10 Dec 2020 05:23:40 -0800 (PST) Received: by mail-wr1-x429.google.com with SMTP id l9so5439658wrt.13 for ; Thu, 10 Dec 2020 05:23:40 -0800 (PST) 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=4BSYnwiIQ7CT0Z5pJ2mXNb8eQMvY9YaXHEnPXL6O4cs=; b=hdIdg1LvSnn5BlwPRzn2fBgFbP7OFcV4C9u8Z933dnpCtGrBZatlW9Qb/F0ywGMdhl Q/NLn5f6MgtH+A31fYmBgM2dpam03vzPd3Bza+IYInO+7a+Br6YLrAxc/yCqfSc/UOBo u6i78yrZhNbgIX539HsR+Sl1164P7ysCECcuYIV1Nkk6GIBTjHL3uenYmpDQekBjU0tB YBgJ2fAdvDTjCHZBFhu5D9pmEm3qyY0GH/wuscrXlgYC3I/0KfeY7jASN+j2PuUFazgM dP1wOT2iIC/Xc7X8sCHREY71DmfLtosFU8LZjQtIKkXv3HGITpcJ8/5eOG+vTnGiJ3gl X7PA== 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=4BSYnwiIQ7CT0Z5pJ2mXNb8eQMvY9YaXHEnPXL6O4cs=; b=EAMsngRC/+A3+GCt0mbtcIaU6S8SG56PoifBGP4HrQ1NAIPwE+3WRxYyez1AYVMR3y 86+AHZf01bT4xV54x00FmE4U3dESHspYNiKVncFkeKvkNYs7p9u9xo/keYhdXqNMTvOl WX5q859vSJsUIMiVoiVKysZwZIEyToFf/d8dx1379uXET8oPCYXhyCJc+tn0sp8bpeA7 4fgsOuoF04fF/uWME98+E5jHvkvXp8WVhFtE7wCP6N+PkafIUwelNWxRu0omarzxZAlx 1SlZP6CmUrG1wRDzhKMC9w+nuNocC39Us1esyAzDTbzomUMXUNA/5Im1rw3nb8ZsPp0p x8pw== X-Gm-Message-State: AOAM530Z3TB5Q3sAvE1HBCPZsdNx64Itqr/ETeKqJX1nwLD1+XDJ5y89 grWtrny+JkUr1/WrJMmUgN1yIIJnuRj/iw== X-Google-Smtp-Source: ABdhPJxVN8otec0I/rysHu5JxkoM1K6TYSymfWBTZEdlNI97CyERU4VYeeQ/prHRJaSappIRzkvOLA== X-Received: by 2002:adf:fccb:: with SMTP id f11mr1041144wrs.3.1607606619323; Thu, 10 Dec 2020 05:23:39 -0800 (PST) Received: from localhost.localdomain (lfbn-nic-1-190-206.w2-15.abo.wanadoo.fr. [2.15.39.206]) by smtp.gmail.com with ESMTPSA id n14sm9444811wmi.1.2020.12.10.05.23.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 10 Dec 2020 05:23:38 -0800 (PST) From: Bartosz Golaszewski To: Kent Gibson , Andy Shevchenko , Geert Uytterhoeven , Jack Winch , Helmut Grohne , Linus Walleij Cc: linux-gpio@vger.kernel.org, Bartosz Golaszewski Subject: [libgpiod][PATCH 14/14] core: kill chip iterators Date: Thu, 10 Dec 2020 14:23:15 +0100 Message-Id: <20201210132315.5785-15-brgl@bgdev.pl> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201210132315.5785-1-brgl@bgdev.pl> References: <20201210132315.5785-1-brgl@bgdev.pl> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org From: Bartosz Golaszewski Chip iterators require the user to have permission to access all GPIO chips. They also don't take into account symbolic links. In general they're badly designed so remove them treewide in favor of scanning /dev manually using the provided gpiod_is_gpiochip_device() helper. Signed-off-by: Bartosz Golaszewski --- bindings/cxx/chip.cpp | 5 + bindings/cxx/examples/Makefile.am | 4 +- bindings/cxx/examples/gpiodetectcxx.cpp | 13 ++- bindings/cxx/examples/gpiofindcxx.cpp | 16 ++- bindings/cxx/examples/gpioinfocxx.cpp | 43 +++++---- bindings/cxx/gpiod.hpp | 117 ++-------------------- bindings/cxx/iter.cpp | 67 ------------- bindings/cxx/tests/tests-chip.cpp | 20 ++++ bindings/cxx/tests/tests-iter.cpp | 37 ------- bindings/python/examples/gpiodetect.py | 12 ++- bindings/python/examples/gpiofind.py | 15 ++- bindings/python/examples/gpioinfo.py | 33 ++++--- bindings/python/gpiodmodule.c | 114 +++++++--------------- bindings/python/tests/gpiod_py_test.py | 39 +++----- configure.ac | 6 ++ include/gpiod.h | 93 +----------------- lib/Makefile.am | 2 +- lib/iter.c | 123 ------------------------ tests/Makefile.am | 1 - tests/gpiod-test.h | 2 - tests/tests-iter.c | 100 ------------------- tools/gpiodetect.c | 29 ++++-- tools/gpiofind.c | 27 +++--- tools/gpioinfo.c | 27 ++++-- tools/tools-common.c | 15 +++ tools/tools-common.h | 3 + 26 files changed, 250 insertions(+), 713 deletions(-) delete mode 100644 lib/iter.c delete mode 100644 tests/tests-iter.c diff --git a/bindings/cxx/chip.cpp b/bindings/cxx/chip.cpp index 82ba559..107088e 100644 --- a/bindings/cxx/chip.cpp +++ b/bindings/cxx/chip.cpp @@ -51,6 +51,11 @@ void chip_deleter(::gpiod_chip* chip) } /* namespace */ +bool is_gpiochip_device(const ::std::string& path) +{ + return ::gpiod_is_gpiochip_device(path.c_str()); +} + chip::chip(const ::std::string& device, int how) : _m_chip() { diff --git a/bindings/cxx/examples/Makefile.am b/bindings/cxx/examples/Makefile.am index 8d39be2..43e9875 100644 --- a/bindings/cxx/examples/Makefile.am +++ b/bindings/cxx/examples/Makefile.am @@ -7,8 +7,8 @@ # AM_CPPFLAGS = -I$(top_srcdir)/bindings/cxx/ -I$(top_srcdir)/include -AM_CPPFLAGS += -Wall -Wextra -g -std=gnu++11 -AM_LDFLAGS = -lgpiodcxx -L$(top_builddir)/bindings/cxx/ +AM_CPPFLAGS += -Wall -Wextra -g -std=gnu++17 +AM_LDFLAGS = -lgpiodcxx -L$(top_builddir)/bindings/cxx/ -lstdc++fs noinst_PROGRAMS = \ gpiodetectcxx \ diff --git a/bindings/cxx/examples/gpiodetectcxx.cpp b/bindings/cxx/examples/gpiodetectcxx.cpp index 6da5573..76d367d 100644 --- a/bindings/cxx/examples/gpiodetectcxx.cpp +++ b/bindings/cxx/examples/gpiodetectcxx.cpp @@ -10,6 +10,7 @@ #include #include +#include #include int main(int argc, char **argv) @@ -19,10 +20,14 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - for (auto& it: ::gpiod::make_chip_iter()) { - ::std::cout << it.name() << " [" - << it.label() << "] (" - << it.num_lines() << " lines)" << ::std::endl; + for (const auto& entry: ::std::filesystem::directory_iterator("/dev/")) { + if (::gpiod::is_gpiochip_device(entry.path())) { + ::gpiod::chip chip(entry.path()); + + ::std::cout << chip.name() << " [" + << chip.label() << "] (" + << chip.num_lines() << " lines)" << ::std::endl; + } } return EXIT_SUCCESS; diff --git a/bindings/cxx/examples/gpiofindcxx.cpp b/bindings/cxx/examples/gpiofindcxx.cpp index c817378..f8b771c 100644 --- a/bindings/cxx/examples/gpiofindcxx.cpp +++ b/bindings/cxx/examples/gpiofindcxx.cpp @@ -10,6 +10,7 @@ #include #include +#include #include int main(int argc, char **argv) @@ -19,11 +20,16 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - for (auto& chip: ::gpiod::make_chip_iter()) { - auto lines = chip.find_line(argv[1], true); - if (!lines.empty()) { - ::std::cout << lines.front().name() << " " << lines.front().offset() << ::std::endl; - return EXIT_SUCCESS; + for (const auto& entry: ::std::filesystem::directory_iterator("/dev/")) { + if (::gpiod::is_gpiochip_device(entry.path())) { + ::gpiod::chip chip(entry.path()); + + auto lines = chip.find_line(argv[1], true); + if (!lines.empty()) { + ::std::cout << lines.front().name() << " " << + lines.front().offset() << ::std::endl; + return EXIT_SUCCESS; + } } } diff --git a/bindings/cxx/examples/gpioinfocxx.cpp b/bindings/cxx/examples/gpioinfocxx.cpp index 02d69b6..2490abd 100644 --- a/bindings/cxx/examples/gpioinfocxx.cpp +++ b/bindings/cxx/examples/gpioinfocxx.cpp @@ -10,6 +10,7 @@ #include #include +#include #include int main(int argc, char **argv) @@ -19,31 +20,35 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - for (auto& cit: ::gpiod::make_chip_iter()) { - ::std::cout << cit.name() << " - " << cit.num_lines() << " lines:" << ::std::endl; + for (const auto& entry: ::std::filesystem::directory_iterator("/dev/")) { + if (::gpiod::is_gpiochip_device(entry.path())) { + ::gpiod::chip chip(entry.path()); - for (auto& lit: ::gpiod::line_iter(cit)) { - ::std::cout << "\tline "; - ::std::cout.width(3); - ::std::cout << lit.offset() << ": "; + ::std::cout << chip.name() << " - " << chip.num_lines() << " lines:" << ::std::endl; - ::std::cout.width(12); - ::std::cout << (lit.name().empty() ? "unnamed" : lit.name()); - ::std::cout << " "; + for (auto& lit: ::gpiod::line_iter(chip)) { + ::std::cout << "\tline "; + ::std::cout.width(3); + ::std::cout << lit.offset() << ": "; - ::std::cout.width(12); - ::std::cout << (lit.consumer().empty() ? "unused" : lit.consumer()); - ::std::cout << " "; + ::std::cout.width(12); + ::std::cout << (lit.name().empty() ? "unnamed" : lit.name()); + ::std::cout << " "; - ::std::cout.width(8); - ::std::cout << (lit.direction() == ::gpiod::line::DIRECTION_INPUT ? "input" : "output"); - ::std::cout << " "; + ::std::cout.width(12); + ::std::cout << (lit.consumer().empty() ? "unused" : lit.consumer()); + ::std::cout << " "; - ::std::cout.width(10); - ::std::cout << (lit.active_state() == ::gpiod::line::ACTIVE_LOW - ? "active-low" : "active-high"); + ::std::cout.width(8); + ::std::cout << (lit.direction() == ::gpiod::line::DIRECTION_INPUT ? "input" : "output"); + ::std::cout << " "; - ::std::cout << ::std::endl; + ::std::cout.width(10); + ::std::cout << (lit.active_state() == ::gpiod::line::ACTIVE_LOW + ? "active-low" : "active-high"); + + ::std::cout << ::std::endl; + } } } diff --git a/bindings/cxx/gpiod.hpp b/bindings/cxx/gpiod.hpp index 9d081fe..d81ee30 100644 --- a/bindings/cxx/gpiod.hpp +++ b/bindings/cxx/gpiod.hpp @@ -32,6 +32,14 @@ struct line_event; * @{ */ +/** + * @brief Check if the file pointed to by path is a GPIO chip character device. + * @param path Path to check. + * @return True if the file exists and is a GPIO chip character device or a + * symbolic link to it. + */ +bool is_gpiochip_device(const ::std::string& path) GPIOD_API; + /** * @brief Represents a GPIO chip. * @@ -861,115 +869,6 @@ private: ::std::vector _m_bulk; }; -/** - * @brief Create a new chip_iter. - * @return New chip iterator object pointing to the first GPIO chip on the system. - * @note This function is needed as we already use the default constructor of - * gpiod::chip_iter as the return value of gpiod::end. - */ -GPIOD_API chip_iter make_chip_iter(void); - -/** - * @brief Support for range-based loops for chip iterators. - * @param iter A chip iterator. - * @return Iterator unchanged. - */ -GPIOD_API chip_iter begin(chip_iter iter) noexcept; - -/** - * @brief Support for range-based loops for chip iterators. - * @param iter A chip iterator. - * @return New end iterator. - */ -GPIOD_API chip_iter end(const chip_iter& iter) noexcept; - -/** - * @brief Allows to iterate over all GPIO chips present on the system. - */ -class chip_iter -{ -public: - - /** - * @brief Default constructor. Creates the end iterator. - */ - GPIOD_API chip_iter(void) = default; - - /** - * @brief Copy constructor. - * @param other Other chip_iter. - */ - GPIOD_API chip_iter(const chip_iter& other) = default; - - /** - * @brief Move constructor. - * @param other Other chip_iter. - */ - GPIOD_API chip_iter(chip_iter&& other) = default; - - /** - * @brief Assignment operator. - * @param other Other chip_iter. - * @return Reference to this iterator. - */ - GPIOD_API chip_iter& operator=(const chip_iter& other) = default; - - /** - * @brief Move assignment operator. - * @param other Other chip_iter. - * @return Reference to this iterator. - */ - GPIOD_API chip_iter& operator=(chip_iter&& other) = default; - - /** - * @brief Destructor. - */ - GPIOD_API ~chip_iter(void) = default; - - /** - * @brief Advance the iterator by one element. - * @return Reference to this iterator. - */ - GPIOD_API chip_iter& operator++(void); - - /** - * @brief Dereference current element. - * @return Current GPIO chip by reference. - */ - GPIOD_API const chip& operator*(void) const; - - /** - * @brief Member access operator. - * @return Current GPIO chip by pointer. - */ - GPIOD_API const chip* operator->(void) const; - - /** - * @brief Check if this operator points to the same element. - * @param rhs Right-hand side of the equation. - * @return True if this iterator points to the same chip_iter, - * false otherwise. - */ - GPIOD_API bool operator==(const chip_iter& rhs) const noexcept; - - /** - * @brief Check if this operator doesn't point to the same element. - * @param rhs Right-hand side of the equation. - * @return True if this iterator doesn't point to the same chip_iter, - * false otherwise. - */ - GPIOD_API bool operator!=(const chip_iter& rhs) const noexcept; - -private: - - chip_iter(::gpiod_chip_iter* iter); - - ::std::shared_ptr<::gpiod_chip_iter> _m_iter; - chip _m_current; - - friend chip_iter make_chip_iter(void); -}; - /** * @brief Support for range-based loops for line iterators. * @param iter A line iterator. diff --git a/bindings/cxx/iter.cpp b/bindings/cxx/iter.cpp index 15c3925..846d36b 100644 --- a/bindings/cxx/iter.cpp +++ b/bindings/cxx/iter.cpp @@ -10,73 +10,6 @@ namespace gpiod { -namespace { - -void chip_iter_deleter(::gpiod_chip_iter* iter) -{ - ::gpiod_chip_iter_free_noclose(iter); -} - -} /* namespace */ - -chip_iter make_chip_iter(void) -{ - ::gpiod_chip_iter* iter = ::gpiod_chip_iter_new(); - if (!iter) - throw ::std::system_error(errno, ::std::system_category(), - "error creating GPIO chip iterator"); - - return chip_iter(iter); -} - -bool chip_iter::operator==(const chip_iter& rhs) const noexcept -{ - return this->_m_current == rhs._m_current; -} - -bool chip_iter::operator!=(const chip_iter& rhs) const noexcept -{ - return this->_m_current != rhs._m_current; -} - -chip_iter::chip_iter(::gpiod_chip_iter *iter) - : _m_iter(iter, chip_iter_deleter) -{ - ::gpiod_chip* first = ::gpiod_chip_iter_next_noclose(this->_m_iter.get()); - - if (first != nullptr) - this->_m_current = chip(first); -} - -chip_iter& chip_iter::operator++(void) -{ - ::gpiod_chip* next = ::gpiod_chip_iter_next_noclose(this->_m_iter.get()); - - this->_m_current = next ? chip(next) : chip(); - - return *this; -} - -const chip& chip_iter::operator*(void) const -{ - return this->_m_current; -} - -const chip* chip_iter::operator->(void) const -{ - return ::std::addressof(this->_m_current); -} - -chip_iter begin(chip_iter iter) noexcept -{ - return iter; -} - -chip_iter end(const chip_iter&) noexcept -{ - return chip_iter(); -} - line_iter begin(line_iter iter) noexcept { return iter; diff --git a/bindings/cxx/tests/tests-chip.cpp b/bindings/cxx/tests/tests-chip.cpp index c45f2df..2492b42 100644 --- a/bindings/cxx/tests/tests-chip.cpp +++ b/bindings/cxx/tests/tests-chip.cpp @@ -12,6 +12,26 @@ using ::gpiod::test::mockup; +TEST_CASE("GPIO chip device can be verified with is_gpiochip_device()", "[chip]") +{ + mockup::probe_guard mockup_chips({ 8 }); + + SECTION("good chip") + { + REQUIRE(::gpiod::is_gpiochip_device(mockup::instance().chip_path(0))); + } + + SECTION("not a chip") + { + REQUIRE_FALSE(::gpiod::is_gpiochip_device("/dev/null")); + } + + SECTION("nonexistent file") + { + REQUIRE_FALSE(::gpiod::is_gpiochip_device("/dev/nonexistent_device")); + } +} + TEST_CASE("GPIO chip device can be opened in different modes", "[chip]") { mockup::probe_guard mockup_chips({ 8, 8, 8 }); diff --git a/bindings/cxx/tests/tests-iter.cpp b/bindings/cxx/tests/tests-iter.cpp index 4c07613..708709c 100644 --- a/bindings/cxx/tests/tests-iter.cpp +++ b/bindings/cxx/tests/tests-iter.cpp @@ -12,43 +12,6 @@ using ::gpiod::test::mockup; -TEST_CASE("Chip iterator works", "[iter][chip]") -{ - mockup::probe_guard mockup_chips({ 8, 8, 8 }); - bool gotA = false, gotB = false, gotC = false; - - for (auto& it: ::gpiod::make_chip_iter()) { - if (it.label() == "gpio-mockup-A") - gotA = true; - if (it.label() == "gpio-mockup-B") - gotB = true; - if (it.label() == "gpio-mockup-C") - gotC = true; - } - - REQUIRE(gotA); - REQUIRE(gotB); - REQUIRE(gotC); -} - -TEST_CASE("Chip iterator loop can be broken out of", "[iter][chip]") -{ - mockup::probe_guard mockup_chips({ 8, 8, 8, 8, 8, 8 }); - int count_chips = 0; - - for (auto& it: ::gpiod::make_chip_iter()) { - if (it.label() == "gpio-mockup-A" || - it.label() == "gpio-mockup-B" || - it.label() == "gpio-mockup-C") - count_chips++; - - if (count_chips == 3) - break; - } - - REQUIRE(count_chips == 3); -} - TEST_CASE("Line iterator works", "[iter][line]") { mockup::probe_guard mockup_chips({ 4 }); diff --git a/bindings/python/examples/gpiodetect.py b/bindings/python/examples/gpiodetect.py index 9318f51..781939b 100755 --- a/bindings/python/examples/gpiodetect.py +++ b/bindings/python/examples/gpiodetect.py @@ -10,10 +10,12 @@ '''Reimplementation of the gpiodetect tool in Python.''' import gpiod +import os if __name__ == '__main__': - for chip in gpiod.ChipIter(): - print('{} [{}] ({} lines)'.format(chip.name(), - chip.label(), - chip.num_lines())) - chip.close() + for entry in os.scandir('/dev/'): + if gpiod.is_gpiochip_device(entry.path): + with gpiod.Chip(entry.path) as chip: + print('{} [{}] ({} lines)'.format(chip.name(), + chip.label(), + chip.num_lines())) diff --git a/bindings/python/examples/gpiofind.py b/bindings/python/examples/gpiofind.py index 8505ba0..2655742 100755 --- a/bindings/python/examples/gpiofind.py +++ b/bindings/python/examples/gpiofind.py @@ -10,12 +10,17 @@ '''Reimplementation of the gpiofind tool in Python.''' import gpiod +import os import sys if __name__ == '__main__': - line = gpiod.find_line(sys.argv[1]) - if line is None: - sys.exit(1) + for entry in os.scandir('/dev/'): + if gpiod.is_gpiochip_device(entry.path): + with gpiod.Chip(entry.path) as chip: + lines = chip.find_line(sys.argv[1], unique=True) + if lines is not None: + line = lines.to_list()[0] + print('{} {}'.format(line.owner().name(), line.offset())) + sys.exit(0) - print('{} {}'.format(line.owner().name(), line.offset())) - line.owner().close() + sys.exit(1) diff --git a/bindings/python/examples/gpioinfo.py b/bindings/python/examples/gpioinfo.py index de4b6f3..6a47b66 100755 --- a/bindings/python/examples/gpioinfo.py +++ b/bindings/python/examples/gpioinfo.py @@ -10,23 +10,24 @@ '''Simplified reimplementation of the gpioinfo tool in Python.''' import gpiod +import os if __name__ == '__main__': - for chip in gpiod.ChipIter(): - print('{} - {} lines:'.format(chip.name(), chip.num_lines())) + for entry in os.scandir('/dev/'): + if gpiod.is_gpiochip_device(entry.path): + with gpiod.Chip(entry.path) as chip: + print('{} - {} lines:'.format(chip.name(), chip.num_lines())) - for line in gpiod.LineIter(chip): - offset = line.offset() - name = line.name() - consumer = line.consumer() - direction = line.direction() - active_state = line.active_state() + for line in gpiod.LineIter(chip): + offset = line.offset() + name = line.name() + consumer = line.consumer() + direction = line.direction() + active_state = line.active_state() - print('\tline {:>3}: {:>18} {:>12} {:>8} {:>10}'.format( - offset, - 'unnamed' if name is None else name, - 'unused' if consumer is None else consumer, - 'input' if direction == gpiod.Line.DIRECTION_INPUT else 'output', - 'active-low' if active_state == gpiod.Line.ACTIVE_LOW else 'active-high')) - - chip.close() + print('\tline {:>3}: {:>18} {:>12} {:>8} {:>10}'.format( + offset, + 'unnamed' if name is None else name, + 'unused' if consumer is None else consumer, + 'input' if direction == gpiod.Line.DIRECTION_INPUT else 'output', + 'active-low' if active_state == gpiod.Line.ACTIVE_LOW else 'active-high')) diff --git a/bindings/python/gpiodmodule.c b/bindings/python/gpiodmodule.c index d183e6f..af37df2 100644 --- a/bindings/python/gpiodmodule.c +++ b/bindings/python/gpiodmodule.c @@ -34,11 +34,6 @@ typedef struct { Py_ssize_t iter_idx; } gpiod_LineBulkObject; -typedef struct { - PyObject_HEAD - struct gpiod_chip_iter *iter; -} gpiod_ChipIterObject; - typedef struct { PyObject_HEAD unsigned int offset; @@ -2220,7 +2215,7 @@ PyDoc_STRVAR(gpiod_Chip_find_line_doc, static gpiod_LineBulkObject * gpiod_Chip_find_line(gpiod_ChipObject *self, PyObject *args, PyObject *kwds) { - static char *kwlist[] = { "unique", NULL }; + static char *kwlist[] = { "", "unique", NULL }; gpiod_LineBulkObject *bulk_obj; struct gpiod_line_bulk *bulk; @@ -2469,76 +2464,6 @@ static PyTypeObject gpiod_ChipType = { .tp_methods = gpiod_Chip_methods, }; -static int gpiod_ChipIter_init(gpiod_ChipIterObject *self, - PyObject *Py_UNUSED(ignored0), - PyObject *Py_UNUSED(ignored1)) -{ - self->iter = gpiod_chip_iter_new(); - if (!self->iter) { - PyErr_SetFromErrno(PyExc_OSError); - return -1; - } - - return 0; -} - -static void gpiod_ChipIter_dealloc(gpiod_ChipIterObject *self) -{ - if (self->iter) - gpiod_chip_iter_free_noclose(self->iter); - - PyObject_Del(self); -} - -static gpiod_ChipObject *gpiod_ChipIter_next(gpiod_ChipIterObject *self) -{ - gpiod_ChipObject *chip_obj; - struct gpiod_chip *chip; - - Py_BEGIN_ALLOW_THREADS; - chip = gpiod_chip_iter_next_noclose(self->iter); - Py_END_ALLOW_THREADS; - if (!chip) - return NULL; /* Last element. */ - - chip_obj = PyObject_New(gpiod_ChipObject, &gpiod_ChipType); - if (!chip_obj) { - gpiod_chip_close(chip); - return NULL; - } - - chip_obj->chip = chip; - - return chip_obj; -} - -PyDoc_STRVAR(gpiod_ChipIterType_doc, -"Allows to iterate over all GPIO chips in the system.\n" -"\n" -"The ChipIter's constructor takes no arguments.\n" -"\n" -"Each iteration yields the next open GPIO chip handle. The caller is\n" -"responsible for closing each chip\n" -"\n" -"Example:\n" -"\n" -" for chip in gpiod.ChipIter():\n" -" do_something_with_chip(chip)\n" -" chip.close()"); - -static PyTypeObject gpiod_ChipIterType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "gpiod.ChipIter", - .tp_basicsize = sizeof(gpiod_ChipIterObject), - .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = gpiod_ChipIterType_doc, - .tp_new = PyType_GenericNew, - .tp_init = (initproc)gpiod_ChipIter_init, - .tp_dealloc = (destructor)gpiod_ChipIter_dealloc, - .tp_iter = PyObject_SelfIter, - .tp_iternext = (iternextfunc)gpiod_ChipIter_next, -}; - static int gpiod_LineIter_init(gpiod_LineIterObject *self, PyObject *args, PyObject *Py_UNUSED(ignored)) { @@ -2618,7 +2543,6 @@ static gpiod_PyType gpiod_PyType_list[] = { { .name = "LineEvent", .typeobj = &gpiod_LineEventType, }, { .name = "LineBulk", .typeobj = &gpiod_LineBulkType, }, { .name = "LineIter", .typeobj = &gpiod_LineIterType, }, - { .name = "ChipIter", .typeobj = &gpiod_ChipIterType }, { } }; @@ -2702,6 +2626,41 @@ static gpiod_ConstDescr gpiod_ConstList[] = { { } }; +PyDoc_STRVAR(gpiod_Module_is_gpiochip_device_doc, +"is_gpiochip_device(path) -> boolean\n" +"\n" +"Check if the file pointed to by path is a GPIO chip character device.\n" +"Returns true if so, False otherwise.\n" +"\n" +" path\n" +" Path to the file that should be checked.\n"); + +static PyObject * +gpiod_Module_is_gpiochip_device(PyObject *Py_UNUSED(self), PyObject *args) +{ + const char *path; + int ret; + + ret = PyArg_ParseTuple(args, "s", &path); + if (!ret) + return NULL; + + if (gpiod_is_gpiochip_device(path)) + Py_RETURN_TRUE; + + Py_RETURN_FALSE; +} + +static PyMethodDef gpiod_module_methods[] = { + { + .ml_name = "is_gpiochip_device", + .ml_meth = (PyCFunction)gpiod_Module_is_gpiochip_device, + .ml_flags = METH_VARARGS, + .ml_doc = gpiod_Module_is_gpiochip_device_doc, + }, + { } +}; + PyDoc_STRVAR(gpiod_Module_doc, "Python bindings for libgpiod.\n\ \n\ @@ -2712,6 +2671,7 @@ static PyModuleDef gpiod_Module = { .m_name = "gpiod", .m_doc = gpiod_Module_doc, .m_size = -1, + .m_methods = gpiod_module_methods, }; typedef struct { diff --git a/bindings/python/tests/gpiod_py_test.py b/bindings/python/tests/gpiod_py_test.py index c490933..f116657 100755 --- a/bindings/python/tests/gpiod_py_test.py +++ b/bindings/python/tests/gpiod_py_test.py @@ -79,6 +79,19 @@ def check_kernel(major, minor, release): # Chip test cases # +class IsGpioDevice(MockupTestCase): + + chip_sizes = ( 8, ) + + def test_is_gpiochip_device_good(self): + self.assertTrue(gpiod.is_gpiochip_device(mockup.chip_path(0))) + + def test_is_gpiochip_device_bad(self): + self.assertFalse(gpiod.is_gpiochip_device('/dev/null')) + + def test_is_gpiochip_device_nonexistent(self): + self.assertFalse(gpiod.is_gpiochip_device('/dev/nonexistent_device')) + class ChipOpen(MockupTestCase): chip_sizes = ( 8, 8, 8 ) @@ -149,8 +162,7 @@ class ChipGetLines(MockupTestCase): def test_find_single_line_by_name(self): with gpiod.Chip(mockup.chip_name(1)) as chip: - lines = chip.find_line('gpio-mockup-B-4').to_list() - self.assertEqual(len(lines), 1) + lines = chip.find_line('gpio-mockup-B-4', unique=True).to_list() self.assertEqual(lines[0].offset(), 4) def test_get_single_line_invalid_offset(self): @@ -162,7 +174,7 @@ class ChipGetLines(MockupTestCase): def test_find_single_line_nonexistent(self): with gpiod.Chip(mockup.chip_name(1)) as chip: - lines = chip.find_line('nonexistent-line') + lines = chip.find_line('nonexistent-line', unique=True) self.assertEqual(lines, None) def test_get_multiple_lines_by_offsets_in_tuple(self): @@ -675,27 +687,6 @@ class LineRequestBehavior(MockupTestCase): # Iterator test cases # -class ChipIterator(MockupTestCase): - - chip_sizes = ( 4, 8, 16 ) - - def test_iterate_over_chips(self): - gotA = False - gotB = False - gotC = False - - for chip in gpiod.ChipIter(): - if chip.label() == 'gpio-mockup-A': - gotA = True - elif chip.label() == 'gpio-mockup-B': - gotB = True - elif chip.label() == 'gpio-mockup-C': - gotC = True - - self.assertTrue(gotA) - self.assertTrue(gotB) - self.assertTrue(gotC) - class LineIterator(MockupTestCase): chip_sizes = ( 4, ) diff --git a/configure.ac b/configure.ac index 90a6324..ddb9dc2 100644 --- a/configure.ac +++ b/configure.ac @@ -181,6 +181,12 @@ then AC_LANG_POP([C++]) ]) fi + + if test "x$with_examples" = xtrue + then + # Examples use C++17 features + AX_CXX_COMPILE_STDCXX([17], [ext], [mandatory]) + fi fi AC_ARG_ENABLE([bindings-python], diff --git a/include/gpiod.h b/include/gpiod.h index fc50fe8..a7e7348 100644 --- a/include/gpiod.h +++ b/include/gpiod.h @@ -8,6 +8,7 @@ #ifndef __LIBGPIOD_GPIOD_H__ #define __LIBGPIOD_GPIOD_H__ +#include #include #include #include @@ -27,7 +28,7 @@ extern "C" { * users of libgpiod. * *

The API is logically split into several parts such as: GPIO chip & line - * operators, iterators, GPIO events handling etc. + * operators, GPIO events handling etc. * *

General note on error handling: all routines exported by libgpiod set * errno to one of the error values defined in errno.h upon failure. The way @@ -39,7 +40,6 @@ extern "C" { struct gpiod_chip; struct gpiod_line; -struct gpiod_chip_iter; struct gpiod_line_bulk; /** @@ -1053,95 +1053,6 @@ int gpiod_line_event_read_fd_multiple(int fd, struct gpiod_line_event *events, /** * @} * - * @} - * - * @defgroup iterators Iterators for GPIO chips and lines - * @{ - * - * These functions and data structures allow easy iterating over GPIO - * chips and lines. - */ - -/** - * @brief Create a new gpiochip iterator. - * @return Pointer to a new chip iterator object or NULL if an error occurred. - * - * Internally this routine scans the /dev/ directory for GPIO chip device - * files, opens them and stores their the handles until ::gpiod_chip_iter_free - * or ::gpiod_chip_iter_free_noclose is called. - */ -struct gpiod_chip_iter *gpiod_chip_iter_new(void) GPIOD_API; - -/** - * @brief Release all resources allocated for the gpiochip iterator and close - * the most recently opened gpiochip (if any). - * @param iter The gpiochip iterator object. - */ -void gpiod_chip_iter_free(struct gpiod_chip_iter *iter) GPIOD_API; - -/** - * @brief Release all resources allocated for the gpiochip iterator but - * don't close the most recently opened gpiochip (if any). - * @param iter The gpiochip iterator object. - * - * Users may want to break the loop when iterating over gpiochips and keep - * the most recently opened chip active while freeing the iterator data. - * This routine enables that. - */ -void gpiod_chip_iter_free_noclose(struct gpiod_chip_iter *iter) GPIOD_API; - -/** - * @brief Get the next gpiochip handle. - * @param iter The gpiochip iterator object. - * @return Pointer to the next open gpiochip handle or NULL if no more chips - * are present in the system. - * @note The previous chip handle will be closed using ::gpiod_chip_iter_free. - */ -struct gpiod_chip * -gpiod_chip_iter_next(struct gpiod_chip_iter *iter) GPIOD_API; - -/** - * @brief Get the next gpiochip handle without closing the previous one. - * @param iter The gpiochip iterator object. - * @return Pointer to the next open gpiochip handle or NULL if no more chips - * are present in the system. - * @note This function works just like ::gpiod_chip_iter_next but doesn't - * close the most recently opened chip handle. - */ -struct gpiod_chip * -gpiod_chip_iter_next_noclose(struct gpiod_chip_iter *iter) GPIOD_API; - -/** - * @brief Iterate over all GPIO chips present in the system. - * @param iter An initialized GPIO chip iterator. - * @param chip Pointer to a GPIO chip handle. On each iteration the newly - * opened chip handle is assigned to this argument. - * - * The user must not close the GPIO chip manually - instead the previous chip - * handle is closed automatically on the next iteration. The last chip to be - * opened is closed internally by ::gpiod_chip_iter_free. - */ -#define gpiod_foreach_chip(iter, chip) \ - for ((chip) = gpiod_chip_iter_next(iter); \ - (chip); \ - (chip) = gpiod_chip_iter_next(iter)) - -/** - * @brief Iterate over all chips present in the system without closing them. - * @param iter An initialized GPIO chip iterator. - * @param chip Pointer to a GPIO chip handle. On each iteration the newly - * opened chip handle is assigned to this argument. - * - * The user must close all the GPIO chips manually after use, until then, the - * chips remain open. Free the iterator by calling - * ::gpiod_chip_iter_free_noclose to avoid closing the last chip automatically. - */ -#define gpiod_foreach_chip_noclose(iter, chip) \ - for ((chip) = gpiod_chip_iter_next_noclose(iter); \ - (chip); \ - (chip) = gpiod_chip_iter_next_noclose(iter)) - -/** * @} * * @defgroup misc Stuff that didn't fit anywhere else diff --git a/lib/Makefile.am b/lib/Makefile.am index c5277ce..43ebf76 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -7,7 +7,7 @@ # lib_LTLIBRARIES = libgpiod.la -libgpiod_la_SOURCES = core.c helpers.c iter.c misc.c +libgpiod_la_SOURCES = core.c helpers.c misc.c libgpiod_la_CFLAGS = -Wall -Wextra -g -std=gnu89 libgpiod_la_CFLAGS += -fvisibility=hidden -I$(top_srcdir)/include/ libgpiod_la_CFLAGS += -include $(top_builddir)/config.h diff --git a/lib/iter.c b/lib/iter.c deleted file mode 100644 index 2ff767c..0000000 --- a/lib/iter.c +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * This file is part of libgpiod. - * - * Copyright (C) 2017-2018 Bartosz Golaszewski - */ - -/* GPIO chip and line iterators. */ - -#include -#include -#include - -struct gpiod_chip_iter { - struct gpiod_chip **chips; - unsigned int num_chips; - unsigned int offset; -}; - -static int dir_filter(const struct dirent *dir) -{ - return !strncmp(dir->d_name, "gpiochip", 8); -} - -static void free_dirs(struct dirent **dirs, unsigned int num_dirs) -{ - unsigned int i; - - for (i = 0; i < num_dirs; i++) - free(dirs[i]); - free(dirs); -} - -struct gpiod_chip_iter *gpiod_chip_iter_new(void) -{ - struct gpiod_chip_iter *iter; - struct dirent **dirs; - int i, num_chips; - - num_chips = scandir("/dev", &dirs, dir_filter, alphasort); - if (num_chips < 0) - return NULL; - - iter = malloc(sizeof(*iter)); - if (!iter) - goto err_free_dirs; - - iter->num_chips = num_chips; - iter->offset = 0; - - if (num_chips == 0) { - iter->chips = NULL; - return iter; - } - - iter->chips = calloc(num_chips, sizeof(*iter->chips)); - if (!iter->chips) - goto err_free_iter; - - for (i = 0; i < num_chips; i++) { - iter->chips[i] = gpiod_chip_open_by_name(dirs[i]->d_name); - if (!iter->chips[i]) - goto err_close_chips; - } - - free_dirs(dirs, num_chips); - - return iter; - -err_close_chips: - for (i = 0; i < num_chips; i++) { - if (iter->chips[i]) - gpiod_chip_close(iter->chips[i]); - } - - free(iter->chips); - -err_free_iter: - free(iter); - -err_free_dirs: - free_dirs(dirs, num_chips); - - return NULL; -} - -void gpiod_chip_iter_free(struct gpiod_chip_iter *iter) -{ - if (iter->offset > 0 && iter->offset < iter->num_chips) - gpiod_chip_close(iter->chips[iter->offset - 1]); - gpiod_chip_iter_free_noclose(iter); -} - -void gpiod_chip_iter_free_noclose(struct gpiod_chip_iter *iter) -{ - unsigned int i; - - for (i = iter->offset; i < iter->num_chips; i++) { - if (iter->chips[i]) - gpiod_chip_close(iter->chips[i]); - } - - if (iter->chips) - free(iter->chips); - - free(iter); -} - -struct gpiod_chip *gpiod_chip_iter_next(struct gpiod_chip_iter *iter) -{ - if (iter->offset > 0) { - gpiod_chip_close(iter->chips[iter->offset - 1]); - iter->chips[iter->offset - 1] = NULL; - } - - return gpiod_chip_iter_next_noclose(iter); -} - -struct gpiod_chip *gpiod_chip_iter_next_noclose(struct gpiod_chip_iter *iter) -{ - return iter->offset < (iter->num_chips) - ? iter->chips[iter->offset++] : NULL; -} diff --git a/tests/Makefile.am b/tests/Makefile.am index 2d3b959..91798f7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -25,6 +25,5 @@ gpiod_test_SOURCES = \ tests-bulk.c \ tests-chip.c \ tests-event.c \ - tests-iter.c \ tests-line.c \ tests-misc.c diff --git a/tests/gpiod-test.h b/tests/gpiod-test.h index df9f0c7..7ed4d23 100644 --- a/tests/gpiod-test.h +++ b/tests/gpiod-test.h @@ -25,11 +25,9 @@ */ typedef struct gpiod_chip gpiod_chip_struct; typedef struct gpiod_line_bulk gpiod_line_bulk_struct; -typedef struct gpiod_chip_iter gpiod_chip_iter_struct; G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_struct, gpiod_chip_close); G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_line_bulk_struct, gpiod_line_bulk_free); -G_DEFINE_AUTOPTR_CLEANUP_FUNC(gpiod_chip_iter_struct, gpiod_chip_iter_free); /* These are private definitions and should not be used directly. */ typedef void (*_gpiod_test_func)(void); diff --git a/tests/tests-iter.c b/tests/tests-iter.c deleted file mode 100644 index 163a820..0000000 --- a/tests/tests-iter.c +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1-or-later -/* - * This file is part of libgpiod. - * - * Copyright (C) 2019 Bartosz Golaszewski - */ - -#include - -#include "gpiod-test.h" - -#define GPIOD_TEST_GROUP "iter" - -GPIOD_TEST_CASE(chip_iter, 0, { 8, 8, 8 }) -{ - g_autoptr(gpiod_chip_iter_struct) iter = NULL; - struct gpiod_chip *chip; - gboolean A, B, C; - - A = B = C = FALSE; - - iter = gpiod_chip_iter_new(); - g_assert_nonnull(iter); - gpiod_test_return_if_failed(); - - gpiod_foreach_chip(iter, chip) { - if (strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0) - A = TRUE; - else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-B") == 0) - B = TRUE; - else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-C") == 0) - C = TRUE; - } - - g_assert_true(A); - g_assert_true(B); - g_assert_true(C); -} - -GPIOD_TEST_CASE(chip_iter_no_close, 0, { 8, 8, 8 }) -{ - g_autoptr(gpiod_chip_iter_struct) iter = NULL; - g_autoptr(gpiod_chip_struct) chipA = NULL; - g_autoptr(gpiod_chip_struct) chipB = NULL; - g_autoptr(gpiod_chip_struct) chipC = NULL; - struct gpiod_chip *chip; - - iter = gpiod_chip_iter_new(); - g_assert_nonnull(iter); - gpiod_test_return_if_failed(); - - gpiod_foreach_chip_noclose(iter, chip) { - if (strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0) - chipA = chip; - else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-B") == 0) - chipB = chip; - else if (strcmp(gpiod_chip_label(chip), "gpio-mockup-C") == 0) - chipC = chip; - else - gpiod_chip_close(chip); - } - - g_assert_nonnull(chipA); - g_assert_nonnull(chipB); - g_assert_nonnull(chipC); - - gpiod_chip_iter_free_noclose(iter); - iter = NULL; - - /* See if the chips are still open and usable. */ - g_assert_cmpstr(gpiod_chip_label(chipA), ==, "gpio-mockup-A"); - g_assert_cmpstr(gpiod_chip_label(chipB), ==, "gpio-mockup-B"); - g_assert_cmpstr(gpiod_chip_label(chipC), ==, "gpio-mockup-C"); -} - -GPIOD_TEST_CASE(chip_iter_break, 0, { 8, 8, 8, 8, 8 }) -{ - g_autoptr(gpiod_chip_iter_struct) iter = NULL; - struct gpiod_chip *chip; - guint i = 0; - - iter = gpiod_chip_iter_new(); - g_assert_nonnull(iter); - gpiod_test_return_if_failed(); - - gpiod_foreach_chip(iter, chip) { - if ((strcmp(gpiod_chip_label(chip), "gpio-mockup-A") == 0) || - (strcmp(gpiod_chip_label(chip), "gpio-mockup-B") == 0) || - (strcmp(gpiod_chip_label(chip), "gpio-mockup-C") == 0)) - i++; - - if (i == 3) - break; - } - - gpiod_chip_iter_free(iter); - iter = NULL; - - g_assert_cmpuint(i, ==, 3); -} diff --git a/tools/gpiodetect.c b/tools/gpiodetect.c index 1c992a4..8e067f7 100644 --- a/tools/gpiodetect.c +++ b/tools/gpiodetect.c @@ -5,6 +5,8 @@ * Copyright (C) 2017-2018 Bartosz Golaszewski */ +#include +#include #include #include #include @@ -33,9 +35,9 @@ static void print_help(void) int main(int argc, char **argv) { - struct gpiod_chip_iter *iter; + int optc, opti, num_chips, i; struct gpiod_chip *chip; - int optc, opti; + struct dirent **entries; for (;;) { optc = getopt_long(argc, argv, shortopts, longopts, &opti); @@ -62,18 +64,31 @@ int main(int argc, char **argv) if (argc > 0) die("unrecognized argument: %s", argv[0]); - iter = gpiod_chip_iter_new(); - if (!iter) - die_perror("unable to access GPIO chips"); + num_chips = scandir("/dev/", &entries, chip_dir_filter, alphasort); + if (num_chips < 0) + die_perror("unable to scan /dev"); + + for (i = 0; i < num_chips; i++) { + chip = gpiod_chip_open_by_name(entries[i]->d_name); + if (!chip) { + if (errno == EACCES) + printf("%s Permission denied\n", + entries[i]->d_name); + else + die_perror("unable to open %s", + entries[i]->d_name); + } - gpiod_foreach_chip(iter, chip) { printf("%s [%s] (%u lines)\n", gpiod_chip_name(chip), gpiod_chip_label(chip), gpiod_chip_num_lines(chip)); + + gpiod_chip_close(chip); + free(entries[i]); } - gpiod_chip_iter_free(iter); + free(entries); return EXIT_SUCCESS; } diff --git a/tools/gpiofind.c b/tools/gpiofind.c index ffb8fc0..4acf621 100644 --- a/tools/gpiofind.c +++ b/tools/gpiofind.c @@ -5,6 +5,7 @@ * Copyright (C) 2017-2018 Bartosz Golaszewski */ +#include #include #include #include @@ -34,10 +35,10 @@ static void print_help(void) int main(int argc, char **argv) { - struct gpiod_chip_iter *iter; + int i, num_chips, optc, opti; struct gpiod_chip *chip; struct gpiod_line *line; - int optc, opti; + struct dirent **entries; for (;;) { optc = getopt_long(argc, argv, shortopts, longopts, &opti); @@ -64,23 +65,27 @@ int main(int argc, char **argv) if (argc != 1) die("exactly one GPIO line name must be specified"); - iter = gpiod_chip_iter_new(); - if (!iter) - die_perror("unable to access GPIO chips"); + num_chips = scandir("/dev/", &entries, chip_dir_filter, alphasort); + if (num_chips < 0) + die_perror("unable to scan /dev"); + + for (i = 0; i < num_chips; i++) { + chip = gpiod_chip_open_by_name(entries[i]->d_name); + if (!chip) { + if (errno == EACCES) + continue; + + die_perror("unable to open %s", entries[i]->d_name); + } - gpiod_foreach_chip(iter, chip) { line = gpiod_chip_find_line_unique(chip, argv[0]); if (line) { printf("%s %u\n", gpiod_chip_name(chip), gpiod_line_offset(line)); - gpiod_chip_iter_free(iter); + gpiod_chip_close(chip); return EXIT_SUCCESS; } - - if (errno != ENOENT) - die_perror("error performing the line lookup"); } - gpiod_chip_iter_free(iter); return EXIT_FAILURE; } diff --git a/tools/gpioinfo.c b/tools/gpioinfo.c index dd4a388..e3dbde7 100644 --- a/tools/gpioinfo.c +++ b/tools/gpioinfo.c @@ -5,6 +5,7 @@ * Copyright (C) 2017-2018 Bartosz Golaszewski */ +#include #include #include #include @@ -180,9 +181,9 @@ static void list_lines(struct gpiod_chip *chip) int main(int argc, char **argv) { - struct gpiod_chip_iter *chip_iter; + int num_chips, i, optc, opti; struct gpiod_chip *chip; - int i, optc, opti; + struct dirent **entries; for (;;) { optc = getopt_long(argc, argv, shortopts, longopts, &opti); @@ -207,14 +208,26 @@ int main(int argc, char **argv) argv += optind; if (argc == 0) { - chip_iter = gpiod_chip_iter_new(); - if (!chip_iter) - die_perror("error accessing GPIO chips"); + num_chips = scandir("/dev/", &entries, + chip_dir_filter, alphasort); + if (num_chips < 0) + die_perror("unable to scan /dev"); + + for (i = 0; i < num_chips; i++) { + chip = gpiod_chip_open_by_name(entries[i]->d_name); + if (!chip) { + if (errno == EACCES) + printf("%s Permission denied\n", + entries[i]->d_name); + else + die_perror("unable to open %s", + entries[i]->d_name); + } - gpiod_foreach_chip(chip_iter, chip) list_lines(chip); - gpiod_chip_iter_free(chip_iter); + gpiod_chip_close(chip); + } } else { for (i = 0; i < argc; i++) { chip = gpiod_chip_open_lookup(argv[i]); diff --git a/tools/tools-common.c b/tools/tools-common.c index af05102..b64ef93 100644 --- a/tools/tools-common.c +++ b/tools/tools-common.c @@ -101,3 +101,18 @@ int make_signalfd(void) return sigfd; } + +int chip_dir_filter(const struct dirent *entry) +{ + bool is_chip; + char *path; + int ret; + + ret = asprintf(&path, "/dev/%s", entry->d_name); + if (ret < 0) + return 0; + + is_chip = gpiod_is_gpiochip_device(path); + free(path); + return !!is_chip; +} diff --git a/tools/tools-common.h b/tools/tools-common.h index 8ccde62..4148dd8 100644 --- a/tools/tools-common.h +++ b/tools/tools-common.h @@ -8,6 +8,8 @@ #ifndef __GPIOD_TOOLS_COMMON_H__ #define __GPIOD_TOOLS_COMMON_H__ +#include + /* * Various helpers for the GPIO tools. * @@ -29,5 +31,6 @@ void print_version(void); int bias_flags(const char *option); void print_bias_help(void); int make_signalfd(void); +int chip_dir_filter(const struct dirent *entry); #endif /* __GPIOD_TOOLS_COMMON_H__ */