[U-Boot] [PATCH 3/3] dm: core: Add uclass_first/next_ok_device()

Simon Glass sjg at chromium.org
Thu Apr 20 01:29:56 UTC 2017


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 <sjg at chromium.org>
---

 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



More information about the U-Boot mailing list