]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
expo: Add a configuration editor
authorSimon Glass <sjg@chromium.org>
Thu, 1 Jun 2023 16:23:02 +0000 (10:23 -0600)
committerTom Rini <trini@konsulko.com>
Fri, 14 Jul 2023 16:54:51 +0000 (12:54 -0400)
Add a new 'cedit' command which allows editing configuration using an
expo. The configuration items appear as menus on the display.

This is extremely basic, only supporting menus and not providing any way
to load or save the configuration.

Signed-off-by: Simon Glass <sjg@chromium.org>
14 files changed:
boot/Kconfig
boot/Makefile
boot/cedit.c [new file with mode: 0644]
boot/expo_build.c
boot/scene.c
boot/scene_internal.h
cmd/Kconfig
cmd/Makefile
cmd/cedit.c [new file with mode: 0644]
configs/sandbox_defconfig
doc/develop/expo.rst
doc/usage/cmd/cedit.rst [new file with mode: 0644]
doc/usage/index.rst
include/expo.h

index a643a3d128637f186878e0f721b500fd169b54fb..c8b8f36d83586dfc20ac9c72f9e6e6d75c1aa512 100644 (file)
@@ -1630,4 +1630,18 @@ config SAVE_PREV_BL_INITRAMFS_START_ADDR
          If no initramfs was provided by previous bootloader, no env variables
          will be created.
 
+menu "Configuration editor"
+
+config CEDIT
+       bool "Configuration editor"
+       depends on BOOTSTD
+       help
+         Provides a way to deal with board configuration and present it to
+         the user for adjustment.
+
+         This is intended to provide both graphical and text-based user
+         interfaces, but only graphical is support at present.
+
+endmenu                # Configuration editor
+
 endmenu                # Booting
index 28c4e55ca656f1a3821e0b104e18cb701c58246c..f828f870a37b023e4de2391c7d2a334ce7caa456 100644 (file)
@@ -33,6 +33,7 @@ ifdef CONFIG_$(SPL_TPL_)BOOTSTD_FULL
 obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += bootmeth_efi_mgr.o
 obj-$(CONFIG_$(SPL_TPL_)EXPO) += bootflow_menu.o
 obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootflow_menu.o
