dm: Add child_pre_probe() and child_post_remove() methods

Some devices (particularly bus devices) must track their children, knowing
when a new child is added so that it can be set up for communication on the
bus.

Add a child_pre_probe() method to provide this feature, and a corresponding
child_post_remove() method.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2014-07-23 06:55:21 -06:00
parent e59f458de6
commit a327dee0f4
5 changed files with 160 additions and 2 deletions

View File

@@ -14,11 +14,39 @@
DECLARE_GLOBAL_DATA_PTR;
enum {
FLAG_CHILD_PROBED = 10,
FLAG_CHILD_REMOVED = -7,
};
static struct dm_test_state *test_state;
static int testbus_drv_probe(struct udevice *dev)
{
return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
}
static int testbus_child_pre_probe(struct udevice *dev)
{
struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
parent_data->flag += FLAG_CHILD_PROBED;
return 0;
}
static int testbus_child_post_remove(struct udevice *dev)
{
struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
struct dm_test_state *dms = test_state;
parent_data->flag += FLAG_CHILD_REMOVED;
if (dms)
dms->removed = dev;
return 0;
}
static const struct udevice_id testbus_ids[] = {
{
.compatible = "denx,u-boot-test-bus",
@@ -34,6 +62,8 @@ U_BOOT_DRIVER(testbus_drv) = {
.priv_auto_alloc_size = sizeof(struct dm_test_priv),
.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
.per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
.child_pre_probe = testbus_child_pre_probe,
.child_post_remove = testbus_child_post_remove,
};
UCLASS_DRIVER(testbus) = {
@@ -172,3 +202,41 @@ static int dm_test_bus_parent_data(struct dm_test_state *dms)
}
DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
/* Test that the bus ops are called when a child is probed/removed */
static int dm_test_bus_parent_ops(struct dm_test_state *dms)
{
struct dm_test_parent_data *parent_data;
struct udevice *bus, *dev;
struct uclass *uc;
test_state = dms;
ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
ut_assertok(uclass_get(UCLASS_TEST_FDT, &uc));
uclass_foreach_dev(dev, uc) {
/* Ignore these if they are not on this bus */
if (dev->parent != bus)
continue;
ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
ut_assertok(device_probe(dev));
parent_data = dev_get_parentdata(dev);
ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
}
uclass_foreach_dev(dev, uc) {
/* Ignore these if they are not on this bus */
if (dev->parent != bus)
continue;
parent_data = dev_get_parentdata(dev);
ut_asserteq(FLAG_CHILD_PROBED, parent_data->flag);
ut_assertok(device_remove(dev));
ut_asserteq_ptr(NULL, dev_get_parentdata(dev));
ut_asserteq_ptr(dms->removed, dev);
}
test_state = NULL;
return 0;
}
DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);