1 // 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 
expo_new(const char * name,void * priv,struct expo ** expp)16 int 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 
estr_destroy(struct expo_string * estr)37 static void estr_destroy(struct expo_string *estr)
38 {
39 	free(estr);
40 }
41 
expo_destroy(struct expo * exp)42 void 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 
expo_str(struct expo * exp,const char * name,uint id,const char * str)57 int 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 
expo_get_str(struct expo * exp,uint id)72 const 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 
expo_set_display(struct expo * exp,struct udevice * dev)84 int expo_set_display(struct expo *exp, struct udevice *dev)
85 {
86 	exp->display = dev;
87 
88 	return 0;
89 }
90 
exp_set_text_mode(struct expo * exp,bool text_mode)91 void exp_set_text_mode(struct expo *exp, bool text_mode)
92 {
93 	exp->text_mode = text_mode;
94 }
95 
expo_lookup_scene_id(struct expo * exp,uint scene_id)96 struct 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 
expo_set_scene_id(struct expo * exp,uint scene_id)108 int 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 
expo_render(struct expo * exp)117 int 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 
expo_send_key(struct expo * exp,int key)145 int 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 
expo_action_get(struct expo * exp,struct expo_action * act)164 int 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 }
171