+obj-$(CONFIG_$(SPL_TPL_)CEDIT) += cedit.o
 endif
 
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
diff --git a/boot/cedit.c b/boot/cedit.c
new file mode 100644 (file)
index 0000000..ee24658
--- /dev/null
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Implementation of configuration editor
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <cli.h>
+#include <dm.h>
+#include <expo.h>
+#include <menu.h>
+#include <video.h>
+#include <linux/delay.h>
+#include "scene_internal.h"
+
+int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
+{
+       struct scene_obj_txt *txt;
+       struct scene_obj *obj;
+       struct scene *scn;
+       int y;
+
+       scn = expo_lookup_scene_id(exp, scene_id);
+       if (!scn)
+               return log_msg_ret("scn", -ENOENT);
+
+       txt = scene_obj_find_by_name(scn, "prompt");
+       if (txt)
+               scene_obj_set_pos(scn, txt->obj.id, 0, vpriv->ysize - 50);
+
+       txt = scene_obj_find_by_name(scn, "title");
+       if (txt)
+               scene_obj_set_pos(scn, txt->obj.id, 200, 10);
+
+       y = 100;
+       list_for_each_entry(obj, &scn->obj_head, sibling) {
+               if (obj->type == SCENEOBJT_MENU) {
+                       scene_obj_set_pos(scn, obj->id, 50, y);
+                       scene_menu_arrange(scn, (struct scene_obj_menu *)obj);
+                       y += 50;
+               }
+       }
+
+       return 0;
+}
+
+int cedit_run(struct expo *exp)
+{
+       struct cli_ch_state s_cch, *cch = &s_cch;
+       struct video_priv *vid_priv;
+       uint scene_id;
+       struct udevice *dev;
+       struct scene *scn;
+       bool done;
+       int ret;
+
+       cli_ch_init(cch);
+
+       /* For now we only support a video console */
+       ret = uclass_first_device_err(UCLASS_VIDEO, &dev);
+       if (ret)
+               return log_msg_ret("vid", ret);
+       ret = expo_set_display(exp, dev);
+       if (ret)
+               return log_msg_ret("dis", ret);
+
+       ret = expo_first_scene_id(exp);
+       if (ret < 0)
+               return log_msg_ret("scn", ret);
+       scene_id = ret;
+
+       ret = expo_set_scene_id(exp, scene_id);
+       if (ret)
+               return log_msg_ret("sid", ret);
+
+       exp->popup = true;
+
+       /* This is not supported for now */
+       if (0)
+               expo_set_text_mode(exp, true);
+
+       vid_priv = dev_get_uclass_priv(dev);
+
+       scn = expo_lookup_scene_id(exp, scene_id);
+       scene_highlight_first(scn);
+
+       cedit_arange(exp, vid_priv, scene_id);
+
+       ret = expo_calc_dims(exp);
+       if (ret)
+               return log_msg_ret("dim", ret);
+
+       done = false;
+       do {
+               struct expo_action act;
+               int ichar, key;
+
+               ret = expo_render(exp);
+               if (ret)
+                       break;
+
+               ichar = cli_ch_process(cch, 0);
+               if (!ichar) {
+                       while (!ichar && !tstc()) {
+                               schedule();
+                               mdelay(2);
+                               ichar = cli_ch_process(cch, -ETIMEDOUT);
+                       }
+                       if (!ichar) {
+                               ichar = getchar();
+                               ichar = cli_ch_process(cch, ichar);
+                       }
+               }
+
+               key = 0;
+               if (ichar) {
+                       key = bootmenu_conv_key(ichar);
+                       if (key == BKEY_NONE)
+                               key = ichar;
+               }
+               if (!key)
+                       continue;
+
+               ret = expo_send_key(exp, key);
+               if (ret)
+                       break;
+
+               ret = expo_action_get(exp, &act);
+               if (!ret) {
+                       switch (act.type) {
+                       case EXPOACT_POINT_OBJ:
+                               scene_set_highlight_id(scn, act.select.id);
+                               cedit_arange(exp, vid_priv, scene_id);
+                               break;
+                       case EXPOACT_OPEN:
+                               scene_set_open(scn, act.select.id, true);
+                               cedit_arange(exp, vid_priv, scene_id);
+                               break;
+                       case EXPOACT_CLOSE:
+                               scene_set_open(scn, act.select.id, false);
+                               cedit_arange(exp, vid_priv, scene_id);
+                               break;
+                       case EXPOACT_SELECT:
+                               scene_set_open(scn, scn->highlight_id, false);
+                               cedit_arange(exp, vid_priv, scene_id);
+                               break;
+                       case EXPOACT_QUIT:
+                               log_debug("quitting\n");
+                               done = true;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       } while (!done);
+
+       if (ret)
+               return log_msg_ret("end", ret);
+
+       return 0;
+}
index 7e61ab06a8dabf6499cd842c8e382f40abeed1d8..22f62eb54bc536edc77d0d8386f8d326509ad584 100644 (file)
@@ -376,7 +376,8 @@ int expo_build(ofnode root, struct expo **expp)
        ret = read_strings(&info, root);
        if (ret)
                return log_msg_ret("str", ret);
-       list_strings(&info);
+       if (_DEBUG)
+               list_strings(&info);
 
        ret = expo_new("name", NULL, &exp);
        if (ret)
index 6fbc1fc578c2a748ba5508e7ba10143215154a82..e52333371f9cbc34a714599ccd64eb8e13a660d0 100644 (file)
@@ -92,6 +92,18 @@ void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type)
        return NULL;
 }
 
+void *scene_obj_find_by_name(struct scene *scn, const char *name)
+{
+       struct scene_obj *obj;
+
+       list_for_each_entry(obj, &scn->obj_head, sibling) {
+               if (!strcmp(name, obj->name))
+                       return obj;
+       }
+
+       return NULL;
+}
+
 int scene_obj_add(struct scene *scn, const char *name, uint id,
                  enum scene_obj_t type, uint size, struct scene_obj **objp)
 {
index dc98ecd02146f4611137dedea6cf6c163445c8bf..fb1ea5533b9ae6b3c4f7a2041633554a0bc7f043 100644 (file)
@@ -40,6 +40,14 @@ uint resolve_id(struct expo *exp, uint id);
  */
 void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type);
 
