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>
This commit is contained in:
Simon Glass 2022-03-04 08:43:03 -07:00 committed by Tom Rini
parent 5a4219043d
commit 5b896ed585
7 changed files with 96 additions and 0 deletions

View 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");

View 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

View 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:

View 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)) {

View 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

View 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;
};
/**

View 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);