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:
parent
5a4219043d
commit
5b896ed585
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user