+/**
+ * scene_obj_find_by_name() - Find an object in a scene by name
+ *
+ * @scn: Scene to search
+ * @name: Name to search for
+ */
+void *scene_obj_find_by_name(struct scene *scn, const char *name);
+
 /**
  * scene_obj_add() - Add a new object to a scene
  *
index c1941849f98bb392d1dbfbfbda06b59e40a7744e..f6b10e01f848111394bdffa494124bb868cb280b 100644 (file)
@@ -428,6 +428,15 @@ config CMD_ABOOTIMG
 
          See doc/android/boot-image.rst for details.
 
+config CMD_CEDIT
+       bool "cedit - Configuration editor"
+       depends on CEDIT
+       default y
+       help
+         Provides a command to allow editing of board configuration and
+         providing a UI for the user to adjust settings. Subcommands allow
+         loading and saving of configuration as well as showing an editor.
+
 config CMD_ELF
        bool "bootelf, bootvx"
        default y
index 6c37521b4e2b1742c9e92a911b36afcfb2bab61c..9f8c0b058beae4dba57777393d7f20988732e154 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_CMD_BUTTON) += button.o
 obj-$(CONFIG_CMD_CAT) += cat.o
 obj-$(CONFIG_CMD_CACHE) += cache.o
 obj-$(CONFIG_CMD_CBFS) += cbfs.o
+obj-$(CONFIG_CMD_CEDIT) += cedit.o
 obj-$(CONFIG_CMD_CLK) += clk.o
 obj-$(CONFIG_CMD_CLS) += cls.o
 obj-$(CONFIG_CMD_CONFIG) += config.o
diff --git a/cmd/cedit.c b/cmd/cedit.c
new file mode 100644 (file)
index 0000000..0cae304
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * 'cedit' command
+ *
+ * Copyright 2023 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <expo.h>
+#include <fs.h>
+#include <dm/ofnode.h>
+#include <linux/sizes.h>
+
+struct expo *cur_exp;
+
+static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc,
+                        char *const argv[])
+{
+       const char *fname;
+       struct expo *exp;
+       oftree tree;
+       ulong size;
+       void *buf;
+       int ret;
+
+       if (argc < 4)
+               return CMD_RET_USAGE;
+       fname = argv[3];
+
+       ret = fs_load_alloc(argv[1], argv[2], argv[3], SZ_1M, 0, &buf, &size);
+       if (ret) {
+               printf("File not found\n");
+               return CMD_RET_FAILURE;
+       }
+
+       tree = oftree_from_fdt(buf);
+       if (!oftree_valid(tree)) {
+               printf("Cannot create oftree\n");
+               return CMD_RET_FAILURE;
+       }
+
+       ret = expo_build(oftree_root(tree), &exp);
+       oftree_dispose(tree);
+       if (ret) {
+               printf("Failed to build expo: %dE\n", ret);
+               return CMD_RET_FAILURE;
+       }
+
+       cur_exp = exp;
+
+       return 0;
+}
+
+static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc,
+                       char *const argv[])
+{
+       ofnode node;
+       int ret;
+
+       if (!cur_exp) {
+               printf("No expo loaded\n");
+               return CMD_RET_FAILURE;
+       }
+
+       node = ofnode_path("/cedit-theme");
+       if (ofnode_valid(node)) {
+               ret = expo_apply_theme(cur_exp, node);
+               if (ret)
+                       return CMD_RET_FAILURE;
+       } else {
+               log_warning("No theme found\n");
+       }
+       ret = cedit_run(cur_exp);
+       if (ret) {
+               log_err("Failed (err=%dE)\n", ret);
+               return CMD_RET_FAILURE;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char cedit_help_text[] =
+       "load <interface> <dev[:part]> <filename>   - load config editor\n"
+       "cedit run                                        - run config editor";
+#endif /* CONFIG_SYS_LONGHELP */
+
+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(run, 1, 1, do_cedit_run),
+);
index 1ec44d5b33bb714394621657e9b596348096c66b..4cef6c515396eb9a5a9a2721344aa0e4a3623fbf 100644 (file)
@@ -30,6 +30,7 @@ CONFIG_AUTOBOOT_STOP_STR_ENABLE=y
 CONFIG_AUTOBOOT_STOP_STR_CRYPT="$5$rounds=640000$HrpE65IkB8CM5nCL$BKT3QdF98Bo8fJpTr9tjZLZQyzqPASBY20xuK5Rent9"
 CONFIG_IMAGE_PRE_LOAD=y
 CONFIG_IMAGE_PRE_LOAD_SIG=y
