core: kill chip iterators
authorBartosz Golaszewski <bgolaszewski@baylibre.com>
Thu, 26 Nov 2020 13:11:54 +0000 (14:11 +0100)
committerBartosz Golaszewski <bgolaszewski@baylibre.com>
Mon, 14 Dec 2020 14:57:15 +0000 (15:57 +0100)
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 <bgolaszewski@baylibre.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
26 files changed:
bindings/cxx/chip.cpp
bindings/cxx/examples/Makefile.am
bindings/cxx/examples/gpiodetectcxx.cpp
bindings/cxx/examples/gpiofindcxx.cpp
bindings/cxx/examples/gpioinfocxx.cpp
bindings/cxx/gpiod.hpp
bindings/cxx/iter.cpp
bindings/cxx/tests/tests-chip.cpp
bindings/cxx/tests/tests-iter.cpp
bindings/python/examples/gpiodetect.py
bindings/python/examples/gpiofind.py
bindings/python/examples/gpioinfo.py
bindings/python/gpiodmodule.c
bindings/python/tests/gpiod_py_test.py
configure.ac
include/gpiod.h
lib/Makefile.am
lib/iter.c [deleted file]
tests/Makefile.am
tests/gpiod-test.h
tests/tests-iter.c [deleted file]
tools/gpiodetect.c
tools/gpiofind.c
tools/gpioinfo.c
tools/tools-common.c
tools/tools-common.h

index 82ba559a1ecb02607fee618eecdc5c11524d8009..107088ea5fa92d8a41bd3ff00694e280829b57d7 100644 (file)
@@ -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()
 {
index 8d39be25ab40aac4e2d704bacad746178b66cb17..43e98755466cca8084e09a887100180739f54cee 100644 (file)
@@ -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                   \
index 6da557303c697ce86afe34f5ab54f2a0fd4e1667..76d367da5f4eeda264251714d0e6dda23d60dcd5 100644 (file)
@@ -10,6 +10,7 @@
 #include <gpiod.hpp>
 
 #include <cstdlib>
+#include <filesystem>
 #include <iostream>
 
 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;
index c817378edbf79f075e500f24befd7be2da34d5f5..f8b771c7584a428c09431b960d36eb2cb7f01bc5 100644 (file)
@@ -10,6 +10,7 @@
 #include <gpiod.hpp>
 
 #include <cstdlib>
+#include <filesystem>
 #include <iostream>
 
 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;
+                       }
                }
        }
 
index 02d69b6a182a25daca72c9243d68f2fd0b267cb2..2490abdf1290a29965ee0bca85d7cc6082a13ba9 100644 (file)
@@ -10,6 +10,7 @@
 #include <gpiod.hpp>
 
 #include <cstdlib>
+#include <filesystem>
 #include <iostream>
 
 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;
+                       }
                }
        }
 
index 9d081fecaebd13b9e582080f9d35d07d50230893..d81ee302facb4001fd3d302fa00d1f8aad8e4fad 100644 (file)
@@ -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<line> _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.
index 15c3925107a6808511b38cd8e7d30e6398361c5b..846d36b7c712feed795ffaafc63583d1193e00ae 100644 (file)
 
 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;
index c45f2df7432e33c0c2c269a68ddd66e9470ecb0d..2492b4278ec60b28dc39a4bd8f798091596a01f7 100644 (file)
 
 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 });
index 4c07613d4dafd2d88009ddc697e68697e39ff9b1..708709c4ea326cce41027a0fb5813bbca01c6ab2 100644 (file)
 
 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 });
index 9318f51942e4458a899d6d5d43f76e7c8a2b7b27..781939b46bf498006a05253a7af93a48831f4a23 100755 (executable)
 '''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()))
index 8505ba020e02541d541c726072a00f4a70df257a..26557424edfa2398fa3a688d44cd05655751e059 100755 (executable)
 '''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)
index de4b6f33720c735b3c2145f3c2425aadc46e37e3..6a47b66653bf83f7e401d043b09fc91f73234ed0 100755 (executable)
 '''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'))
index d183e6f24a90d40123440ffe385433c1b8518f63..af37df22e1aab10e868a5fe6fece2c34dc41114a 100644 (file)
@@ -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 {
index c490933597e462870736ddaa52374a9d76851286..f116657ba0618630997c15f1845f4e2523e0637c 100755 (executable)
@@ -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, )
index 90a63240ea192fd3e1f87ee5afc7455491d4b402..ddb9dc217c9a3989647b6e57b21d7a2f37640e38 100644 (file)
@@ -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],
index fc50fe8887ac7a85cbd4ff2ecb1505961bed8a7a..a7e7348782b8ab7f4150f8b717871d7f9e051e83 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __LIBGPIOD_GPIOD_H__
 #define __LIBGPIOD_GPIOD_H__
 
+#include <dirent.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <time.h>
@@ -27,7 +28,7 @@ extern "C" {
  * users of libgpiod.
  *
  * <p>The API is logically split into several parts such as: GPIO chip & line
- * operators, iterators, GPIO events handling etc.
+ * operators, GPIO events handling etc.
  *
  * <p>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
index c5277cec4c2b394604dda9561557fb6e70791176..43ebf762b5a0971880c40df5454031085f88993b 100644 (file)
@@ -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 (file)
index 2ff767c..0000000
+++ /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 <bartekgola@gmail.com>
- */
-
-/* GPIO chip and line iterators. */
-
-#include <dirent.h>
-#include <gpiod.h>
-#include <string.h>
-
-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;
-}
index 2d3b95939e2d02a39fbfe63b6fa388b1121e6dbe..91798f71349b43c5c902e8687697c2cceadd9cf7 100644 (file)
@@ -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
index df9f0c7fc34736031b4f6cbf2b9b71912bd1ae28..7ed4d2357b007549e619114b4b52caa6a9043c85 100644 (file)
  */
 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 (file)
index 163a820..0000000
+++ /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 <bgolaszewski@baylibre.com>
- */
-
-#include <string.h>
-
-#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);
-}
index 1c992a4313825eab1471df97b0c392d409b526b3..8e067f7fb326f2f3d8e8d892625f2dfe7983cd23 100644 (file)
@@ -5,6 +5,8 @@
  * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
  */
 
+#include <dirent.h>
+#include <errno.h>
 #include <getopt.h>
 #include <gpiod.h>
 #include <stdio.h>
@@ -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;
 }
index ffb8fc055788d78e5c3150ef7416698cbfce0652..4acf621f56814b0efbac56216ed08d2476d89f62 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
  */
 
+#include <dirent.h>
 #include <errno.h>
 #include <getopt.h>
 #include <gpiod.h>
@@ -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;
 }
index dd4a388432397e707722842e0c1002c8c5385a91..e3dbde71aedc927e8bc5c20ef26bc7a05e5d56c6 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2017-2018 Bartosz Golaszewski <bartekgola@gmail.com>
  */
 
+#include <dirent.h>
 #include <errno.h>
 #include <getopt.h>
 #include <gpiod.h>
@@ -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]);
index af05102e50a86d5dca630b1b9f82066f1fd86269..b64ef93cb4c02be8963a4e8b5581b42c24845672 100644 (file)
@@ -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;
+}
index 8ccde62aa36958887f583e860a41be65655aecc9..4148dd8ef0b97808777fa80d3e1838f7805d3c1a 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __GPIOD_TOOLS_COMMON_H__
 #define __GPIOD_TOOLS_COMMON_H__
 
+#include <dirent.h>
+
 /*
  * 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__ */