diff options
| author | Simon Glass <sjg@chromium.org> | 2023-01-06 08:52:36 -0600 | 
|---|---|---|
| committer | Tom Rini <trini@konsulko.com> | 2023-01-16 18:26:50 -0500 | 
| commit | 87c6f8a4880d849fc4b782d0c43880ef7eb1fe8e (patch) | |
| tree | 708deae4b26ad9ee3da1993e5c256bc6daee3177 /boot | |
| parent | 9e7ac0b0be5cb663e539716554d66f8f0890ca83 (diff) | |
expo: Add basic implementation
An expo is a way of presenting and collecting information from the
user. It consists of a collection of 'scenes' of which only one is
presented at a time. An expo is typically used to show a boot menu
and allow settings to be changed.
One created, the same expo can be automatically presented in graphical
form using a vidconsole, or in text form on a serial console.
Add an initial implementation of the expo itself. Supports for scenes
and objects is provided later.
Signed-off-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'boot')
| -rw-r--r-- | boot/Kconfig | 12 | ||||
| -rw-r--r-- | boot/expo.c | 170 | 
2 files changed, 182 insertions, 0 deletions
| diff --git a/boot/Kconfig b/boot/Kconfig index 30bc182fcd5..36ccbf6b542 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -557,6 +557,18 @@ config VPL_BOOTMETH_VBE_SIMPLE_FW  endif # BOOTMETH_VBE +config EXPO +	bool "Support for expos - groups of scenes displaying a UI" +	default y if BOOTMETH_VBE +	help +	  An expo is a way of presenting and collecting information from the +	  user. It consists of a collection of 'scenes' of which only one is +	  presented at a time. An expo is typically used to show a boot menu +	  and allow settings to be changed. + +	  The expo can be presented in graphics form using a vidconsole, or in +	  text form on a serial console. +  config BOOTMETH_SANDBOX  	def_bool y  	depends on SANDBOX diff --git a/boot/expo.c b/boot/expo.c new file mode 100644 index 00000000000..05950a17603 --- /dev/null +++ b/boot/expo.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Implementation of a expo, a collection of scenes providing menu options + * + * Copyright 2022 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <dm.h> +#include <expo.h> +#include <malloc.h> +#include <video.h> +#include "scene_internal.h" + +int expo_new(const char *name, void *priv, struct expo **expp) +{ +	struct expo *exp; + +	exp = calloc(1, sizeof(struct expo)); +	if (!exp) +		return log_msg_ret("expo", -ENOMEM); +	exp->name = strdup(name); +	if (!exp->name) { +		free(exp); +		return log_msg_ret("name", -ENOMEM); +	} +	exp->priv = priv; +	INIT_LIST_HEAD(&exp->scene_head); +	INIT_LIST_HEAD(&exp->str_head); + +	*expp = exp; + +	return 0; +} + +static void estr_destroy(struct expo_string *estr) +{ +	free(estr); +} + +void expo_destroy(struct expo *exp) +{ +	struct scene *scn, *next; +	struct expo_string *estr, *enext; + +	list_for_each_entry_safe(scn, next, &exp->scene_head, sibling) +		scene_destroy(scn); + +	list_for_each_entry_safe(estr, enext, &exp->str_head, sibling) +		estr_destroy(estr); + +	free(exp->name); +	free(exp); +} + +int expo_str(struct expo *exp, const char *name, uint id, const char *str) +{ +	struct expo_string *estr; + +	estr = calloc(1, sizeof(struct expo_string)); +	if (!estr) +		return log_msg_ret("obj", -ENOMEM); + +	estr->id = resolve_id(exp, id); +	estr->str = str; +	list_add_tail(&estr->sibling, &exp->str_head); + +	return estr->id; +} + +const char *expo_get_str(struct expo *exp, uint id) +{ +	struct expo_string *estr; + +	list_for_each_entry(estr, &exp->str_head, sibling) { +		if (estr->id == id) +			return estr->str; +	} + +	return NULL; +} + +int expo_set_display(struct expo *exp, struct udevice *dev) +{ +	exp->display = dev; + +	return 0; +} + +void exp_set_text_mode(struct expo *exp, bool text_mode) +{ +	exp->text_mode = text_mode; +} + +struct scene *expo_lookup_scene_id(struct expo *exp, uint scene_id) +{ +	struct scene *scn; + +	list_for_each_entry(scn, &exp->scene_head, sibling) { +		if (scn->id == scene_id) +			return scn; +	} + +	return NULL; +} + +int expo_set_scene_id(struct expo *exp, uint scene_id) +{ +	if (!expo_lookup_scene_id(exp, scene_id)) +		return log_msg_ret("id", -ENOENT); +	exp->scene_id = scene_id; + +	return 0; +} + +int expo_render(struct expo *exp) +{ +	struct udevice *dev = exp->display; +	struct video_priv *vid_priv = dev_get_uclass_priv(dev); +	struct scene *scn = NULL; +	u32 colour; +	int ret; + +	colour = video_index_to_colour(vid_priv, VID_WHITE); +	ret = video_fill(dev, colour); +	if (ret) +		return log_msg_ret("fill", ret); + +	if (exp->scene_id) { +		scn = expo_lookup_scene_id(exp, exp->scene_id); +		if (!scn) +			return log_msg_ret("scn", -ENOENT); + +		ret = scene_render(scn); +		if (ret) +			return log_msg_ret("ren", ret); +	} + +	video_sync(dev, true); + +	return scn ? 0 : -ECHILD; +} + +int expo_send_key(struct expo *exp, int key) +{ +	struct scene *scn = NULL; + +	if (exp->scene_id) { +		int ret; + +		scn = expo_lookup_scene_id(exp, exp->scene_id); +		if (!scn) +			return log_msg_ret("scn", -ENOENT); + +		ret = scene_send_key(scn, key, &exp->action); +		if (ret) +			return log_msg_ret("key", ret); +	} + +	return scn ? 0 : -ECHILD; +} + +int expo_action_get(struct expo *exp, struct expo_action *act) +{ +	*act = exp->action; +	exp->action.type = EXPOACT_NONE; + +	return act->type == EXPOACT_NONE ? -EAGAIN : 0; +} | 
