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