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 <[email protected]>
---

(no changes since v1)

 common/event.c               |  6 ++++++
 drivers/core/Kconfig         | 10 ++++++++++
 drivers/core/device-remove.c |  8 ++++++++
 drivers/core/device.c        |  9 +++++++++
 include/dm/device-internal.h | 10 ++++++++++
 include/event.h              | 15 ++++++++++++++
 test/common/event.c          | 38 ++++++++++++++++++++++++++++++++++++
 7 files changed, 96 insertions(+)

diff --git a/common/event.c b/common/event.c
index 366be24569..737d3ac9ea 100644
--- a/common/event.c
+++ b/common/event.c
@@ -24,6 +24,12 @@ DECLARE_GLOBAL_DATA_PTR;
 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 8f7703c8b5..5c3400417f 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -77,6 +77,16 @@ config DM_DEVICE_REMOVE
          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 e6ec6ff421..73d2e9e420 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -207,6 +207,10 @@ int device_remove(struct udevice *dev, uint flags)
        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 @@ int device_remove(struct udevice *dev, uint flags)
 
        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 901c1e2f7d..1b356f12dd 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 @@ int device_probe(struct udevice *dev)
        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 @@ int device_probe(struct udevice *dev)
                                  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 02002acb78..c420726287 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 @@ static inline void devres_release_all(struct udevice *dev)
 }
 
 #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 effd58c704..f4c12d768b 100644
--- a/include/event.h
+++ b/include/event.h
@@ -19,6 +19,12 @@ enum event_t {
        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 @@ union event_data {
        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 dfaa66ea49..6037ae2ce3 100644
--- a/test/common/event.c
+++ b/test/common/event.c
@@ -45,3 +45,41 @@ static int test_event_base(struct unit_test_state *uts)
        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);
-- 
2.35.1.616.g0bdcbb4464-goog

Reply via email to