expo: cedit: Support writing settings to a file

Support writing settings from an expo into a file in FDT format. It
consists of a single node with a two properties for each sceneitem,
one with tag ID chosen by the user and another for its text value.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2023-08-14 16:40:33 -06:00 committed by Tom Rini
parent 6e648fa781
commit 2dee81fe5f
5 changed files with 270 additions and 3 deletions

View File

@ -9,6 +9,7 @@
#define LOG_CATEGORY LOGC_EXPO #define LOG_CATEGORY LOGC_EXPO
#include <common.h> #include <common.h>
#include <abuf.h>
#include <cedit.h> #include <cedit.h>
#include <cli.h> #include <cli.h>
#include <dm.h> #include <dm.h>
@ -18,6 +19,15 @@
#include <linux/delay.h> #include <linux/delay.h>
#include "scene_internal.h" #include "scene_internal.h"
/**
* struct cedit_iter_priv - private data for cedit operations
*
* @buf: Buffer to use when writing settings to the devicetree
*/
struct cedit_iter_priv {
struct abuf *buf;
};
int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id) int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
{ {
struct scene_obj_txt *txt; struct scene_obj_txt *txt;
@ -182,3 +192,129 @@ int cedit_run(struct expo *exp)
return 0; return 0;
} }
static int check_space(int ret, struct abuf *buf)
{
if (ret == -FDT_ERR_NOSPACE) {
if (!abuf_realloc_inc(buf, CEDIT_SIZE_INC))
return log_msg_ret("spc", -ENOMEM);
ret = fdt_resize(abuf_data(buf), abuf_data(buf),
abuf_size(buf));
if (ret)
return log_msg_ret("res", -EFAULT);
}
return 0;
}
static int h_write_settings(struct scene_obj *obj, void *vpriv)
{
struct cedit_iter_priv *priv = vpriv;
struct abuf *buf = priv->buf;
switch (obj->type) {
case SCENEOBJT_NONE:
case SCENEOBJT_IMAGE:
case SCENEOBJT_TEXT:
break;
case SCENEOBJT_MENU: {
const struct scene_obj_menu *menu;
const struct scene_obj_txt *txt;
struct scene *scn = obj->scene;
const struct scene_menitem *mi;
const char *str;
char name[80];
int ret, i;
menu = (struct scene_obj_menu *)obj;
ret = -EAGAIN;
for (i = 0; ret && i < 2; i++) {
ret = fdt_property_u32(abuf_data(buf), obj->name,
menu->cur_item_id);
if (!i) {
ret = check_space(ret, buf);
if (ret)
return log_msg_ret("res", -ENOMEM);
}
}
/* this should not happen */
if (ret)
return log_msg_ret("wrt", -EFAULT);
mi = scene_menuitem_find(menu, menu->cur_item_id);
if (!mi)
return log_msg_ret("mi", -ENOENT);
txt = scene_obj_find(scn, mi->label_id, SCENEOBJT_TEXT);
if (!txt)
return log_msg_ret("txt", -ENOENT);
str = expo_get_str(scn->expo, txt->str_id);
if (!str)
return log_msg_ret("str", -ENOENT);
snprintf(name, sizeof(name), "%s-str", obj->name);
ret = -EAGAIN;
for (i = 0; ret && i < 2; i++) {
ret = fdt_property_string(abuf_data(buf), name, str);
if (!i) {
ret = check_space(ret, buf);
if (ret)
return log_msg_ret("rs2", -ENOMEM);
}
}
/* this should not happen */
if (ret)
return log_msg_ret("wr2", -EFAULT);
break;
}
}
return 0;
}
int cedit_write_settings(struct expo *exp, struct abuf *buf)
{
struct cedit_iter_priv priv;
void *fdt;
int ret;
abuf_init(buf);
if (!abuf_realloc(buf, CEDIT_SIZE_INC))
return log_msg_ret("buf", -ENOMEM);
fdt = abuf_data(buf);
ret = fdt_create(fdt, abuf_size(buf));
if (!ret)
ret = fdt_finish_reservemap(fdt);
if (!ret)
ret = fdt_begin_node(fdt, "");
if (!ret)
ret = fdt_begin_node(fdt, CEDIT_NODE_NAME);
if (ret) {
log_debug("Failed to start FDT (err=%d)\n", ret);
return log_msg_ret("sta", -EINVAL);
}
/* write out the items */
priv.buf = buf;
ret = expo_iter_scene_objs(exp, h_write_settings, &priv);
if (ret) {
log_debug("Failed to write settings (err=%d)\n", ret);
return log_msg_ret("set", ret);
}
ret = fdt_end_node(fdt);
if (!ret)
ret = fdt_end_node(fdt);
if (!ret)
ret = fdt_finish(fdt);
if (ret) {
log_debug("Failed to finish FDT (err=%d)\n", ret);
return log_msg_ret("fin", -EINVAL);
}
return 0;
}

