
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@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);