blob: be11cfd4e946597c0439d5821866828dcf05907f [file] [log] [blame]
Simon Glassd8adbe92023-01-06 08:52:36 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Implementation of a expo, a collection of scenes providing menu options
4 *
5 * Copyright 2022 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
Simon Glassfe4c1e22023-06-01 10:22:43 -06009#define LOG_CATEGORY LOGC_EXPO
10
Simon Glassd8adbe92023-01-06 08:52:36 -060011#include <common.h>
12#include <dm.h>
13#include <expo.h>
14#include <malloc.h>
15#include <video.h>
16#include "scene_internal.h"
17
18int expo_new(const char *name, void *priv, struct expo **expp)
19{
20 struct expo *exp;
21
22 exp = calloc(1, sizeof(struct expo));
23 if (!exp)
24 return log_msg_ret("expo", -ENOMEM);
25 exp->name = strdup(name);
26 if (!exp->name) {
27 free(exp);
28 return log_msg_ret("name", -ENOMEM);
29 }
30 exp->priv = priv;
31 INIT_LIST_HEAD(&exp->scene_head);
32 INIT_LIST_HEAD(&exp->str_head);
33
34 *expp = exp;
35
36 return 0;
37}
38
39static void estr_destroy(struct expo_string *estr)
40{
41 free(estr);
42}
43
44void expo_destroy(struct expo *exp)
45{
46 struct scene *scn, *next;
47 struct expo_string *estr, *enext;
48
49 list_for_each_entry_safe(scn, next, &exp->scene_head, sibling)
50 scene_destroy(scn);
51
52 list_for_each_entry_safe(estr, enext, &exp->str_head, sibling)
53 estr_destroy(estr);
54
55 free(exp->name);
56 free(exp);
57}
58
Simon Glass6e9e4152023-06-01 10:22:47 -060059uint resolve_id(struct expo *exp, uint id)
60{
61 if (!id)
62 id = exp->next_id++;
63 else if (id >= exp->next_id)
64 exp->next_id = id + 1;
65
66 return id;
67}
68
69void expo_set_dynamic_start(struct expo *exp, uint dyn_start)
70{
71 exp->next_id = dyn_start;
72}
73
Simon Glassd8adbe92023-01-06 08:52:36 -060074int expo_str(struct expo *exp, const char *name, uint id, const char *str)
75{
76 struct expo_string *estr;
77
78 estr = calloc(1, sizeof(struct expo_string));
79 if (!estr)
80 return log_msg_ret("obj", -ENOMEM);
81
82 estr->id = resolve_id(exp, id);
83 estr->str = str;
84 list_add_tail(&estr->sibling, &exp->str_head);
85
86 return estr->id;
87}
88
89const char *expo_get_str(struct expo *exp, uint id)
90{
91 struct expo_string *estr;
92
93 list_for_each_entry(estr, &exp->str_head, sibling) {
94 if (estr->id == id)
95 return estr->str;
96 }
97
98 return NULL;
99}
100
101int expo_set_display(struct expo *exp, struct udevice *dev)
102{
Simon Glass67e2af12023-06-01 10:22:34 -0600103 struct udevice *cons;
104 int ret;
105
106 ret = device_find_first_child_by_uclass(dev, UCLASS_VIDEO_CONSOLE,
107 &cons);
108 if (ret)
109 return log_msg_ret("con", ret);
110
Simon Glassd8adbe92023-01-06 08:52:36 -0600111 exp->display = dev;
Simon Glass67e2af12023-06-01 10:22:34 -0600112 exp->cons = cons;
Simon Glassd8adbe92023-01-06 08:52:36 -0600113
114 return 0;
115}
116
Simon Glassb2c40342023-06-01 10:22:37 -0600117void expo_set_text_mode(struct expo *exp, bool text_mode)
Simon Glassd8adbe92023-01-06 08:52:36 -0600118{
119 exp->text_mode = text_mode;
120}
121
122struct scene *expo_lookup_scene_id(struct expo *exp, uint scene_id)
123{
124 struct scene *scn;
125
126 list_for_each_entry(scn, &exp->scene_head, sibling) {
127 if (scn->id == scene_id)
128 return scn;
129 }
130
131 return NULL;
132}
133
134int expo_set_scene_id(struct expo *exp, uint scene_id)
135{
Simon Glassd7e32a82023-06-01 10:22:35 -0600136 struct scene *scn;
137 int ret;
138
139 scn = expo_lookup_scene_id(exp, scene_id);
140 if (!scn)
Simon Glassd8adbe92023-01-06 08:52:36 -0600141 return log_msg_ret("id", -ENOENT);
Simon Glassd7e32a82023-06-01 10:22:35 -0600142 ret = scene_arrange(scn);
143 if (ret)
144 return log_msg_ret("arr", ret);
145
Simon Glassd8adbe92023-01-06 08:52:36 -0600146 exp->scene_id = scene_id;
147
148 return 0;
149}
150
151int expo_render(struct expo *exp)
152{
153 struct udevice *dev = exp->display;
154 struct video_priv *vid_priv = dev_get_uclass_priv(dev);
155 struct scene *scn = NULL;
156 u32 colour;
157 int ret;
158
159 colour = video_index_to_colour(vid_priv, VID_WHITE);
160 ret = video_fill(dev, colour);
161 if (ret)
162 return log_msg_ret("fill", ret);
163
164 if (exp->scene_id) {
165 scn = expo_lookup_scene_id(exp, exp->scene_id);
166 if (!scn)
167 return log_msg_ret("scn", -ENOENT);
168
169 ret = scene_render(scn);
170 if (ret)
171 return log_msg_ret("ren", ret);
172 }
173
174 video_sync(dev, true);
175
176 return scn ? 0 : -ECHILD;
177}
178
179int expo_send_key(struct expo *exp, int key)
180{
181 struct scene *scn = NULL;
182
183 if (exp->scene_id) {
184 int ret;
185
186 scn = expo_lookup_scene_id(exp, exp->scene_id);
187 if (!scn)
188 return log_msg_ret("scn", -ENOENT);
189
190 ret = scene_send_key(scn, key, &exp->action);
191 if (ret)
192 return log_msg_ret("key", ret);
Simon Glassd7e32a82023-06-01 10:22:35 -0600193
194 /* arrange it to get any changes */
195 ret = scene_arrange(scn);
196 if (ret)
197 return log_msg_ret("arr", ret);
Simon Glassd8adbe92023-01-06 08:52:36 -0600198 }
199
200 return scn ? 0 : -ECHILD;
201}
202
203int expo_action_get(struct expo *exp, struct expo_action *act)
204{
205 *act = exp->action;
206 exp->action.type = EXPOACT_NONE;
207
208 return act->type == EXPOACT_NONE ? -EAGAIN : 0;
209}