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