event: Add events for device probe/remove
Generate events when devices are probed or removed, allowing hooks
to be added for these situations.
This is controlled by the DM_EVENT config option.
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/common/event.c b/common/event.c
index 366be24..737d3ac 100644
--- a/common/event.c
+++ b/common/event.c
@@ -24,6 +24,12 @@
const char *const type_name[] = {
"none",
"test",
+
+ /* Events related to driver model */
+ "dm_pre_probe",
+ "dm_post_probe",
+ "dm_pre_remove",
+ "dm_post_remove",
};
_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 8f7703c..5c34004 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -77,6 +77,16 @@
it causes unplugged devices to linger around in the dm-tree, and it
causes USB host controllers to not be stopped when booting the OS.
+config DM_EVENT
+ bool "Support events with driver model"
+ depends on DM
+ imply EVENT
+ default y if SANDBOX
+ help
+ This enables support for generating events related to driver model
+ operations, such as prbing or removing a device. Subsystems can
+ register a 'spy' function that is called when the event occurs.
+
config SPL_DM_DEVICE_REMOVE
bool "Support device removal in SPL"
depends on SPL_DM
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index e6ec6ff..73d2e9e 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -207,6 +207,10 @@
if (!(dev_get_flags(dev) & DM_FLAG_ACTIVATED))
return 0;
+ ret = device_notify(dev, EVT_DM_PRE_REMOVE);
+ if (ret)
+ return ret;
+
/*
* If the child returns EKEYREJECTED, continue. It just means that it
* didn't match the flags.
@@ -256,6 +260,10 @@
dev_bic_flags(dev, DM_FLAG_ACTIVATED);
+ ret = device_notify(dev, EVT_DM_POST_REMOVE);
+ if (ret)
+ goto err_remove;
+
return 0;
err_remove:
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 901c1e2..1b356f1 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -10,6 +10,7 @@
#include <common.h>
#include <cpu_func.h>
+#include <event.h>
#include <log.h>
#include <asm/global_data.h>
#include <asm/io.h>
@@ -493,6 +494,10 @@
if (dev_get_flags(dev) & DM_FLAG_ACTIVATED)
return 0;
+ ret = device_notify(dev, EVT_DM_PRE_PROBE);
+ if (ret)
+ return ret;
+
drv = dev->driver;
assert(drv);
@@ -597,6 +602,10 @@
dev->name, ret, errno_str(ret));
}
+ ret = device_notify(dev, EVT_DM_POST_PROBE);
+ if (ret)
+ return ret;
+
return 0;
fail_uclass:
if (device_remove(dev, DM_REMOVE_NORMAL)) {
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 02002ac..c420726 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -10,6 +10,7 @@
#ifndef _DM_DEVICE_INTERNAL_H
#define _DM_DEVICE_INTERNAL_H
+#include <event.h>
#include <linker_lists.h>
#include <dm/ofnode.h>
@@ -426,4 +427,13 @@
}
#endif /* ! CONFIG_DEVRES */
+
+static inline int device_notify(const struct udevice *dev, enum event_t type)
+{
+#if CONFIG_IS_ENABLED(DM_EVENT)
+ return event_notify(type, &dev, sizeof(dev));
+#else
+ return 0;
+#endif
+}
#endif
diff --git a/include/event.h b/include/event.h
index effd58c..f4c12d7 100644
--- a/include/event.h
+++ b/include/event.h
@@ -19,6 +19,12 @@
EVT_NONE,
EVT_TEST,
+ /* Events related to driver model */
+ EVT_DM_PRE_PROBE,
+ EVT_DM_POST_PROBE,
+ EVT_DM_PRE_REMOVE,
+ EVT_DM_POST_REMOVE,
+
EVT_COUNT
};
@@ -31,6 +37,15 @@
struct event_data_test {
int signal;
} test;
+
+ /**
+ * struct event_dm - driver model event
+ *
+ * @dev: Device this event relates to
+ */
+ struct event_dm {
+ struct udevice *dev;
+ } dm;
};
/**
diff --git a/test/common/event.c b/test/common/event.c
index dfaa66e..6037ae2 100644
--- a/test/common/event.c
+++ b/test/common/event.c
@@ -45,3 +45,41 @@
return 0;
}
COMMON_TEST(test_event_base, 0);
+
+static int h_probe(void *ctx, struct event *event)
+{
+ struct test_state *test_state = ctx;
+
+ test_state->dev = event->data.dm.dev;
+ switch (event->type) {
+ case EVT_DM_PRE_PROBE:
+ test_state->val |= 1;
+ break;
+ case EVT_DM_POST_PROBE:
+ test_state->val |= 2;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int test_event_probe(struct unit_test_state *uts)
+{
+ struct test_state state;
+ struct udevice *dev;
+
+ state.val = 0;
+ ut_assertok(event_register("pre", EVT_DM_PRE_PROBE, h_probe, &state));
+ ut_assertok(event_register("post", EVT_DM_POST_PROBE, h_probe, &state));
+
+ /* Probe a device */
+ ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
+
+ /* Check that the handler is called */
+ ut_asserteq(3, state.val);
+
+ return 0;
+}
+COMMON_TEST(test_event_probe, UT_TESTF_DM | UT_TESTF_SCAN_FDT);