Sometimes it is useful to iterate through all devices in a uclass and
skip over those which do not work correctly (e.g fail to probe). Add two
new functions to provide this feature.

Signed-off-by: Simon Glass <[email protected]>
---

 drivers/core/uclass.c | 29 +++++++++++++++++++++++++++++
 include/dm/uclass.h   | 31 +++++++++++++++++++++++++++++++
 test/dm/test-fdt.c    | 45 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 105 insertions(+)

diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 42613031ff..eac30d965d 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -456,6 +456,35 @@ int uclass_next_device(struct udevice **devp)
        return uclass_get_device_tail(dev, ret, devp);
 }
 
+struct udevice *uclass_first_ok_device(enum uclass_id id)
+{
+       struct udevice *dev;
+       int ret;
+
+       ret = uclass_find_first_device(id, &dev);
+       if (!dev)
+               return NULL;
+       ret = device_probe(dev);
+       if (ret)
+               return uclass_next_ok_device(dev);
+
+       return dev;
+}
+
+struct udevice *uclass_next_ok_device(struct udevice *dev)
+{
+       int ret;
+
+       do {
+               ret = uclass_find_next_device(&dev);
+               if (!dev)
+                       return NULL;
+               ret = device_probe(dev);
+       } while (ret);
+
+       return dev;
+}
+
 int uclass_bind_device(struct udevice *dev)
 {
        struct uclass *uc;
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 63da868ae5..b53fba5c2c 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -262,6 +262,37 @@ int uclass_first_device_err(enum uclass_id id, struct 
udevice **devp);
 int uclass_next_device(struct udevice **devp);
 
 /**
+ * uclass_first_ok_device() - Get the first functioning device in a uclass
+ *
+ * The device returned is probed if necessary, and ready for use. Any devices
+ * which fail to probe are skipped. It is not possible to discover the error
+ * for any devices which fail to probe. You should use uclass_first_device()
+ * if you care about that.
+ *
+ * @id: Uclass ID to look up
+ * @return: pointer to the first functioning device in that uclass if one
+ * can be found, or NULL if there is no such device (e.g. if the rest of the
+ * devices cannot be probed).
+ */
+struct udevice *uclass_first_ok_device(enum uclass_id id);
+
+/**
+ * uclass_next_ok_device() - Get the next functioning device in a uclass
+ *
+ * The device returned is probed if necessary, and ready for use. Any devices
+ * which fail to probe are skipped. It is not possible to discover the error
+ * for any devices which fail to probe. You should use uclass_next_device()
+ * if you care about that.
+ *
+ * @dev: Pointer to the previous device (e.g. returned from
+ * uclass_first_ok_device() or uclass_next_ok_device()
+ * @return: pointer to the next functioning device in the same uclass if one
+ * can be found, or NULL if there is no such device (e.g. if the rest of the
+ * devices cannot be probed).
+ */
+struct udevice *uclass_next_ok_device(struct udevice *dev);
+
+/**
  * uclass_resolve_seq() - Resolve a device's sequence number
  *
  * On entry dev->seq is -1, and dev->req_seq may be -1 (to allocate a
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 1770b86fed..69c1a89246 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -338,3 +338,48 @@ static int dm_test_first_next_device(struct 
unit_test_state *uts)
        return 0;
 }
 DM_TEST(dm_test_first_next_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test uclass_first_ok_device() and uclass_next_ok_device() */
+static int dm_test_first_next_ok_device(struct unit_test_state *uts)
+{
+       struct dm_testprobe_pdata *pdata;
+       struct udevice *dev, *parent = NULL, *devlist[4];
+       int count;
+
+       /* There should be 4 devices */
+       for (dev = uclass_first_ok_device(UCLASS_TEST_PROBE), count = 0;
+            dev;
+            dev = uclass_next_ok_device(dev)) {
+               devlist[count++] = dev;
+               parent = dev_get_parent(dev);
+               }
+       ut_asserteq(4, count);
+
+       /* Remove them and try again, with an error on the second one */
+       pdata = dev_get_platdata(devlist[1]);
+       pdata->probe_err = -ENOMEM;
+       device_remove(parent, DM_REMOVE_NORMAL);
+       ut_asserteq_ptr(devlist[0], uclass_first_ok_device(UCLASS_TEST_PROBE));
+       ut_asserteq_ptr(devlist[2], uclass_next_ok_device(devlist[0]));
+       ut_asserteq_ptr(devlist[3], uclass_next_ok_device(devlist[2]));
+       ut_asserteq_ptr(NULL, uclass_next_ok_device(devlist[3]));
+
+       /* Now an error on the first one */
+       pdata = dev_get_platdata(devlist[0]);
+       pdata->probe_err = -ENOENT;
+       device_remove(parent, DM_REMOVE_NORMAL);
+       ut_asserteq_ptr(devlist[2], uclass_first_ok_device(UCLASS_TEST_PROBE));
+       ut_asserteq_ptr(devlist[3], uclass_next_ok_device(devlist[2]));
+       ut_asserteq_ptr(NULL, uclass_next_ok_device(devlist[3]));
+
+       /* Now errors on all */
+       pdata = dev_get_platdata(devlist[2]);
+       pdata->probe_err = -ENOENT;
+       pdata = dev_get_platdata(devlist[3]);
+       pdata->probe_err = -ENOENT;
+       device_remove(parent, DM_REMOVE_NORMAL);
+       ut_asserteq_ptr(NULL, uclass_first_ok_device(UCLASS_TEST_PROBE));
+
+       return 0;
+}
+DM_TEST(dm_test_first_next_ok_device, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
-- 
2.12.2.816.g2cccc81164-goog

_______________________________________________
U-Boot mailing list
[email protected]
https://lists.denx.de/listinfo/u-boot

Reply via email to