dm: core: Add a function to find the first inactive child
authorSimon Glass <sjg@chromium.org>
Mon, 1 Oct 2018 18:22:07 +0000 (12:22 -0600)
committerSimon Glass <sjg@chromium.org>
Tue, 9 Oct 2018 10:40:27 +0000 (04:40 -0600)
Some devices have children and want to press an existing inactive child
into service when needed. Add a function to help with this.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/core/device.c
include/dm/device.h
test/dm/core.c

index a9e5906e7cde64d4832a733d82eda99fec2517e0..5176aa3f866f49a422a0dba715237144ad5039cd 100644 (file)
@@ -681,6 +681,24 @@ int device_find_next_child(struct udevice **devp)
        return 0;
 }
 
+int device_find_first_inactive_child(struct udevice *parent,
+                                    enum uclass_id uclass_id,
+                                    struct udevice **devp)
+{
+       struct udevice *dev;
+
+       *devp = NULL;
+       list_for_each_entry(dev, &parent->child_head, sibling_node) {
+               if (!device_active(dev) &&
+                   device_get_uclass_id(dev) == uclass_id) {
+                       *devp = dev;
+                       return 0;
+               }
+       }
+
+       return -ENODEV;
+}
+
 struct udevice *dev_get_parent(const struct udevice *child)
 {
        return child->parent;
index f873fc66e121da98fd56dc19f09c78a391fa84f7..847934425bbc0a03fbbb84226687f51a25fb85e4 100644 (file)
@@ -519,6 +519,21 @@ int device_find_first_child(struct udevice *parent, struct udevice **devp);
  */
 int device_find_next_child(struct udevice **devp);
 
+/**
+ * device_find_first_inactive_child() - Find the first inactive child
+ *
+ * This is used to locate an existing child of a device which is of a given
+ * uclass.
+ *
+ * @parent:    Parent device to search
+ * @uclass_id: Uclass to look for
+ * @devp:      Returns device found, if any
+ * @return 0 if found, else -ENODEV
+ */
+int device_find_first_inactive_child(struct udevice *parent,
+                                    enum uclass_id uclass_id,
+                                    struct udevice **devp);
+
 /**
  * device_has_children() - check if a device has any children
  *
index c15a8406c09811ed70932c4999e9433b63b26283..260f6494a2ecc606335bc2d60c481259a3b275f5 100644 (file)
@@ -870,3 +870,34 @@ static int dm_test_uclass_names(struct unit_test_state *uts)
        return 0;
 }
 DM_TEST(dm_test_uclass_names, DM_TESTF_SCAN_PDATA);
+
+static int dm_test_inactive_child(struct unit_test_state *uts)
+{
+       struct dm_test_state *dms = uts->priv;
+       struct udevice *parent, *dev1, *dev2;
+
+       /* Skip the behaviour in test_post_probe() */
+       dms->skip_post_probe = 1;
+
+       ut_assertok(uclass_first_device_err(UCLASS_TEST, &parent));
+
+       /*
+        * Create a child but do not activate it. Calling the function again
+        * should return the same child.
+        */
+       ut_asserteq(-ENODEV, device_find_first_inactive_child(parent,
+                                                       UCLASS_TEST, &dev1));
+       ut_assertok(device_bind_ofnode(parent, DM_GET_DRIVER(test_drv),
+                                      "test_child", 0, ofnode_null(), &dev1));
+
+       ut_assertok(device_find_first_inactive_child(parent, UCLASS_TEST,
+                                                    &dev2));
+       ut_asserteq_ptr(dev1, dev2);
+
+       ut_assertok(device_probe(dev1));
+       ut_asserteq(-ENODEV, device_find_first_inactive_child(parent,
+                                                       UCLASS_TEST, &dev2));
+
+       return 0;
+}
+DM_TEST(dm_test_inactive_child, DM_TESTF_SCAN_PDATA);