blob: 9d67a060a021f73763a3dbc75b9c44602446ba75 [file] [log] [blame]
Simon Glass87a5d1b2022-03-04 08:43:00 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Events provide a general-purpose way to react to / subscribe to changes
4 * within U-Boot
5 *
6 * Copyright 2021 Google LLC
7 * Written by Simon Glass <sjg@chromium.org>
8 */
9
10#define LOG_CATEGORY LOGC_EVENT
11
12#include <common.h>
13#include <event.h>
14#include <event_internal.h>
15#include <log.h>
16#include <linker_lists.h>
17#include <malloc.h>
18#include <asm/global_data.h>
19#include <linux/list.h>
20
21DECLARE_GLOBAL_DATA_PTR;
22
23#if CONFIG_IS_ENABLED(EVENT_DEBUG)
24const char *const type_name[] = {
25 "none",
26 "test",
Simon Glass5b896ed2022-03-04 08:43:03 -070027
28 /* Events related to driver model */
Simon Glass7fe32b32022-03-04 08:43:05 -070029 "dm_post_init",
Simon Glass5b896ed2022-03-04 08:43:03 -070030 "dm_pre_probe",
31 "dm_post_probe",
32 "dm_pre_remove",
33 "dm_post_remove",
Simon Glass42fdceb2022-03-04 08:43:04 -070034
35 /* init hooks */
36 "misc_init_f",
Simon Glass87a5d1b2022-03-04 08:43:00 -070037};
38
39_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
40#endif
41
42static const char *event_type_name(enum event_t type)
43{
44#if CONFIG_IS_ENABLED(EVENT_DEBUG)
45 return type_name[type];
46#else
47 return "(unknown)";
48#endif
49}
50
51static int notify_static(struct event *ev)
52{
53 struct evspy_info *start =
54 ll_entry_start(struct evspy_info, evspy_info);
55 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
56 struct evspy_info *spy;
57
58 for (spy = start; spy != start + n_ents; spy++) {
59 if (spy->type == ev->type) {
60 int ret;
61
62 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
63 event_type_name(ev->type), event_spy_id(spy));
64 ret = spy->func(NULL, ev);
65
66 /*
67 * TODO: Handle various return codes to
68 *
69 * - claim an event (no others will see it)
70 * - return an error from the event
71 */
72 if (ret)
73 return log_msg_ret("spy", ret);
74 }
75 }
76
77 return 0;
78}
79
80static int notify_dynamic(struct event *ev)
81{
82 struct event_state *state = gd_event_state();
83 struct event_spy *spy, *next;
84
85 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
86 if (spy->type == ev->type) {
87 int ret;
88
89 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
90 event_type_name(ev->type), spy->id);
91 ret = spy->func(spy->ctx, ev);
92
93 /*
94 * TODO: Handle various return codes to
95 *
96 * - claim an event (no others will see it)
97 * - return an error from the event
98 */
99 if (ret)
100 return log_msg_ret("spy", ret);
101 }
102 }
103
104 return 0;
105}
106
107int event_notify(enum event_t type, void *data, int size)
108{
109 struct event event;
110 int ret;
111
112 event.type = type;
113 if (size > sizeof(event.data))
114 return log_msg_ret("size", -E2BIG);
115 memcpy(&event.data, data, size);
116
117 ret = notify_static(&event);
118 if (ret)
119 return log_msg_ret("dyn", ret);
120
121 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
122 ret = notify_dynamic(&event);
123 if (ret)
124 return log_msg_ret("dyn", ret);
125 }
126
127 return 0;
128}
129
130int event_notify_null(enum event_t type)
131{
132 return event_notify(type, NULL, 0);
133}
134
135void event_show_spy_list(void)
136{
137 struct evspy_info *start =
138 ll_entry_start(struct evspy_info, evspy_info);
139 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
140 struct evspy_info *spy;
141 const int size = sizeof(ulong) * 2;
142
143 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
144 for (spy = start; spy != start + n_ents; spy++) {
145 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
146 spy->type, event_type_name(spy->type), size, spy->func,
147 event_spy_id(spy));
148 }
149}
150
151#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
152static void spy_free(struct event_spy *spy)
153{
154 list_del(&spy->sibling_node);
155}
156
157int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
158{
159 struct event_state *state = gd_event_state();
160 struct event_spy *spy;
161
162 if (!CONFIG_IS_ENABLED(EVENT_DYNAMIC))
163 return -ENOSYS;
164 spy = malloc(sizeof(*spy));
165 if (!spy)
166 return log_msg_ret("alloc", -ENOMEM);
167
168 spy->id = id;
169 spy->type = type;
170 spy->func = func;
171 spy->ctx = ctx;
172 list_add_tail(&spy->sibling_node, &state->spy_head);
173
174 return 0;
175}
176
177int event_uninit(void)
178{
179 struct event_state *state = gd_event_state();
180 struct event_spy *spy, *next;
181
182 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
183 spy_free(spy);
184
185 return 0;
186}
187
188int event_init(void)
189{
190 struct event_state *state = gd_event_state();
191
192 INIT_LIST_HEAD(&state->spy_head);
193
194 return 0;
195}
196#endif /* EVENT_DYNAMIC */