+CONFIG_CEDIT=y
 CONFIG_CONSOLE_RECORD=y
 CONFIG_CONSOLE_RECORD_OUT_SIZE=0x6000
 CONFIG_PRE_CONSOLE_BUFFER=y
index f5caadbfd98c7061e456b5883de09eb1096cf99d..2ac4af232da46dba3b1048af685e6b419cef193a 100644 (file)
@@ -171,8 +171,6 @@ menu-inset
 menuitem-gap-y
     Number of pixels between menu items
 
-.. _expo_format:
-
 Pop-up mode
 -----------
 
@@ -202,6 +200,8 @@ just as its title and label, as with the `CPU Speed` and `AC Power` menus here::
      UP and DOWN to choose, ENTER to select
 
 
+.. _expo_format:
+
 Expo Format
 -----------
 
@@ -211,7 +211,8 @@ makes it easier and faster to create and edit the description. An expo builder
 is provided to convert this format into an expo structure.
 
 Layout of the expo scenes is handled automatically, based on a set of simple
-rules.
+rules. The :doc:`../usage/cmd/cedit` can be used to load a configuration
+and create an expo from it.
 
 Top-level node
 ~~~~~~~~~~~~~~
@@ -464,6 +465,7 @@ Some ideas for future work:
 - Support unicode
 - Support curses for proper serial-terminal menus
 - Add support for large menus which need to scroll
+- Add support for reading and writing configuration settings with cedit
 
 .. Simon Glass <sjg@chromium.org>
 .. 7-Oct-22
diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst
new file mode 100644 (file)
index 0000000..8e1110c
--- /dev/null
@@ -0,0 +1,31 @@
+.. SPDX-License-Identifier: GPL-2.0+:
+
+cedit command
+=============
+
+Synopis
+-------
+
+::
+
+    cedit load <interface> <dev[:part]> <filename>
+    cedit run
+
+Description
+-----------
+
+The *cedit* command is used to load a configuration-editor description and allow
+the user to interact with it.
+
+It makes use of the expo subsystem.
+
+The description is in the form of a devicetree file, as documented at
+:ref:`expo_format`.
+
+Example
+-------
+
+::
+
+    => cedit load hostfs - fred.dtb
+    => cedit run
index 388e59f1733300039de503552d492b737ca3b833..f2ffd2787aa85284f030cff74c421692ed17e386 100644 (file)
@@ -39,6 +39,7 @@ Shell commands
    cmd/bootz
    cmd/cat
    cmd/cbsysinfo
+   cmd/cedit
    cmd/cls
    cmd/cmp
    cmd/coninfo
index 9fec4d0cd84ea8d99a1d907a606a4c974403095c..0b1d944a169f47980c2df1122a449b730c90830f 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/list.h>
 
 struct udevice;
+struct video_priv;
 
 /**
  * enum expoact_type - types of actions reported by the expo
@@ -378,6 +379,14 @@ int expo_calc_dims(struct expo *exp);
  */
 int expo_set_scene_id(struct expo *exp, uint scene_id);
 
+/**
+ * expo_first_scene_id() - Get the ID of the first scene
+ *
+ * @exp: Expo to check
+ * Returns: Scene ID of first scene, or -ENOENT if there are no scenes
+ */
+int expo_first_scene_id(struct expo *exp);
+
 /**
  * expo_render() - render the expo on the display / console
  *
@@ -667,4 +676,24 @@ int expo_apply_theme(struct expo *exp, ofnode node);
  */
 int expo_build(ofnode root, struct expo **expp);
 
+/**
+ * cedit_arange() - Arrange objects in a configuration-editor scene
+ *
+ * @exp: Expo to update
+ * @vid_priv: Private info of the video device
+ * @scene_id: scene ID to arrange
+ * Returns: 0 if OK, -ve on error
+ */
+int cedit_arange(struct expo *exp, struct video_priv *vid_priv, uint scene_id);
+
+/**
+ * cedit_run() - Run a configuration editor
+ *
+ * This accepts input until the user quits with Escape
+ *
+ * @exp: Expo to use
+ * Returns: 0 if OK, -ve on error
+ */
+int cedit_run(struct expo *exp);
+
 #endif /*__SCENE_H */