blob: 737d3ac9eaaab5aca907dce237cd8dacea406b50 [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 */
29 "dm_pre_probe",
30 "dm_post_probe",
31 "dm_pre_remove",
32 "dm_post_remove",
Simon Glass87a5d1b2022-03-04 08:43:00 -070033};
34
35_Static_assert(ARRAY_SIZE(type_name) == EVT_COUNT, "event type_name size");
36#endif
37
38static const char *event_type_name(enum event_t type)
39{
40#if CONFIG_IS_ENABLED(EVENT_DEBUG)
41 return type_name[type];
42#else
43 return "(unknown)";
44#endif
45}
46
47static int notify_static(struct event *ev)
48{
49 struct evspy_info *start =
50 ll_entry_start(struct evspy_info, evspy_info);
51 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
52 struct evspy_info *spy;
53
54 for (spy = start; spy != start + n_ents; spy++) {
55 if (spy->type == ev->type) {
56 int ret;
57
58 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
59 event_type_name(ev->type), event_spy_id(spy));
60 ret = spy->func(NULL, ev);
61
62 /*
63 * TODO: Handle various return codes to
64 *
65 * - claim an event (no others will see it)
66 * - return an error from the event
67 */
68 if (ret)
69 return log_msg_ret("spy", ret);
70 }
71 }
72
73 return 0;
74}
75
76static int notify_dynamic(struct event *ev)
77{
78 struct event_state *state = gd_event_state();
79 struct event_spy *spy, *next;
80
81 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node) {
82 if (spy->type == ev->type) {
83 int ret;
84
85 log_debug("Sending event %x/%s to spy '%s'\n", ev->type,
86 event_type_name(ev->type), spy->id);
87 ret = spy->func(spy->ctx, ev);
88
89 /*
90 * TODO: Handle various return codes to
91 *
92 * - claim an event (no others will see it)
93 * - return an error from the event
94 */
95 if (ret)
96 return log_msg_ret("spy", ret);
97 }
98 }
99
100 return 0;
101}
102
103int event_notify(enum event_t type, void *data, int size)
104{
105 struct event event;
106 int ret;
107
108 event.type = type;
109 if (size > sizeof(event.data))
110 return log_msg_ret("size", -E2BIG);
111 memcpy(&event.data, data, size);
112
113 ret = notify_static(&event);
114 if (ret)
115 return log_msg_ret("dyn", ret);
116
117 if (CONFIG_IS_ENABLED(EVENT_DYNAMIC)) {
118 ret = notify_dynamic(&event);
119 if (ret)
120 return log_msg_ret("dyn", ret);
121 }
122
123 return 0;
124}
125
126int event_notify_null(enum event_t type)
127{
128 return event_notify(type, NULL, 0);
129}
130
131void event_show_spy_list(void)
132{
133 struct evspy_info *start =
134 ll_entry_start(struct evspy_info, evspy_info);
135 const int n_ents = ll_entry_count(struct evspy_info, evspy_info);
136 struct evspy_info *spy;
137 const int size = sizeof(ulong) * 2;
138
139 printf("Seq %-24s %*s %s\n", "Type", size, "Function", "ID");
140 for (spy = start; spy != start + n_ents; spy++) {
141 printf("%3x %-3x %-20s %*p %s\n", (uint)(spy - start),
142 spy->type, event_type_name(spy->type), size, spy->func,
143 event_spy_id(spy));
144 }
145}
146
147#if CONFIG_IS_ENABLED(EVENT_DYNAMIC)
148static void spy_free(struct event_spy *spy)
149{
150 list_del(&spy->sibling_node);
151}
152
153int event_register(const char *id, enum event_t type, event_handler_t func, void *ctx)
154{
155 struct event_state *state = gd_event_state();
156 struct event_spy *spy;
157
158 if (!CONFIG_IS_ENABLED(EVENT_DYNAMIC))
159 return -ENOSYS;
160 spy = malloc(sizeof(*spy));
161 if (!spy)
162 return log_msg_ret("alloc", -ENOMEM);
163
164 spy->id = id;
165 spy->type = type;
166 spy->func = func;
167 spy->ctx = ctx;
168 list_add_tail(&spy->sibling_node, &state->spy_head);
169
170 return 0;
171}
172
173int event_uninit(void)
174{
175 struct event_state *state = gd_event_state();
176 struct event_spy *spy, *next;
177
178 list_for_each_entry_safe(spy, next, &state->spy_head, sibling_node)
179 spy_free(spy);
180
181 return 0;
182}
183
184int event_init(void)
185{
186 struct event_state *state = gd_event_state();
187
188 INIT_LIST_HEAD(&state->spy_head);
189
190 return 0;
191}
192#endif /* EVENT_DYNAMIC */