blob: 05950a1760383d86536803a79a4fe5ca948454b9 [file] [log] [blame]
Simon Glass87c6f8a2023-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
9#include <common.h>
10#include <dm.h>
11#include <expo.h>
12#include <malloc.h>
13#include <video.h>
14#include "scene_internal.h"
15
16int expo_new(const char *name, void *priv, struct expo **expp)
17{
18 struct expo *exp;
19
20 exp = calloc(1, sizeof(struct expo));
21 if (!exp)
22 return log_msg_ret("expo", -ENOMEM);
23 exp->name = strdup(name);
24 if (!exp->name) {
25 free(exp);
26 return log_msg_ret("name", -ENOMEM);
27 }
28 exp->priv = priv;
29 INIT_LIST_HEAD(&exp->scene_head);
30 INIT_LIST_HEAD(&exp->str_head);
31
32 *expp = exp;
33
34 return 0;
35}
36
37static void estr_destroy(struct expo_string *estr)
38{
39 free(estr);
40}
41
42void expo_destroy(struct expo *exp)
43{
44 struct scene *scn, *next;
45 struct expo_string *estr, *enext;
46
47 list_for_each_entry_safe(scn, next, &exp->scene_head, sibling)
48 scene_destroy(scn);
49
50 list_for_each_entry_safe(estr, enext, &exp->str_head, sibling)
51 estr_destroy(estr);
52
53 free(exp->name);
54 free(exp);
55}
56
57int expo_str(struct expo *exp, const char *name, uint id, const char *str)
58{
59 struct expo_string *estr;
60
61 estr = calloc(1, sizeof(struct expo_string));
62 if (!estr)
63 return log_msg_ret("obj", -ENOMEM);
64
65 estr->id = resolve_id(exp, id);
66 estr->str = str;
67 list_add_tail(&estr->sibling, &exp->str_head);
68
69 return estr->id;
70}
71
72const char *expo_get_str(struct expo *exp, uint id)
73{
74 struct expo_string *estr;
75
76 list_for_each_entry(estr, &exp->str_head, sibling) {
77 if (estr->id == id)
78 return estr->str;
79 }
80
81 return NULL;
82}
83
84int expo_set_display(struct expo *exp, struct udevice *dev)
85{
86 exp->display = dev;
87
88 return 0;
89}
90
91void exp_set_text_mode(struct expo *exp, bool text_mode)
92{
93 exp->text_mode = text_mode;
94}
95
96struct scene *expo_lookup_scene_id(struct expo *exp, uint scene_id)
97{
98 struct scene *scn;
99
100 list_for_each_entry(scn, &exp->scene_head, sibling) {
101 if (scn->id == scene_id)
102 return scn;
103 }
104
105 return NULL;
106}
107
108int expo_set_scene_id(struct expo *exp, uint scene_id)
109{
110 if (!expo_lookup_scene_id(exp, scene_id))
111 return log_msg_ret("id", -ENOENT);
112 exp->scene_id = scene_id;
113
114 return 0;
115}
116
117int expo_render(struct expo *exp)
118{
119 struct udevice *dev = exp->display;
120 struct video_priv *vid_priv = dev_get_uclass_priv(dev);
121 struct scene *scn = NULL;
122 u32 colour;
123 int ret;
124
125 colour = video_index_to_colour(vid_priv, VID_WHITE);
126 ret = video_fill(dev, colour);
127 if (ret)
128 return log_msg_ret("fill", ret);
129
130 if (exp->scene_id) {
131 scn = expo_lookup_scene_id(exp, exp->scene_id);
132 if (!scn)
133 return log_msg_ret("scn", -ENOENT);
134
135 ret = scene_render(scn);
136 if (ret)
137 return log_msg_ret("ren", ret);
138 }
139
140 video_sync(dev, true);
141
142 return scn ? 0 : -ECHILD;
143}
144
145int expo_send_key(struct expo *exp, int key)
146{
147 struct scene *scn = NULL;
148
149 if (exp->scene_id) {
150 int ret;
151
152 scn = expo_lookup_scene_id(exp, exp->scene_id);
153 if (!scn)
154 return log_msg_ret("scn", -ENOENT);
155
156 ret = scene_send_key(scn, key, &exp->action);
157 if (ret)
158 return log_msg_ret("key", ret);
159 }
160
161 return scn ? 0 : -ECHILD;
162}
163
164int expo_action_get(struct expo *exp, struct expo_action *act)
165{
166 *act = exp->action;
167 exp->action.type = EXPOACT_NONE;
168
169 return act->type == EXPOACT_NONE ? -EAGAIN : 0;
170}