event: Add events for device probe/remove
authorSimon Glass <sjg@chromium.org>
Fri, 4 Mar 2022 15:43:03 +0000 (08:43 -0700)
committerTom Rini <trini@konsulko.com>
Thu, 10 Mar 2022 13:28:36 +0000 (08:28 -0500)
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>
common/event.c
drivers/core/Kconfig
drivers/core/device-remove.c
drivers/core/device.c
include/dm/device-internal.h
include/event.h
test/common/event.c

index 366be24..737d3ac 100644 (file)
@@ -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");
index 8f7703c..5c34004 100644 (file)
@@ -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
index e6ec6ff..73d2e9e 100644 (file)
@@ -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:
index 901c1e2..1b356f1 100644 (file)
@@ -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)) {
index 02002ac..c420726 100644 (file)
@@ -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
index effd58c..f4c12d7 100644 (file)
@@ -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;
 };
 
 /**
index dfaa66e..6037ae2 100644 (file)
@@ -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);