View File

@ -7,15 +7,28 @@
*/ */
#include <common.h> #include <common.h>
#include <abuf.h>
#include <cedit.h> #include <cedit.h>
#include <command.h> #include <command.h>
#include <expo.h> #include <expo.h>
#include <fs.h> #include <fs.h>
#include <malloc.h>
#include <mapmem.h>
#include <dm/ofnode.h> #include <dm/ofnode.h>
#include <linux/sizes.h> #include <linux/sizes.h>
struct expo *cur_exp; struct expo *cur_exp;
static int check_cur_expo(void)
{
if (!cur_exp) {
printf("No expo loaded\n");
return -ENOENT;
}
return 0;
}
static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc, static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]) char *const argv[])
{ {
@ -54,16 +67,46 @@ static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc,
return 0; return 0;
} }
static int do_cedit_write_fdt(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
const char *fname;
struct abuf buf;
loff_t bytes;
int ret;
if (argc < 4)
return CMD_RET_USAGE;
fname = argv[3];
if (check_cur_expo())
return CMD_RET_FAILURE;
ret = cedit_write_settings(cur_exp, &buf);
if (ret) {
printf("Failed to write settings: %dE\n", ret);
return CMD_RET_FAILURE;
}
if (fs_set_blk_dev(argv[1], argv[2], FS_TYPE_ANY))
return CMD_RET_FAILURE;
ret = fs_write(fname, map_to_sysmem(abuf_data(&buf)), 0,
abuf_size(&buf), &bytes);
if (ret)
return CMD_RET_FAILURE;
return 0;
}
static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[]) char *const argv[])
{ {
ofnode node; ofnode node;
int ret; int ret;
if (!cur_exp) { if (check_cur_expo())
printf("No expo loaded\n");
return CMD_RET_FAILURE; return CMD_RET_FAILURE;
}
node = ofnode_path("/bootstd/cedit-theme"); node = ofnode_path("/bootstd/cedit-theme");
if (ofnode_valid(node)) { if (ofnode_valid(node)) {
@ -85,10 +128,12 @@ static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc,
#ifdef CONFIG_SYS_LONGHELP #ifdef CONFIG_SYS_LONGHELP
static char cedit_help_text[] = static char cedit_help_text[] =
"load <interface> <dev[:part]> <filename> - load config editor\n" "load <interface> <dev[:part]> <filename> - load config editor\n"
"cedit write_fdt <i/f> <dev[:part]> <filename> - write settings\n"
"cedit run - run config editor"; "cedit run - run config editor";
#endif /* CONFIG_SYS_LONGHELP */ #endif /* CONFIG_SYS_LONGHELP */
U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text,
U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load), U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load),
U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt),
U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run), U_BOOT_SUBCMD_MKENT(run, 1, 1, do_cedit_run),
); );

View File

