mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +01:00 
			
		
		
		
	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:
		| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user