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

Simon Glass sjg at chromium.org
Mon Apr 24 02:10:45 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.

The caller must check the return value each time to make sure that the
device is valid. But the device pointer is always returned.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

Changes in v2:
- Return even device, even those with errors
- Rename the functions

 drivers/core/uclass.c | 27 +++++++++++++++++
 include/dm/uclass.h   | 31 ++++++++++++++++++++
 test/dm/test-fdt.c    | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 138 insertions(+)

diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 42613031ff..69456ebcb0 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -456,6 +456,33 @@ int uclass_next_device(struct udevice **devp)
 	return uclass_get_device_tail(dev, ret, devp);
 }
 
+int uclass_first_device_check(enum uclass_id id, struct udevice **devp)
+{
+	int ret;
+
+	*devp = NULL;
+	ret = uclass_find_first_device(id, devp);
+	if (ret)
+		return ret;
+	if (!*devp)
+		return 0;
+
+	return device_probe(*devp);
+}
+
+int uclass_next_device_check(struct udevice **devp)
+{
+	int ret;
+
+	ret = uclass_find_next_device(devp);
+	if (ret)
+		return ret;
+	if (!*devp)
+		return 0;
+
+	return device_probe(*devp);
+}
+
 int uclass_bind_device(struct udevice *dev)
 {
 	struct uclass *uc;
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index 63da868ae5..4a713412a6 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_device() - Get the first device in a uclass
+ *
+ * The device returned is probed if necessary, and ready for use
+ *
+ * This function is useful to start iterating through a list of devices which
+ * are functioning correctly and can be probed.
+ *
+ * @id: Uclass ID to look up
+ * @devp: Returns pointer to the first device in that uclass, or NULL if there
+ * is no first device
+ * @return 0 if OK (found or not found), other -ve on error. If an error occurs
+ * it is still possible to move to the next device.
+ */
+int uclass_first_device_check(enum uclass_id id, struct udevice **devp);
+
+/**
+ * uclass_next_device() - Get the next device in a uclass
+ *
+ * The device returned is probed if necessary, and ready for use
+ *
+ * This function is useful to start iterating through a list of devices which
+ * are functioning correctly and can be probed.
+ *
+ * @devp: On entry, pointer to device to lookup. On exit, returns pointer
+ * to the next device in the uclass if any
+ * @return 0 if OK (found or not found), other -ve on error. If an error occurs
+ * it is still possible to move to the next device.
+ */
+int uclass_next_device_check(struct udevice **devp);
+
+/**
  * 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..f028fe5935 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -338,3 +338,83 @@ 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);
+
+/**
+ * check_devices() - Check return values and pointers
+ *
+ * This runs through a full sequence of uclass_first_device_check()...
+ * uclass_next_device_check() checking that the return values and devices
+ * are correct.
+ *
+ * @uts: Test state
+ * @devlist: List of expected devices
+ * @mask: Indicates which devices should return an error. Device n should
+ *	  return error (-NOENT - n) if bit n is set, or no error (i.e. 0) if
+ *	  bit n is clear.
+ */
+static int check_devices(struct unit_test_state *uts,
+			 struct udevice *devlist[], int mask)
+{
+	int expected_ret;
+	struct udevice *dev;
+	int i;
+
+	expected_ret = (mask & 1) ? -ENOENT : 0;
+	mask >>= 1;
+	ut_asserteq(expected_ret,
+		    uclass_first_device_check(UCLASS_TEST_PROBE, &dev));
+	for (i = 0; i < 4; i++) {
+		ut_asserteq_ptr(devlist[i], dev);
+		expected_ret = (mask & 1) ? -ENOENT - (i + 1) : 0;
+		mask >>= 1;
+		ut_asserteq(expected_ret, uclass_next_device_check(&dev));
+	}
+	ut_asserteq_ptr(NULL, dev);
+
+	return 0;
+}
+
+/* Test uclass_first_device_check() and uclass_next_device_check() */
+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;
+	int ret;
+
+	/* There should be 4 devices */
+	count = 0;
+	for (ret = uclass_first_device_check(UCLASS_TEST_PROBE, &dev);
+	     dev;
+	     ret = uclass_next_device_check(&dev)) {
+		ut_assertok(ret);
+		devlist[count++] = dev;
+		parent = dev_get_parent(dev);
+		}
+	ut_asserteq(4, count);
+	ut_assertok(uclass_first_device_check(UCLASS_TEST_PROBE, &dev));
+	ut_assertok(check_devices(uts, devlist, 0));
+
+	/* Remove them and try again, with an error on the second one */
+	pdata = dev_get_platdata(devlist[1]);
+	pdata->probe_err = -ENOENT - 1;
+	device_remove(parent, DM_REMOVE_NORMAL);
+	ut_assertok(check_devices(uts, devlist, 1 << 1));
+
+	/* Now an error on the first one */
+	pdata = dev_get_platdata(devlist[0]);
+	pdata->probe_err = -ENOENT - 0;
+	device_remove(parent, DM_REMOVE_NORMAL);
+	ut_assertok(check_devices(uts, devlist, 3 << 0));
+
+	/* Now errors on all */
+	pdata = dev_get_platdata(devlist[2]);
+	pdata->probe_err = -ENOENT - 2;
+	pdata = dev_get_platdata(devlist[3]);
+	pdata->probe_err = -ENOENT - 3;
+	device_remove(parent, DM_REMOVE_NORMAL);
+	ut_assertok(check_devices(uts, devlist, 0xf << 0));
+
+	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