@ -10,6 +10,7 @@ Synopis
cedit load <interface> <dev[:part]> <filename> cedit load <interface> <dev[:part]> <filename>
cedit run cedit run
cedit write_fdt <dev[:part]> <filename>
Description Description
----------- -----------
@ -38,6 +39,12 @@ Runs the default configuration-editor event loop. This is very simple, just
accepting character input and moving through the objects under user control. accepting character input and moving through the objects under user control.
The implementation is at `cedit_run()`. The implementation is at `cedit_run()`.
cedit write_fdt
~~~~~~~~~~~~~~~
Writes the current user settings to a devicetree file. For each menu item the
selected ID and its text string are written.
Example Example
------- -------
@ -46,3 +53,15 @@ Example
=> cedit load hostfs - fred.dtb => cedit load hostfs - fred.dtb
=> cedit run => cedit run
=> cedit write_fdt hostfs - settings.dtb
That results in::
/ {
cedit-values {
cpu-speed = <0x00000006>;
cpu-speed-str = "2 GHz";
power-loss = <0x0000000a>;
power-loss-str = "Always Off";
};
}

View File

@ -7,10 +7,21 @@
#ifndef __CEDIT_H #ifndef __CEDIT_H
#define __CEDIT_H #define __CEDIT_H
struct abuf;
struct expo; struct expo;
struct scene; struct scene;
struct video_priv; struct video_priv;
enum {
/* size increment for writing FDT */
CEDIT_SIZE_INC = 1024,
};
/* Name of the cedit node in the devicetree */
#define CEDIT_NODE_NAME "cedit-values"
extern struct expo *cur_exp;
/** /**
* cedit_arange() - Arrange objects in a configuration-editor scene * cedit_arange() - Arrange objects in a configuration-editor scene
* *
@ -45,4 +56,15 @@ int cedit_run(struct expo *exp);
int cedit_prepare(struct expo *exp, struct video_priv **vid_privp, int cedit_prepare(struct expo *exp, struct video_priv **vid_privp,
struct scene **scnp); struct scene **scnp);
/**
* cedit_write_settings() - Write settings in FDT format
*
* Sets up an FDT with the settings
*
* @exp: Expo to write settings from
* @buf: Returns abuf containing the settings FDT (inited by this function)
* Return: 0 if OK, -ve on error
*/
int cedit_write_settings(struct expo *exp, struct abuf *buf);
#endif /* __CEDIT_H */ #endif /* __CEDIT_H */

View File

@ -7,6 +7,8 @@
#include <common.h> #include <common.h>
#include <cedit.h> #include <cedit.h>
#include <expo.h> #include <expo.h>
#include <mapmem.h>
#include <dm/ofnode.h>
#include <test/ut.h> #include <test/ut.h>
#include "bootstd_common.h" #include "bootstd_common.h"
#include <test/cedit-test.h> #include <test/cedit-test.h>
@ -51,3 +53,46 @@ static int cedit_base(struct unit_test_state *uts)
return 0; return 0;
} }
BOOTSTD_TEST(cedit_base, 0); BOOTSTD_TEST(cedit_base, 0);
/* Check the cedit write_fdt commands */
static int cedit_fdt(struct unit_test_state *uts)
{
struct video_priv *vid_priv;
extern struct expo *cur_exp;
ulong addr = 0x1000;
struct ofprop prop;
struct scene *scn;
oftree tree;
ofnode node;
void *fdt;
int i;
console_record_reset_enable();
ut_assertok(run_command("cedit load hostfs - cedit.dtb", 0));
ut_asserteq(ID_SCENE1, cedit_prepare(cur_exp, &vid_priv, &scn));
ut_assertok(run_command("cedit write_fdt hostfs - settings.dtb", 0));
ut_assertok(run_commandf("load hostfs - %lx settings.dtb", addr));
ut_assert_nextlinen("1024 bytes read");
fdt = map_sysmem(addr, 1024);
tree = oftree_from_fdt(fdt);
node = ofnode_find_subnode(oftree_root(tree), CEDIT_NODE_NAME);
ut_asserteq(ID_CPU_SPEED_1,
ofnode_read_u32_default(node, "cpu-speed", 0));
ut_asserteq_str("2 GHz", ofnode_read_string(node, "cpu-speed-str"));
ut_assert(ofnode_valid(node));
/* There should only be 4 properties */
for (i = 0, ofnode_first_property(node, &prop); ofprop_valid(&prop);
i++, ofnode_next_property(&prop))
;
ut_asserteq(4, i);
ut_assert_console_end();
return 0;
}
BOOTSTD_TEST(cedit_fdt, 0);