[PATCH 00/42] video: Support a cursor more generally

From: Simon Glass <sjg@chromium.org> At present U-Boot does not support displaying a cursor on the console, except with expo. It is quite useful to have a cursor, particularly when using the command-line editor. This series adds tracking of the cursor position for both truetype and normal consoles. The cursor is shown when U-Boot is idle and is removed before writing characters to the display. A save-buffer ensures that the old display contents are provided. Some related improvements in this series include: - expo lineedit support with normal console - arrow keys now render correctly when editing commands with truetype - truetype console now also supports bitmap fonts The cursor is not currently supported for rotated consoles. A README for claude is provided, although so far I have not had too much success with it. A fix for an intermittent build is added as well, along with silencing some build messages noticed from Rust ulib. Simon Glass (42): Provide a README for Claude cyclic: Avoid showing messages when debugging video: Correct ops check for nominal, entry save/restore Makefile: Silence the example Rust build scripts: Fix conditional syntax for capsule ESL generation test: video: Split long strings video: Provide an option to enable the cursor snow: link: Disable the cursor video: console: Put fixed-font rendering into a shared file video: truetype: Rename the FONT_ENTRY() macro video: Move setting of the bitmap font into uclass video: Allow selection of bitmap fonts in truetype video: truetype: Handle rendering of bitmap fonts video: truetype: Use common cursor-drawing code video: Correct cursor handling when the the left side video: Convert to use uclass_id_foreach_dev() video: Provide an idle function for the console video: Provide state for the cursor video: Rename draw_cursor_vertically() to cursor_show() video: Update cursor_show() to take a simple pointer video: Move cursor drawing into the uclass video: Track the current CLI index video: Provide a way to indicate the start of CLI entry console: Add debugging for kerning video: truetype: Record the position where CLI entry starts video: truetype: Track characters and their widths expo: Enable the cursor when editing a textline video: Track whether the cursor is enabled video: Drop vidconsole_set_cursor_visible() video: Update normal console to use tracking information video: Add save and restore drivers for normal console video: Drop extra parameters from get_cursor_info() video: Support a cursor in multi-line text video: Drop extra parameters from vidconsole_show_cursor() video: Provide a buffer to hold pixels behind the cursor video: Support reading the framebuffer when writing video: Save overwritten pixels when drawing the cursor video: Show the cursor when idle video: truetype: Clear after the current char on insert video: truetype: Avoid clearing on backspace video: Add some notes about the cursor console: Add some cursor tests .claude/.gitignore | 1 + .claude/README.md | 69 ++++++ .gitignore | 1 + boot/scene_textline.c | 9 +- cmd/font.c | 3 - common/Kconfig | 9 + common/cli_readline.c | 5 + common/cyclic.c | 5 +- configs/chromebook_link_defconfig | 1 + configs/snow_defconfig | 1 + doc/usage/cmd/font.rst | 16 +- drivers/video/Kconfig | 8 + drivers/video/console_core.c | 195 ++++++++++++++--- drivers/video/console_normal.c | 140 ++++++++---- drivers/video/console_truetype.c | 326 ++++++++++++++++++---------- drivers/video/vidconsole-uclass.c | 176 ++++++++++++++- drivers/video/vidconsole_internal.h | 77 ++++++- drivers/video/video-uclass.c | 30 ++- examples/rust/Makefile | 3 - include/video_console.h | 164 ++++++++++++-- scripts/Makefile.lib | 5 +- test/cmd/font.c | 15 +- test/dm/video.c | 162 +++++++++++++- 23 files changed, 1173 insertions(+), 248 deletions(-) create mode 100644 .claude/.gitignore create mode 100644 .claude/README.md -- 2.43.0 base-commit: 0c2531998ee8fc2da099cb3e20cbabc5221c0b3d branch: curs

From: Simon Glass <sjg@chromium.org> Add the beginnings of a readme to help Claude do the right thing. Signed-off-by: Simon Glass <sjg@chromium.org> --- .claude/.gitignore | 1 + .claude/README.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 1 + 3 files changed, 71 insertions(+) create mode 100644 .claude/.gitignore create mode 100644 .claude/README.md diff --git a/.claude/.gitignore b/.claude/.gitignore new file mode 100644 index 00000000000..93c0f73fa41 --- /dev/null +++ b/.claude/.gitignore @@ -0,0 +1 @@ +settings.local.json diff --git a/.claude/README.md b/.claude/README.md new file mode 100644 index 00000000000..b84be8d2445 --- /dev/null +++ b/.claude/README.md @@ -0,0 +1,69 @@ +# U-Boot Build Instructions for Claude Code + +This file contains information about building U-Boot for use with Claude Code. + +## Building U-Boot + +### Using crosfw (Recommended) + +To build U-Boot for sandbox testing, use the `crosfw` command: + +```bash +# Build for sandbox +crosfw sandbox -L + +# The -L flag disables LTO (equivalent to NO_LTO=1) +# The build is silent unless there are warnings or errors +# The build is done in /tmp/b/<board_name>, so /tmp/b/sandbox in this case +``` + +### Using make directly + +If you prefer to use make directly, please use O= to avoid adding build files to +the source tree: + +```bash +# Clean the build (recommended before first build) +make mrproper + +# Configure for sandbox +make sandbox_defconfig O=/tmp/<build_dir> + +# Build +make -j$(nproc) O=/tmp/<build_dir> +``` +## Testing + +There are aliases in ~/bin/git-alias which you can use. + +To run a sandbox test: + +```bash +rtv <test_name> +# For example: rtv dm_test_video_box +# which translates to: /tmp/b/sandbox/u-boot -v -Tf -c "ut dm video_box" +# test output is silenced unless -v is given +``` + +To run using the Python suite: + +```bash +pyt <test_name> +# alias for: test/py/test.py -B sandbox --build-dir /tmp/b/sandbox -k <test_name> +``` + +## Notes + +- The `crosfw` tool is the preferred build method for this codebase +- Always run `make mrproper` if you encounter build issues +- The sandbox build creates a test environment for U-Boot that runs on the host system +- When using `git diff`, add `--no-ext-diff` to avoid external diff tools that may not work in this environment + +## Coding Conventions + +- For function parameters that return values (output parameters), add 'p' suffix to indicate pointer + - Example: `uint *sizep` instead of `uint *size` + - Example: `bool *visiblep` instead of `bool *visible` +- This follows U-Boot's established naming convention for output parameters +- Keep commit messages concise - focus on the key change and essential details only +- Code should be formatted to 80 columns and not have trailing spaces diff --git a/.gitignore b/.gitignore index e93c33da1bd..6b95c85b9b8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ # Normal rules (sorted alphabetically) # .* +!.claude !.checkpatch.conf *.a *.asn1.[ch] -- 2.43.0

From: Simon Glass <sjg@chromium.org> When using a debugger it is common to single step through functions. If one of those functions happens to be called from a cyclic function, then a warning messages is shown. When debugging the console itself, this can mess up the session. Add a Kconfig to control whether the message is shown. Disable it by default if CONFIG_CC_OPTIMIZE_FOR_DEBUG is enabled. Signed-off-by: Simon Glass <sjg@chromium.org> --- common/Kconfig | 9 +++++++++ common/cyclic.c | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/common/Kconfig b/common/Kconfig index 55e9bcdfa2b..3bd11f44c51 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -666,6 +666,15 @@ config CYCLIC_MAX_CPU_TIME_US takes longer than this duration this function will get unregistered automatically. +config CYCLIC_WARN_LATE + bool "Warn if a cyclic function takes too long" + default y if !CC_OPTIMIZE_FOR_DEBUG + help + Show a warning on the console if a cyclic function goes over the + alotted maximum time. The message is of the form: + + cyclic_run() cyclic function <func_name> took too long: x vs y max + endif # CYCLIC config EVENT diff --git a/common/cyclic.c b/common/cyclic.c index 196797fd61e..e5a2ad302af 100644 --- a/common/cyclic.c +++ b/common/cyclic.c @@ -71,8 +71,9 @@ static void cyclic_run(void) cyclic->cpu_time_us += cpu_time; /* Check if cpu-time exceeds max allowed time */ - if ((cpu_time > CONFIG_CYCLIC_MAX_CPU_TIME_US) && - (!cyclic->already_warned)) { + if (IS_ENABLED(CONFIG_CYCLIC_WARN_LATE) && + cpu_time > CONFIG_CYCLIC_MAX_CPU_TIME_US && + !cyclic->already_warned) { pr_err("cyclic function %s took too long: %lldus vs %dus max\n", cyclic->name, cpu_time, CONFIG_CYCLIC_MAX_CPU_TIME_US); -- 2.43.0

From: Simon Glass <sjg@chromium.org> All of these helper functions check the wrong member. Fix them. Signed-off-by: Simon Glass <sjg@chromium.org> Fixes: 9e55d09596a ("video: Allow obtaining the nominal size of a...") Fixes: 9899eef2cb4 ("video: Allow saving and restoring text-entry...") --- drivers/video/vidconsole-uclass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index a98344cf9a7..6c5338936e5 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -655,7 +655,7 @@ int vidconsole_nominal(struct udevice *dev, const char *name, uint size, struct vidconsole_ops *ops = vidconsole_get_ops(dev); int ret; - if (ops->measure) { + if (ops->nominal) { ret = ops->nominal(dev, name, size, num_chars, bbox); if (ret != -ENOSYS) return ret; @@ -675,7 +675,7 @@ int vidconsole_entry_save(struct udevice *dev, struct abuf *buf) struct vidconsole_ops *ops = vidconsole_get_ops(dev); int ret; - if (ops->measure) { + if (ops->entry_save) { ret = ops->entry_save(dev, buf); if (ret != -ENOSYS) return ret; @@ -692,7 +692,7 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf) struct vidconsole_ops *ops = vidconsole_get_ops(dev); int ret; - if (ops->measure) { + if (ops->entry_restore) { ret = ops->entry_restore(dev, buf); if (ret != -ENOSYS) return ret; -- 2.43.0

From: Simon Glass <sjg@chromium.org> We don't need messages printed when building. Remove them. Signed-off-by: Simon Glass <sjg@chromium.org> --- examples/rust/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/rust/Makefile b/examples/rust/Makefile index d9fcedea60d..d372907d585 100644 --- a/examples/rust/Makefile +++ b/examples/rust/Makefile @@ -41,8 +41,6 @@ $(OUTDIR): # Build dynamic version (links with libu-boot.so) $(OUTDIR)/demo: $(RUST_SOURCES) $(UBOOT_BUILD)/libu-boot.so | $(OUTDIR) - @echo "Building Rust demo (dynamic) with library from $(UBOOT_BUILD)" - @echo "OUTDIR=$(OUTDIR), abspath=$(OUTDIR_ABS)" @if [ ! -f "$(UBOOT_BUILD)/libu-boot.so" ]; then \ echo "No shared library at $(UBOOT_BUILD)/libu-boot.so" >&2; \ echo "Please build U-Boot: make sandbox_defconfig && make" >&2; \ @@ -54,7 +52,6 @@ $(OUTDIR)/demo: $(RUST_SOURCES) $(UBOOT_BUILD)/libu-boot.so | $(OUTDIR) # Build static version (links with libu-boot.a) $(OUTDIR)/demo_static: $(RUST_SOURCES) $(UBOOT_BUILD)/libu-boot.a | $(OUTDIR) - @echo "Building Rust demo (static) with library from $(UBOOT_BUILD)" @if [ ! -f "$(UBOOT_BUILD)/libu-boot.a" ]; then \ echo "No static library at $(UBOOT_BUILD)/libu-boot.a" >&2; \ echo "Please build U-Boot: make sandbox_defconfig && make" >&2; \ -- 2.43.0

From: Simon Glass <sjg@chromium.org> The ifeq/else/endif conditional for capsule_esl_file generation was incorrectly placed inside the recipe, causing malformed Makefile syntax that prevented proper dependency resolution. This resulted in build failures when CONFIG_EFI_CAPSULE_AUTHENTICATE was enabled because the capsule_esl_file target could not be created from the certificate file. Move the conditional to properly wrap the rule definitions, allowing Make to correctly parse and execute the capsule ESL generation rules. Signed-off-by: Simon Glass <sjg@chromium.org> Co-developed-by: Claude <noreply@anthropic.com> --- scripts/Makefile.lib | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 8300c8104ce..5abe428e752 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -409,17 +409,18 @@ capsule_esl_dtsi=.capsule_esl.dtsi quiet_cmd_capsule_esl_gen = ESL $@ cmd_capsule_esl_gen = cert-to-efi-sig-list $< $@ -$(obj)/capsule_esl_file: $(capsule_crt_file) +$(obj)/capsule_esl_file: $(srctree)/$(capsule_crt_file) ifeq ($(CONFIG_EFI_CAPSULE_CRT_FILE),"") $(error "CONFIG_EFI_CAPSULE_CRT_FILE is empty, EFI capsule authentication \ public key must be specified when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled") else + $(Q)echo "Building capsule_esl_file: $@ from $<" $(call cmd,capsule_esl_gen) endif quiet_cmd_capsule_dtsi_gen = CAPSULE $@ cmd_capsule_dtsi_gen = \ - $(shell sed "s:ESL_BIN_FILE:$(abspath $<):" $(capsule_esl_input_file) > $@) + sed "s:ESL_BIN_FILE:capsule_esl_file:" $(capsule_esl_input_file) > $@ $(obj)/$(capsule_esl_dtsi): $(obj)/capsule_esl_file $(capsule_esl_input_file) $(call cmd,capsule_dtsi_gen) -- 2.43.0

From: Simon Glass <sjg@chromium.org> Some strings in this file are quite long and it is a pain to look at them within an 80-column editor. Split them. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- test/dm/video.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/test/dm/video.c b/test/dm/video.c index 513134dd445..a48d0c0411c 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -229,7 +229,8 @@ DM_TEST(dm_test_video_text_12x22, UTF_SCAN_PDATA | UTF_SCAN_FDT); static int dm_test_video_chars(struct unit_test_state *uts) { struct udevice *dev, *con; - const char *test_string = "Well\b\b\b\bxhe is\r \n\ta very \amodest \bman\n\t\tand Has much to\b\bto be modest about."; + const char *test_string = "Well\b\b\b\bxhe is\r \n\ta very \amodest " + "\bman\n\t\tand Has much to\b\bto be modest about."; ut_assertok(select_vidconsole(uts, "vidconsole0")); ut_assertok(video_get_nologo(uts, &dev)); @@ -581,7 +582,13 @@ DM_TEST(dm_test_video_comp_bmp8, UTF_SCAN_PDATA | UTF_SCAN_FDT); static int dm_test_video_truetype(struct unit_test_state *uts) { struct udevice *dev, *con; - const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye"; + const char *test_string = "Criticism may not be agreeable, but it " + "is necessary. It fulfils the same function as pain in the " + "human body. It calls attention to an unhealthy state of " + "things. Some see private enterprise as a predatory target to " + "be shot, others as a cow to be milked, but few are those who " + "see it as a sturdy horse pulling the wagon. The \aprice " + "OF\b\bof greatness\n\tis responsibility.\n\nBye"; ut_assertok(video_get_nologo(uts, &dev)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); @@ -599,7 +606,13 @@ static int dm_test_video_truetype_scroll(struct unit_test_state *uts) { struct sandbox_sdl_plat *plat; struct udevice *dev, *con; - const char *test_string = "Criticism may not be agreeable, but it is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things. Some see private enterprise as a predatory target to be shot, others as a cow to be milked, but few are those who see it as a sturdy horse pulling the wagon. The \aprice OF\b\bof greatness\n\tis responsibility.\n\nBye"; + const char *test_string = "Criticism may not be agreeable, but it " + "is necessary. It fulfils the same function as pain in the " + "human body. It calls attention to an unhealthy state of " + "things. Some see private enterprise as a predatory target to " + "be shot, others as a cow to be milked, but few are those who " + "see it as a sturdy horse pulling the wagon. The \aprice " + "OF\b\bof greatness\n\tis responsibility.\n\nBye"; ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev)); ut_assert(!device_active(dev)); @@ -621,7 +634,11 @@ static int dm_test_video_truetype_bs(struct unit_test_state *uts) { struct sandbox_sdl_plat *plat; struct udevice *dev, *con; - const char *test_string = "...Criticism may or may\b\b\b\b\b\bnot be agreeable, but seldom it is necessary\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bit is necessary. It fulfils the same function as pain in the human body. It calls attention to an unhealthy state of things."; + const char *test_string = "...Criticism may or may\b\b\b\b\b\bnot be " + "agreeable, but seldom it is necessary\b\b\b\b\b\b\b\b\b\b\b\b" + "\b\b\b\b\b\b\b\b\b\bit is necessary. It fulfils the same " + "function as pain in the human body. It calls attention to an " + "unhealthy state of things."; ut_assertok(uclass_find_device(UCLASS_VIDEO, 0, &dev)); ut_assert(!device_active(dev)); @@ -645,7 +662,8 @@ static int dm_test_video_copy(struct unit_test_state *uts) struct video_uc_plat *uc_plat; struct udevice *dev, *con; struct video_priv *priv; - const char *test_string = "\n\tCriticism may not be agreeable, but it is necessary.\t"; + const char *test_string = "\n\tCriticism may not be agreeable, but it " + "is necessary.\t"; ulong addr; if (!IS_ENABLED(CONFIG_VIDEO_COPY)) @@ -710,7 +728,8 @@ static int dm_test_video_damage(struct unit_test_state *uts) struct video_priv *priv; const char *test_string_1 = "Criticism may not be agreeable, "; const char *test_string_2 = "but it is necessary."; - const char *test_string_3 = "It fulfils the same function as pain in the human body."; + const char *test_string_3 = "It fulfils the same function as pain in " + "the human body."; if (!IS_ENABLED(CONFIG_VIDEO_DAMAGE)) return -EAGAIN; -- 2.43.0

From: Simon Glass <sjg@chromium.org> The video cursor is always enabled at present, but it is only used for expo. Put it behind an option, to reduce code size for platforms which do use video but don't want a cursor. Move the existing set_cursor_visible() method behind this option, for the normal console. For the truetype console, the fonts and extra rendering dwarf the code-size saving, so include the cursor there always. Once the cursor is enabled for the CLI, this will produce code-size savings. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/Kconfig | 8 ++++++++ drivers/video/console_normal.c | 7 +++++-- drivers/video/vidconsole-uclass.c | 2 ++ include/video_console.h | 9 +++++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6e1577ae687..446ce51fe27 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -68,6 +68,14 @@ config BACKLIGHT This provides backlight uclass driver that enables basic panel backlight support. +config CURSOR + bool "Show a cursor on the console" + default y + help + Show a cursor on the video console when entering commands. This is + a simple vertical bar drawn before the character at the current + position. The cursor makes it easy to see the current input position. + config VIDEO_PCI_DEFAULT_FB_SIZE hex "Default framebuffer size to use if no drivers request it" default 0x1000000 if X86 diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 07db613ac53..a39b04bd73c 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -105,8 +105,9 @@ static int console_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp) return VID_TO_POS(fontdata->width); } -static int console_set_cursor_visible(struct udevice *dev, bool visible, - uint x, uint y, uint index) +static int __maybe_unused console_set_cursor_visible(struct udevice *dev, + bool visible, uint x, + uint y, uint index) { struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct udevice *vid = dev->parent; @@ -140,7 +141,9 @@ struct vidconsole_ops console_ops = { .get_font_size = console_simple_get_font_size, .get_font = console_simple_get_font, .select_font = console_simple_select_font, +#ifdef CONFIG_CURSOR .set_cursor_visible = console_set_cursor_visible, +#endif }; U_BOOT_DRIVER(vidconsole_normal) = { diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 6c5338936e5..f53d55e81b7 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -701,6 +701,7 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf) return 0; } +#ifdef CONFIG_CURSOR int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, uint x, uint y, uint index) { @@ -715,6 +716,7 @@ int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, return 0; } +#endif void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg, enum colour_idx bg, struct vidconsole_colour *old) diff --git a/include/video_console.h b/include/video_console.h index 8f3f58f3aa9..d3c65a08331 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -404,6 +404,7 @@ int vidconsole_entry_save(struct udevice *dev, struct abuf *buf); */ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf); +#ifdef CONFIG_CURSOR /** * vidconsole_set_cursor_visible() - Show or hide the cursor * @@ -418,6 +419,14 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf); */ int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, uint x, uint y, uint index); +#else +static inline int vidconsole_set_cursor_visible(struct udevice *dev, + bool visible, uint x, uint y, + uint index) +{ + return 0; +} +#endif /* CONFIG_CURSOR */ /** * vidconsole_push_colour() - Temporarily change the font colour -- 2.43.0

From: Simon Glass <sjg@chromium.org> These boards enable EXPO. Disable the cursor so we can get build coverage on this combination. Signed-off-by: Simon Glass <sjg@chromium.org> --- configs/chromebook_link_defconfig | 1 + configs/snow_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig index 05d81f516fc..a0c368b0142 100644 --- a/configs/chromebook_link_defconfig +++ b/configs/chromebook_link_defconfig @@ -77,6 +77,7 @@ CONFIG_TPM_TIS_LPC=y # CONFIG_TPM_V2 is not set CONFIG_USB_STORAGE=y CONFIG_USB_KEYBOARD=y +# CONFIG_CURSOR is not set CONFIG_VIDEO_COPY=y CONFIG_FRAMEBUFFER_SET_VESA_MODE=y CONFIG_FRAMEBUFFER_VESA_MODE_11A=y diff --git a/configs/snow_defconfig b/configs/snow_defconfig index 27698f5ef36..32db5f192fe 100644 --- a/configs/snow_defconfig +++ b/configs/snow_defconfig @@ -97,6 +97,7 @@ CONFIG_USB_EHCI_HCD=y CONFIG_USB_HOST_ETHER=y CONFIG_USB_ETHER_ASIX88179=y CONFIG_VIDEO=y +# CONFIG_CURSOR is not set # CONFIG_VIDEO_BPP8 is not set CONFIG_VIDCONSOLE_AS_LCD=y CONFIG_DISPLAY=y -- 2.43.0

From: Simon Glass <sjg@chromium.org> Move fixed-font, character-rendering from console_normal.c into a shared function in console_core.c. This will allow truetype to use the fixed fonts as well as its own. Co-developed-by: Claude <noreply@anthropic.com> --- drivers/video/console_core.c | 33 ++++++++++++++++++++++++ drivers/video/console_normal.c | 39 ++++++----------------------- drivers/video/vidconsole_internal.h | 24 ++++++++++++++++++ 3 files changed, 64 insertions(+), 32 deletions(-) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index 939363653f6..4b75a5b6e12 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -228,6 +228,39 @@ int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *i return info->name ? 0 : -ENOENT; } +int console_fixed_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp, + struct video_fontdata *fontdata) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct udevice *vid = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + int pbytes = VNBYTES(vid_priv->bpix); + int x, linenum, ret; + void *start, *line; + u8 ch = console_utf_to_cp437(cp); + uchar *pfont = fontdata->video_fontdata + + ch * fontdata->char_pixel_bytes; + + if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) + return -EAGAIN; + linenum = y; + x = VID_TO_PIXEL(x_frac); + start = vid_priv->fb + linenum * vid_priv->line_length + x * pbytes; + line = start; + + ret = fill_char_vertically(pfont, &line, vid_priv, fontdata, NORMAL_DIRECTION); + if (ret) + return ret; + + video_damage(dev->parent, + x, + y, + fontdata->width, + fontdata->height); + + return VID_TO_POS(fontdata->width); +} + int console_simple_select_font(struct udevice *dev, const char *name, uint size) { struct video_fontdata *font; diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index a39b04bd73c..9509f81f40f 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -68,41 +68,11 @@ static int console_move_rows(struct udevice *dev, uint rowdst, return 0; } -static int console_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp) +int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp) { - struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); - struct udevice *vid = dev->parent; - struct video_priv *vid_priv = dev_get_uclass_priv(vid); struct console_simple_priv *priv = dev_get_priv(dev); - struct video_fontdata *fontdata = priv->fontdata; - int pbytes = VNBYTES(vid_priv->bpix); - int x, linenum, ret; - void *start, *line; - u8 ch = console_utf_to_cp437(cp); - uchar *pfont = fontdata->video_fontdata + - ch * fontdata->char_pixel_bytes; - - if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) - return -EAGAIN; - linenum = y; - x = VID_TO_PIXEL(x_frac); - start = vid_priv->fb + linenum * vid_priv->line_length + x * pbytes; - line = start; - if (x_frac + VID_TO_POS(vc_priv->x_charsize) > vc_priv->xsize_frac) - return -EAGAIN; - - ret = fill_char_vertically(pfont, &line, vid_priv, fontdata, NORMAL_DIRECTION); - if (ret) - return ret; - - video_damage(dev->parent, - x, - y, - fontdata->width, - fontdata->height); - - return VID_TO_POS(fontdata->width); + return console_fixed_putc_xy(dev, x_frac, y, cp, priv->fontdata); } static int __maybe_unused console_set_cursor_visible(struct udevice *dev, @@ -134,6 +104,11 @@ static int __maybe_unused console_set_cursor_visible(struct udevice *dev, return 0; } +static int console_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp) +{ + return console_normal_putc_xy(dev, x_frac, y, cp); +} + struct vidconsole_ops console_ops = { .putc_xy = console_putc_xy, .move_rows = console_move_rows, diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index bb0277ee451..af2cca8791c 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -146,6 +146,30 @@ int console_simple_get_font(struct udevice *dev, int seq, struct vidfont_info *i **/ int console_simple_select_font(struct udevice *dev, const char *name, uint size); +/** + * Normal console putc_xy function that can be called by other console drivers + * + * @param dev console device + * @param x_frac fractional X position + * @param y Y position in pixels + * @param cp Unicode code point + * @returns width in fractional pixels, or -ve on error + */ +int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp); + +/** + * Fixed font putc_xy function that can be called with explicit font data + * + * @param dev console device + * @param x_frac fractional X position + * @param y Y position in pixels + * @param cp Unicode code point + * @param fontdata font data to use for rendering + * @returns width in fractional pixels, or -ve on error + */ +int console_fixed_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp, + struct video_fontdata *fontdata); + /** * Internal function to convert Unicode code points to code page 437. * Used by video consoles using bitmap fonts. -- 2.43.0

From: Simon Glass <sjg@chromium.org> Rename this macro in preparation for allowing truetype to use bitmap fonts. This avoids a conflict with FONT_ENTRY() in video_font.h Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index f185552261c..a17519282fc 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -520,7 +520,7 @@ struct font_info { extern u8 __ttf_ ## _name ## _begin[]; \ extern u8 __ttf_ ## _name ## _end[]; -#define FONT_ENTRY(_name) { \ +#define TT_FONT_ENTRY(_name) { \ .name = #_name, \ .begin = __ttf_ ## _name ## _begin, \ .end = __ttf_ ## _name ## _end, \ @@ -535,22 +535,22 @@ FONT_DECL(ubuntu_bold); static struct font_info font_table[] = { #ifdef CONFIG_CONSOLE_TRUETYPE_NIMBUS - FONT_ENTRY(nimbus_sans_l_regular), + TT_FONT_ENTRY(nimbus_sans_l_regular), #endif #ifdef CONFIG_CONSOLE_TRUETYPE_ANKACODER - FONT_ENTRY(ankacoder_c75_r), + TT_FONT_ENTRY(ankacoder_c75_r), #endif #ifdef CONFIG_CONSOLE_TRUETYPE_RUFSCRIPT - FONT_ENTRY(rufscript010), + TT_FONT_ENTRY(rufscript010), #endif #ifdef CONFIG_CONSOLE_TRUETYPE_CANTORAONE - FONT_ENTRY(cantoraone_regular), + TT_FONT_ENTRY(cantoraone_regular), #endif #ifdef CONFIG_CONSOLE_TRUETYPE_UBUNTU_LIGHT - FONT_ENTRY(ubuntu_light), + TT_FONT_ENTRY(ubuntu_light), #endif #ifdef CONFIG_CONSOLE_TRUETYPE_UBUNTU_BOLD - FONT_ENTRY(ubuntu_bold), + TT_FONT_ENTRY(ubuntu_bold), #endif {} /* sentinel */ }; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Most of this function deals with uclass data, so move it into the uclass. This will allow truetype to use it too. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_core.c | 18 +----------------- drivers/video/vidconsole-uclass.c | 24 ++++++++++++++++++++++++ include/video_console.h | 10 ++++++++++ 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index 4b75a5b6e12..aec51dc809d 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -21,25 +21,9 @@ static int console_set_font(struct udevice *dev, struct video_fontdata *fontdata) { struct console_simple_priv *priv = dev_get_priv(dev); - struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); - struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); - - debug("console_simple: setting %s font\n", fontdata->name); - debug("width: %d\n", fontdata->width); - debug("byte width: %d\n", fontdata->byte_width); - debug("height: %d\n", fontdata->height); priv->fontdata = fontdata; - vc_priv->x_charsize = fontdata->width; - vc_priv->y_charsize = fontdata->height; - if (vid_priv->rot % 2) { - vc_priv->cols = vid_priv->ysize / fontdata->width; - vc_priv->rows = vid_priv->xsize / fontdata->height; - vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize); - } else { - vc_priv->cols = vid_priv->xsize / fontdata->width; - vc_priv->rows = vid_priv->ysize / fontdata->height; - } + vidconsole_set_bitmap_font(dev, fontdata); return 0; } diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index f53d55e81b7..b5f0b79bcf6 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -812,3 +812,27 @@ void vidconsole_set_quiet(struct udevice *dev, bool quiet) priv->quiet = quiet; } + +void vidconsole_set_bitmap_font(struct udevice *dev, + struct video_fontdata *fontdata) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); + + log_debug("console_simple: setting %s font\n", fontdata->name); + log_debug("width: %d\n", fontdata->width); + log_debug("byte width: %d\n", fontdata->byte_width); + log_debug("height: %d\n", fontdata->height); + + vc_priv->x_charsize = fontdata->width; + vc_priv->y_charsize = fontdata->height; + if (vid_priv->rot % 2) { + vc_priv->cols = vid_priv->ysize / fontdata->width; + vc_priv->rows = vid_priv->xsize / fontdata->height; + vc_priv->xsize_frac = VID_TO_POS(vid_priv->ysize); + } else { + vc_priv->cols = vid_priv->xsize / fontdata->width; + vc_priv->rows = vid_priv->ysize / fontdata->height; + /* xsize_frac is set in vidconsole_pre_probe() */ + } +} diff --git a/include/video_console.h b/include/video_console.h index d3c65a08331..8cd1ccacb0f 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -10,6 +10,7 @@ #include <video.h> struct abuf; +struct video_fontdata; struct video_priv; #define VID_FRAC_DIV 256 @@ -603,4 +604,13 @@ int vidconsole_get_font_size(struct udevice *dev, const char **name, uint *sizep */ void vidconsole_set_quiet(struct udevice *dev, bool quiet); +/** + * vidconsole_set_bitmap_font() - prepare vidconsole for chosen bitmap font + * + * @dev vidconsole device + * @fontdata pointer to font data struct + */ +void vidconsole_set_bitmap_font(struct udevice *dev, + struct video_fontdata *fontdata); + #endif -- 2.43.0

From: Simon Glass <sjg@chromium.org> It is sometimes useful to use a bitmap font for the console even when truetype fonts are available. As a starting point, pull in the font table and provide information about font sizes. Allow selection of a bitmap font by name, as well as listing available bitmap fonts. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 64 ++++++++++++++++++++++++++++++-- test/cmd/font.c | 8 +++- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index a17519282fc..eb9e7f55d68 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -12,6 +12,7 @@ #include <spl.h> #include <video.h> #include <video_console.h> +#include <video_font.h> /* Functions needed by stb_truetype.h */ static int tt_floor(double val) @@ -169,6 +170,7 @@ struct console_tt_metrics { * last character. We record enough characters to go back to the * start of the current command line. * @pos_ptr: Current position in the position history + * @cur_fontdata: Current fixed font data (NULL if using TrueType) */ struct console_tt_priv { struct console_tt_metrics *cur_met; @@ -176,6 +178,7 @@ struct console_tt_priv { int num_metrics; struct pos_info pos[POS_HISTORY_SIZE]; int pos_ptr; + struct video_fontdata *cur_fontdata; }; /** @@ -595,9 +598,19 @@ int console_truetype_get_font(struct udevice *dev, int seq, struct vidfont_info *info) { struct font_info *tab; + struct video_fontdata *fontdata; int i; - for (i = 0, tab = font_table; tab->begin; tab++, i++) { + /* List fixed fonts first */ + for (i = 0, fontdata = fonts; fontdata->name; fontdata++, i++) { + if (i == seq) { + info->name = fontdata->name; + return 0; + } + } + + /* then list TrueType fonts */ + for (tab = font_table; tab->begin; tab++, i++) { if (i == seq && font_valid(tab)) { info->name = tab->name; return 0; @@ -671,6 +684,27 @@ static struct console_tt_metrics *find_metrics(struct udevice *dev, return NULL; } +/** + * set_bitmap_font() - Set up console to use a fixed font + * + * @dev: Console device + * @fontdata: Fixed font data to use + * Return: 0 if OK, -ve on error + */ +static void set_bitmap_font(struct udevice *dev, + struct video_fontdata *fontdata) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct console_tt_priv *priv = dev_get_priv(dev); + + priv->cur_fontdata = fontdata; + priv->cur_met = NULL; + + vidconsole_set_bitmap_font(dev, fontdata); + + vc_priv->tab_width_frac = VID_TO_POS(fontdata->width) * 8 / 2; +} + static void select_metrics(struct udevice *dev, struct console_tt_metrics *met) { struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); @@ -734,9 +768,24 @@ static int get_metrics(struct udevice *dev, const char *name, uint size, static int truetype_select_font(struct udevice *dev, const char *name, uint size) { + struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_metrics *met; + struct video_fontdata *fontdata; int ret; + /* Check if this is a request for a fixed font */ + if (name) { + for (fontdata = fonts; fontdata->name; fontdata++) { + if (!strcmp(name, fontdata->name)) { + /* Switch to fixed-font mode */ + set_bitmap_font(dev, fontdata); + return 0; + } + } + } + + /* Continue with TrueType font selection */ + priv->cur_fontdata = NULL; ret = get_metrics(dev, name, size, &met); if (ret) return log_msg_ret("sel", ret); @@ -1036,11 +1085,18 @@ static int truetype_set_cursor_visible(struct udevice *dev, bool visible, const char *console_truetype_get_font_size(struct udevice *dev, uint *sizep) { struct console_tt_priv *priv = dev_get_priv(dev); - struct console_tt_metrics *met = priv->cur_met; - *sizep = met->font_size; + if (priv->cur_fontdata) { + /* Using fixed font */ + *sizep = priv->cur_fontdata->height; + return priv->cur_fontdata->name; + } else { + /* Using TrueType font */ + struct console_tt_metrics *met = priv->cur_met; - return met->font_name; + *sizep = met->font_size; + return met->font_name; + } } static int console_truetype_probe(struct udevice *dev) diff --git a/test/cmd/font.c b/test/cmd/font.c index 7ae648d7395..b2610ddef8d 100644 --- a/test/cmd/font.c +++ b/test/cmd/font.c @@ -26,6 +26,10 @@ static int font_test_base(struct unit_test_state *uts) ut_assertok(uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev)); ut_assertok(run_command("font list", 0)); + if (IS_ENABLED(CONFIG_VIDEO_FONT_8X16)) + ut_assert_nextline("8x16"); + if (IS_ENABLED(CONFIG_VIDEO_FONT_SUN12X22)) + ut_assert_nextline("12x22"); if (IS_ENABLED(CONFIG_CONSOLE_TRUETYPE_NIMBUS)) ut_assert_nextline("nimbus_sans_l_regular"); if (IS_ENABLED(CONFIG_CONSOLE_TRUETYPE_ANKACODER)) @@ -37,8 +41,10 @@ static int font_test_base(struct unit_test_state *uts) ut_assertok(vidconsole_get_font_size(dev, &name, &size)); if (IS_ENABLED(CONFIG_CONSOLE_TRUETYPE_ANKACODER)) ut_asserteq_str("ankacoder_c75_r", name); - else + else if (IS_ENABLED(CONFIG_CONSOLE_TRUETYPE_NIMBUS)) ut_asserteq_str("nimbus_sans_l_regular", name); + else + ut_asserteq_str("8x16", name); ut_asserteq(CONFIG_CONSOLE_TRUETYPE_SIZE, size); if (!IS_ENABLED(CONFIG_CONSOLE_TRUETYPE_CANTORAONE)) -- 2.43.0

From: Simon Glass <sjg@chromium.org> Complete the support for this feature by dealing with rendering, the moving to a particular row/column and scrolling. Provide a simple test to check that things look right. Allow omitting the font name to request the default font. Fix an errant tab nearby. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- cmd/font.c | 3 --- doc/usage/cmd/font.rst | 16 ++++++++++-- drivers/video/console_truetype.c | 37 +++++++++++++++++++------- drivers/video/vidconsole-uclass.c | 1 + test/cmd/font.c | 7 +++-- test/dm/video.c | 43 ++++++++++++++++++++++++++++++- 6 files changed, 89 insertions(+), 18 deletions(-) diff --git a/cmd/font.c b/cmd/font.c index 36e41203654..384751e787a 100644 --- a/cmd/font.c +++ b/cmd/font.c @@ -31,9 +31,6 @@ static int do_font_select(struct cmd_tbl *cmdtp, int flag, int argc, uint size = 0; int ret; - if (argc < 2) - return CMD_RET_USAGE; - if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev)) return CMD_RET_FAILURE; name = argv[1]; diff --git a/doc/usage/cmd/font.rst b/doc/usage/cmd/font.rst index 44a04f5d075..6e313e70c7a 100644 --- a/doc/usage/cmd/font.rst +++ b/doc/usage/cmd/font.rst @@ -12,7 +12,7 @@ Synopsis :: font list - font select <name> [<size>] + font select [<name> [<size>]] font size [<size>] Description @@ -25,11 +25,13 @@ font list ~~~~~~~~~ This lists the available fonts, using the name of the font file in the build. +Any enabled bitmap fonts are listed as well. font select ~~~~~~~~~~~ -This selects a new font and optionally changes the size. +This selects a new font and optionally changes the size. If the name is not +provided, the default font is used. font size ~~~~~~~~~ @@ -50,6 +52,16 @@ Examples => font select cantoraone_regular 20 => +This shows an example of selecting a bitmap font Truetype is active:: + + => font list + 8x16 + 12x22 + nimbus_sans_l_regular + cantoraone_regular + => font sel 8x16 + + Configuration ------------- diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index eb9e7f55d68..43274bb8f66 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -13,6 +13,7 @@ #include <video.h> #include <video_console.h> #include <video_font.h> +#include "vidconsole_internal.h" /* Functions needed by stb_truetype.h */ static int tt_floor(double val) @@ -197,11 +198,17 @@ static int console_truetype_set_row(struct udevice *dev, uint row, int clr) struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct console_tt_priv *priv = dev_get_priv(dev); - struct console_tt_metrics *met = priv->cur_met; void *end, *line; + int font_height; + + /* Get font height from current font type */ + if (priv->cur_fontdata) + font_height = priv->cur_fontdata->height; + else + font_height = priv->cur_met->font_size; - line = vid_priv->fb + row * met->font_size * vid_priv->line_length; - end = line + met->font_size * vid_priv->line_length; + line = vid_priv->fb + row * font_height * vid_priv->line_length; + end = line + font_height * vid_priv->line_length; switch (vid_priv->bpix) { case VIDEO_BPP8: { @@ -250,17 +257,22 @@ static int console_truetype_move_rows(struct udevice *dev, uint rowdst, struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct console_tt_priv *priv = dev_get_priv(dev); - struct console_tt_metrics *met = priv->cur_met; void *dst; void *src; - int i, diff; + int i, diff, font_height; - dst = vid_priv->fb + rowdst * met->font_size * vid_priv->line_length; - src = vid_priv->fb + rowsrc * met->font_size * vid_priv->line_length; - memmove(dst, src, met->font_size * vid_priv->line_length * count); + /* Get font height from current font type */ + if (priv->cur_fontdata) + font_height = priv->cur_fontdata->height; + else + font_height = priv->cur_met->font_size; + + dst = vid_priv->fb + rowdst * font_height * vid_priv->line_length; + src = vid_priv->fb + rowsrc * font_height * vid_priv->line_length; + memmove(dst, src, font_height * vid_priv->line_length * count); /* Scroll up our position history */ - diff = (rowsrc - rowdst) * met->font_size; + diff = (rowsrc - rowdst) * font_height; for (i = 0; i < priv->pos_ptr; i++) priv->pos[i].ypos -= diff; @@ -281,7 +293,7 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, struct video_priv *vid_priv = dev_get_uclass_priv(vid); struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_metrics *met = priv->cur_met; - stbtt_fontinfo *font = &met->font; + stbtt_fontinfo *font; int width, height, xoff, yoff; double xpos, x_shift; int lsb; @@ -292,7 +304,12 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, void *start, *end, *line; int row, kern; + /* Use fixed font if selected */ + if (priv->cur_fontdata) + return console_fixed_putc_xy(dev, x, y, cp, priv->cur_fontdata); + /* First get some basic metrics about this character */ + font = &met->font; stbtt_GetCodepointHMetrics(font, cp, &advance, &lsb); /* diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index b5f0b79bcf6..cb7212e9730 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -835,4 +835,5 @@ void vidconsole_set_bitmap_font(struct udevice *dev, vc_priv->rows = vid_priv->ysize / fontdata->height; /* xsize_frac is set in vidconsole_pre_probe() */ } + vc_priv->xstart_frac = 0; } diff --git a/test/cmd/font.c b/test/cmd/font.c index b2610ddef8d..ce694fef7e4 100644 --- a/test/cmd/font.c +++ b/test/cmd/font.c @@ -82,9 +82,12 @@ static int font_test_base(struct unit_test_state *uts) ut_assert_nextline("30"); ut_assertok(ut_check_console_end(uts)); + ut_assertok(run_command("font select", 0)); + ut_assertok(ut_check_console_end(uts)); + ut_assertok(vidconsole_get_font_size(dev, &name, &size)); - ut_asserteq_str("cantoraone_regular", name); - ut_asserteq(30, size); + ut_asserteq_str("nimbus_sans_l_regular", name); + ut_asserteq(CONFIG_CONSOLE_TRUETYPE_SIZE, size); return 0; } diff --git a/test/dm/video.c b/test/dm/video.c index a48d0c0411c..3ec12956909 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -944,7 +944,7 @@ static int dm_test_video_box(struct unit_test_state *uts) video_draw_box(dev, 500, 100, 600, 200, 20, video_index_to_colour(priv, VID_LIGHT_RED), false); ut_asserteq(133, video_compress_fb(uts, dev, false)); - + /* test filled boxes */ video_draw_box(dev, 150, 250, 200, 300, 0, video_index_to_colour(priv, VID_GREEN), true); @@ -956,3 +956,44 @@ static int dm_test_video_box(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_video_box, UTF_SCAN_FDT); + +/* font switching between TrueType and bitmap fonts */ +static int dm_test_video_font_switch(struct unit_test_state *uts) +{ + struct udevice *dev, *con; + const char *truetype_text = + "This is a long line of text written with TrueType font that " + "should wrap to multiple lines to test the multi-line " + "functionality properly. This is the second part of TrueType " + "text that should also be long enough to wrap and test the " + "line handling."; + const char *bitmap_text = + "Now this is bitmap font text that spans multiple lines and " + "should be rendered with the standard 8x16 bitmap font instead " + "of TrueType. More of the line of-bitmap text for testing " + "purposes."; + const char *final_truetype_text = + "Finally back to TrueType font for this concluding multi-line " + "text that demonstrates the font switching functionality " + "working correctly.\nFinal line of TrueType text to complete " + "the test.\n"; + + ut_assertok(video_get_nologo(uts, &dev)); + ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); + + /* Start with TrueType font and write multi-line text */ + vidconsole_put_string(con, truetype_text); + + /* Switch to bitmap font */ + ut_assertok(vidconsole_select_font(con, "8x16", 0)); + vidconsole_put_string(con, bitmap_text); + + /* Switch back to TrueType font */ + ut_assertok(vidconsole_select_font(con, NULL, 0)); + vidconsole_put_string(con, final_truetype_text); + + ut_asserteq(14892, video_compress_fb(uts, dev, false)); + + return 0; +} +DM_TEST(dm_test_video_font_switch, UTF_SCAN_PDATA | UTF_SCAN_FDT); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Update truetype_set_cursor_visible() to use the existing shared draw_cursor_vertically() function instead of duplicating cursor-drawing itself. This corrects a problem where met is accessed for fixed-width fonts, for which it doesn't exist. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 82 +++++--------------------------- 1 file changed, 11 insertions(+), 71 deletions(-) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index 43274bb8f66..fb7f70a4b2a 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -1000,10 +1000,8 @@ static int truetype_set_cursor_visible(struct udevice *dev, bool visible, struct udevice *vid = dev->parent; struct video_priv *vid_priv = dev_get_uclass_priv(vid); struct console_tt_priv *priv = dev_get_priv(dev); - struct console_tt_metrics *met = priv->cur_met; - uint row, width, height, xoff; - void *start, *line; - uint out, val; + void *line; + uint height; if (xpl_phase() <= PHASE_SPL) return -ENOSYS; @@ -1022,79 +1020,21 @@ static int truetype_set_cursor_visible(struct udevice *dev, bool visible, x = VID_TO_PIXEL(vc_priv->xcur_frac); y = vc_priv->ycur; - height = met->font_size; - xoff = 0; - val = vid_priv->colour_bg ? 0 : 255; - width = VIDCONSOLE_CURSOR_WIDTH; + /* Get font height from current font type */ + if (priv->cur_fontdata) + height = priv->cur_fontdata->height; + else + height = priv->cur_met->font_size; /* Figure out where to write the cursor in the frame buffer */ - start = vid_priv->fb + y * vid_priv->line_length + + line = vid_priv->fb + y * vid_priv->line_length + x * VNBYTES(vid_priv->bpix); - line = start; - - /* draw a vertical bar in the correct position */ - for (row = 0; row < height; row++) { - switch (vid_priv->bpix) { - case VIDEO_BPP8: - if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { - u8 *dst = line + xoff; - int i; - - out = val; - for (i = 0; i < width; i++) { - if (vid_priv->colour_fg) - *dst++ |= out; - else - *dst++ &= out; - } - } - break; - case VIDEO_BPP16: { - u16 *dst = (u16 *)line + xoff; - int i; - if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { - for (i = 0; i < width; i++) { - out = val >> 3 | - (val >> 2) << 5 | - (val >> 3) << 11; - if (vid_priv->colour_fg) - *dst++ |= out; - else - *dst++ &= out; - } - } - break; - } - case VIDEO_BPP32: { - u32 *dst = (u32 *)line + xoff; - int i; - - if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { - for (i = 0; i < width; i++) { - int out; - - if (vid_priv->format == VIDEO_X2R10G10B10) - out = val << 2 | val << 12 | val << 22; - else - out = val | val << 8 | val << 16; - if (vid_priv->colour_fg) - *dst++ |= out; - else - *dst++ &= out; - } - } - break; - } - default: - return -ENOSYS; - } - - line += vid_priv->line_length; - } + /* Use the shared cursor drawing function */ + draw_cursor_vertically(&line, vid_priv, height, NORMAL_DIRECTION); - video_damage(dev->parent, x, y, width, height); + video_damage(dev->parent, x, y, VIDCONSOLE_CURSOR_WIDTH, height); return video_sync(vid, true); } -- 2.43.0

From: Simon Glass <sjg@chromium.org> There is normally a prompt which prevents the cursor ever being on the far left. However we should check for this to avoid a potential crash. Add a check for x being at least 0 in console_set_cursor_visible() Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_normal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 9509f81f40f..68d47eb8da6 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -92,11 +92,12 @@ static int __maybe_unused console_set_cursor_visible(struct udevice *dev, return -ENOSYS; x += index * fontdata->width; - start = vid_priv->fb + y * vid_priv->line_length + x * pbytes; /* place the cursor 1 pixel before the start of the next char */ - x -= 1; + if (x > 0) + x -= 1; + start = vid_priv->fb + y * vid_priv->line_length + x * pbytes; line = start; draw_cursor_vertically(&line, vid_priv, vc_priv->y_charsize, NORMAL_DIRECTION); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Convert a few functions in the video uclass to use the new uclass_id_foreach_dev() macro. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/video-uclass.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index 324817aa5ce..cd5c8dd8fad 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -127,15 +127,14 @@ static ulong alloc_fb(struct udevice *dev, ulong *addrp) int video_reserve(ulong *addrp) { struct udevice *dev; + struct uclass *uc; ulong size; if (IS_ENABLED(CONFIG_SPL_VIDEO_HANDOFF) && xpl_phase() == PHASE_BOARD_F) return 0; gd->video_top = *addrp; - for (uclass_find_first_device(UCLASS_VIDEO, &dev); - dev; - uclass_find_next_device(&dev)) { + uclass_id_foreach_dev(UCLASS_VIDEO, dev, uc) { size = alloc_fb(dev, addrp); debug("%s: Reserving %lx bytes at %lx for video device '%s'\n", __func__, size, *addrp, dev->name); @@ -539,11 +538,10 @@ int video_sync(struct udevice *vid, bool force) void video_sync_all(void) { struct udevice *dev; + struct uclass *uc; int ret; - for (uclass_find_first_device(UCLASS_VIDEO, &dev); - dev; - uclass_find_next_device(&dev)) { + uclass_id_foreach_dev(UCLASS_VIDEO, dev, uc) { if (device_active(dev)) { ret = video_sync(dev, true); if (ret) @@ -555,14 +553,13 @@ void video_sync_all(void) bool video_is_active(void) { struct udevice *dev; + struct uclass *uc; /* Assume video to be active if SPL passed video hand-off to U-boot */ if (IS_ENABLED(CONFIG_SPL_VIDEO_HANDOFF) && xpl_phase() > PHASE_SPL) return true; - for (uclass_find_first_device(UCLASS_VIDEO, &dev); - dev; - uclass_find_next_device(&dev)) { + uclass_id_foreach_dev(UCLASS_VIDEO, dev, uc) { if (device_active(dev)) return true; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a way to tell the console that the machine is idle. This will be used (later) to show the cursor. Call the video console sync after that, so that any updates are shown. Keep the video_sync_all() for the case where CONFIG_CURSOR is not enabled, to reduce code size. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/vidconsole-uclass.c | 4 ++++ drivers/video/video-uclass.c | 15 ++++++++++++++- include/video_console.h | 7 +++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index cb7212e9730..46fd355c05f 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -837,3 +837,7 @@ void vidconsole_set_bitmap_font(struct udevice *dev, } vc_priv->xstart_frac = 0; } + +void vidconsole_idle(struct udevice *dev) +{ +} diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c index cd5c8dd8fad..be014a770d0 100644 --- a/drivers/video/video-uclass.c +++ b/drivers/video/video-uclass.c @@ -621,7 +621,20 @@ int video_default_font_height(struct udevice *dev) static void video_idle(struct cyclic_info *cyc) { - video_sync_all(); + if (CONFIG_IS_ENABLED(CURSOR)) { + struct udevice *cons; + struct uclass *uc; + + /* Handle cursor display for each video console */ + uclass_id_foreach_dev(UCLASS_VIDEO_CONSOLE, cons, uc) { + if (device_active(cons)) { + vidconsole_idle(cons); + video_sync(cons->parent, true); + } + } + } else { + video_sync_all(); + } } void video_set_white_on_black(struct udevice *dev, bool white_on_black) diff --git a/include/video_console.h b/include/video_console.h index 8cd1ccacb0f..842ead8d6a1 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -613,4 +613,11 @@ void vidconsole_set_quiet(struct udevice *dev, bool quiet); void vidconsole_set_bitmap_font(struct udevice *dev, struct video_fontdata *fontdata); +/* + * vidconsole_idle() - Handle periodic cursor display during idle time + * + * @dev: vidconsole device + */ +void vidconsole_idle(struct udevice *dev); + #endif -- 2.43.0

From: Simon Glass <sjg@chromium.org> We need to keep track of various things with the cursor, so create a separate struct within the console. Add some Signed-off-by: Simon Glass <sjg@chromium.org> --- include/video_console.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/include/video_console.h b/include/video_console.h index 842ead8d6a1..ba34bb8e19f 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -23,6 +23,28 @@ enum { VIDCONSOLE_CURSOR_WIDTH = 2, }; +/** + * struct vidconsole_cursor - cursor state for a video console + * + * The cursor is set up and maintained by the vidconsole. It is a simple + * vertical bar of width VIDCONSOLE_CURSOR_WIDTH shown in the foreground colour. + * + * @visible: cursor is currently visible + * @x: cursor left X position in pixels + * @y: cursor top Y position in pixels + * @height: height of cursor in pixels + * @index: cursor index within the CLI or field being edited + */ +struct vidconsole_cursor { + bool visible; + + /* filled in by get_cursor_info(): */ + uint x; + uint y; + uint height; + uint index; +}; + /** * struct vidconsole_priv - uclass-private data about a console device * @@ -55,6 +77,7 @@ enum { * @escape_buf: Buffer to accumulate escape sequence * @utf8_buf: Buffer to accumulate UTF-8 byte sequence * @quiet: Suppress all output from stdio + * @curs: Cursor state and management */ struct vidconsole_priv { struct stdio_dev sdev; @@ -80,6 +103,7 @@ struct vidconsole_priv { char escape_buf[32]; char utf8_buf[5]; bool quiet; + struct vidconsole_cursor curs; }; /** -- 2.43.0

From: Simon Glass <sjg@chromium.org> For now the cursor is always vertical, so part of this name is redundant. Rename it to cursor_show(), which is what it does. We will eventually have a cursor_hide() to match it. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_core.c | 5 +++-- drivers/video/console_normal.c | 3 +-- drivers/video/console_truetype.c | 2 +- drivers/video/vidconsole_internal.h | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index aec51dc809d..36e7f81dc0a 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -160,8 +160,8 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri return ret; } -int draw_cursor_vertically(void **line, struct video_priv *vid_priv, - uint height, bool direction) +int cursor_show(void **line, struct video_priv *vid_priv, uint height, + bool direction) { int step, line_step, pbytes, ret; uint value; @@ -188,6 +188,7 @@ int draw_cursor_vertically(void **line, struct video_priv *vid_priv, fill_pixel_and_goto_next(&dst, value, pbytes, step); *line += line_step; } + return ret; } diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 68d47eb8da6..3865870dcd5 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -99,8 +99,7 @@ static int __maybe_unused console_set_cursor_visible(struct udevice *dev, start = vid_priv->fb + y * vid_priv->line_length + x * pbytes; line = start; - draw_cursor_vertically(&line, vid_priv, vc_priv->y_charsize, - NORMAL_DIRECTION); + cursor_show(&line, vid_priv, vc_priv->y_charsize, NORMAL_DIRECTION); return 0; } diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index fb7f70a4b2a..babab5eb2c3 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -1032,7 +1032,7 @@ static int truetype_set_cursor_visible(struct udevice *dev, bool visible, x * VNBYTES(vid_priv->bpix); /* Use the shared cursor drawing function */ - draw_cursor_vertically(&line, vid_priv, height, NORMAL_DIRECTION); + cursor_show(&line, vid_priv, height, NORMAL_DIRECTION); video_damage(dev->parent, x, y, VIDCONSOLE_CURSOR_WIDTH, height); diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index af2cca8791c..02b73296292 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -96,7 +96,7 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri struct video_fontdata *fontdata, bool direction); /** - * draw_cursor_vertically() - Draw a simple vertical cursor + * cursor_show() - Draw a simple vertical cursor * * @line: pointer to framebuffer buffer: upper left cursor corner * @vid_priv: driver private data @@ -116,8 +116,8 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri * * Return: 0, if success, or else error code. */ -int draw_cursor_vertically(void **line, struct video_priv *vid_priv, - uint height, bool direction); +int cursor_show(void **line, struct video_priv *vid_priv, uint height, + bool direction); /** * console probe function. -- 2.43.0

From: Simon Glass <sjg@chromium.org> We don't need to pass a pointer to a pointer, so just pass a normal pointer. This is simpler to understand. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_core.c | 6 +++--- drivers/video/console_normal.c | 5 ++--- drivers/video/console_truetype.c | 2 +- drivers/video/vidconsole_internal.h | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index 36e7f81dc0a..575d0bfe2b8 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -160,7 +160,7 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri return ret; } -int cursor_show(void **line, struct video_priv *vid_priv, uint height, +int cursor_show(void *line, struct video_priv *vid_priv, uint height, bool direction) { int step, line_step, pbytes, ret; @@ -183,10 +183,10 @@ int cursor_show(void **line, struct video_priv *vid_priv, uint height, value = vid_priv->colour_fg; for (int row = 0; row < height; row++) { - dst = *line; + dst = line; for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++) fill_pixel_and_goto_next(&dst, value, pbytes, step); - *line += line_step; + line += line_step; } return ret; diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 3865870dcd5..315d3daa5ce 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -85,7 +85,7 @@ static int __maybe_unused console_set_cursor_visible(struct udevice *dev, struct console_simple_priv *priv = dev_get_priv(dev); struct video_fontdata *fontdata = priv->fontdata; int pbytes = VNBYTES(vid_priv->bpix); - void *start, *line; + void *start; /* for now, this is not used outside expo */ if (!IS_ENABLED(CONFIG_EXPO)) @@ -98,8 +98,7 @@ static int __maybe_unused console_set_cursor_visible(struct udevice *dev, x -= 1; start = vid_priv->fb + y * vid_priv->line_length + x * pbytes; - line = start; - cursor_show(&line, vid_priv, vc_priv->y_charsize, NORMAL_DIRECTION); + cursor_show(start, vid_priv, vc_priv->y_charsize, NORMAL_DIRECTION); return 0; } diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index babab5eb2c3..eedc285903b 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -1032,7 +1032,7 @@ static int truetype_set_cursor_visible(struct udevice *dev, bool visible, x * VNBYTES(vid_priv->bpix); /* Use the shared cursor drawing function */ - cursor_show(&line, vid_priv, height, NORMAL_DIRECTION); + cursor_show(line, vid_priv, height, NORMAL_DIRECTION); video_damage(dev->parent, x, y, VIDCONSOLE_CURSOR_WIDTH, height); diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index 02b73296292..0654a8f98e6 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -116,7 +116,7 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri * * Return: 0, if success, or else error code. */ -int cursor_show(void **line, struct video_priv *vid_priv, uint height, +int cursor_show(void *line, struct video_priv *vid_priv, uint height, bool direction); /** -- 2.43.0

From: Simon Glass <sjg@chromium.org> Rather than having the truetype driver draw the cursor, make it just return the information needed to draw the cursor. This will make it possible for the normal console to support a cursor too. Add a check for the cursor being entirely within the framebuffer. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_core.c | 14 +++++--- drivers/video/console_normal.c | 18 ++++++---- drivers/video/console_truetype.c | 42 ++++++++++-------------- drivers/video/vidconsole-uclass.c | 51 +++++++++++++++++++++++++---- drivers/video/vidconsole_internal.h | 14 +++++--- include/video_console.h | 29 +++++++++++++--- 6 files changed, 119 insertions(+), 49 deletions(-) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index 575d0bfe2b8..6db42e63ea9 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -160,12 +160,12 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri return ret; } -int cursor_show(void *line, struct video_priv *vid_priv, uint height, +int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, bool direction) { int step, line_step, pbytes, ret; + void *line, *dst; uint value; - void *dst; ret = check_bpix_support(vid_priv->bpix); if (ret) @@ -180,16 +180,22 @@ int cursor_show(void *line, struct video_priv *vid_priv, uint height, line_step = vid_priv->line_length; } + /* Figure out where to write the cursor in the frame buffer */ + line = vid_priv->fb + curs->y * vid_priv->line_length + + curs->x * VNBYTES(vid_priv->bpix); + value = vid_priv->colour_fg; - for (int row = 0; row < height; row++) { + for (int row = 0; row < curs->height; row++) { dst = line; + for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++) fill_pixel_and_goto_next(&dst, value, pbytes, step); + line += line_step; } - return ret; + return 0; } int console_probe(struct udevice *dev) diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 315d3daa5ce..ad7eb4661a4 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -75,17 +75,18 @@ int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp) return console_fixed_putc_xy(dev, x_frac, y, cp, priv->fontdata); } -static int __maybe_unused console_set_cursor_visible(struct udevice *dev, - bool visible, uint x, - uint y, uint index) +static __maybe_unused int console_get_cursor_info(struct udevice *dev, + bool visible, uint x, uint y, + uint index) { struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct udevice *vid = dev->parent; struct video_priv *vid_priv = dev_get_uclass_priv(vid); struct console_simple_priv *priv = dev_get_priv(dev); struct video_fontdata *fontdata = priv->fontdata; + struct vidconsole_cursor *curs = &vc_priv->curs; int pbytes = VNBYTES(vid_priv->bpix); - void *start; + void *start, *line; /* for now, this is not used outside expo */ if (!IS_ENABLED(CONFIG_EXPO)) @@ -98,7 +99,12 @@ static int __maybe_unused console_set_cursor_visible(struct udevice *dev, x -= 1; start = vid_priv->fb + y * vid_priv->line_length + x * pbytes; - cursor_show(start, vid_priv, vc_priv->y_charsize, NORMAL_DIRECTION); + line = start; + + /* Store line pointer and height in cursor struct */ + curs->x = x; + curs->y = y; + curs->height = vc_priv->y_charsize; return 0; } @@ -116,7 +122,7 @@ struct vidconsole_ops console_ops = { .get_font = console_simple_get_font, .select_font = console_simple_select_font, #ifdef CONFIG_CURSOR - .set_cursor_visible = console_set_cursor_visible, + .get_cursor_info = console_get_cursor_info, #endif }; diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index eedc285903b..eee4ea2e2a9 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -993,33 +993,30 @@ static int truetype_entry_restore(struct udevice *dev, struct abuf *buf) return 0; } -static int truetype_set_cursor_visible(struct udevice *dev, bool visible, - uint x, uint y, uint index) +static int truetype_get_cursor_info(struct udevice *dev, bool visible, + uint x, uint y, uint index) { struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); - struct udevice *vid = dev->parent; - struct video_priv *vid_priv = dev_get_uclass_priv(vid); struct console_tt_priv *priv = dev_get_priv(dev); - void *line; + struct vidconsole_cursor *curs = &vc_priv->curs; uint height; if (xpl_phase() <= PHASE_SPL) return -ENOSYS; - if (!visible) - return 0; - /* * figure out where to place the cursor. This driver ignores the * passed-in values, since an entry_restore() must have been done before * calling this function. */ - if (index < priv->pos_ptr) - x = VID_TO_PIXEL(priv->pos[index].xpos_frac); - else - x = VID_TO_PIXEL(vc_priv->xcur_frac); - - y = vc_priv->ycur; + if (visible) { + index = priv->pos_ptr; + if (index < priv->pos_ptr) + x = VID_TO_PIXEL(priv->pos[index].xpos_frac); + else + x = VID_TO_PIXEL(vc_priv->xcur_frac); + y = vc_priv->ycur; + } /* Get font height from current font type */ if (priv->cur_fontdata) @@ -1027,16 +1024,13 @@ static int truetype_set_cursor_visible(struct udevice *dev, bool visible, else height = priv->cur_met->font_size; - /* Figure out where to write the cursor in the frame buffer */ - line = vid_priv->fb + y * vid_priv->line_length + - x * VNBYTES(vid_priv->bpix); - - /* Use the shared cursor drawing function */ - cursor_show(line, vid_priv, height, NORMAL_DIRECTION); + /* Store line pointer and height in cursor struct */ + curs->x = x; + curs->y = y; + curs->index = index; + curs->height = height; - video_damage(dev->parent, x, y, VIDCONSOLE_CURSOR_WIDTH, height); - - return video_sync(vid, true); + return 0; } const char *console_truetype_get_font_size(struct udevice *dev, uint *sizep) @@ -1101,7 +1095,7 @@ struct vidconsole_ops console_truetype_ops = { .nominal = truetype_nominal, .entry_save = truetype_entry_save, .entry_restore = truetype_entry_restore, - .set_cursor_visible = truetype_set_cursor_visible + .get_cursor_info = truetype_get_cursor_info, }; U_BOOT_DRIVER(vidconsole_truetype) = { diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 46fd355c05f..479793bc227 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -17,6 +17,7 @@ #include <dm.h> #include <video.h> #include <video_console.h> +#include "vidconsole_internal.h" #include <video_font.h> /* Bitmap font for code page 437 */ #include <linux/ctype.h> @@ -702,21 +703,59 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf) } #ifdef CONFIG_CURSOR -int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, - uint x, uint y, uint index) +int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index) { + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); struct vidconsole_ops *ops = vidconsole_get_ops(dev); + struct vidconsole_cursor *curs = &priv->curs; int ret; - if (ops->set_cursor_visible) { - ret = ops->set_cursor_visible(dev, visible, x, y, index); - if (ret != -ENOSYS) + /* find out where the cursor should be drawn */ + if (ops->get_cursor_info) { + ret = ops->get_cursor_info(dev, true, x, y, index); + if (ret && ret != -ENOSYS) + return ret; + } + + /* If the driver stored cursor line and height, use them for drawing */ + if (curs->height) { + struct udevice *vid = dev_get_parent(dev); + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + + /* + * avoid drawing off the display - we assume that the driver + * ensures that curs->y < vid_priv->ysize + */ + curs->height = min(curs->height, vid_priv->ysize - curs->y); + + ret = cursor_show(curs, vid_priv, NORMAL_DIRECTION); + if (ret) + return ret; + + /* Update display damage for cursor area */ + video_damage(vid, curs->x, curs->y, VIDCONSOLE_CURSOR_WIDTH, + curs->height); + } + + priv->curs.visible = true; + + return 0; +} + +int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, + uint x, uint y, uint index) +{ + if (visible) { + int ret; + + ret = vidconsole_show_cursor(dev, x, y, index); + if (ret) return ret; } return 0; } -#endif +#endif /* CONFIG_CURSOR */ void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg, enum colour_idx bg, struct vidconsole_colour *old) diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index 0654a8f98e6..c008b9cf7d3 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -9,6 +9,10 @@ #include <charset.h> #include <config.h> +struct udevice; +struct vidconsole_cursor; +struct video_priv; + #define FLIPPED_DIRECTION 1 #define NORMAL_DIRECTION 0 @@ -98,10 +102,10 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri /** * cursor_show() - Draw a simple vertical cursor * - * @line: pointer to framebuffer buffer: upper left cursor corner - * @vid_priv: driver private data - * @height: height of the cursor in pixels - * @param direction controls cursor orientation. Can be normal or flipped. + * @curs: cursor information + * @vid_priv: video-device info + * @direction: controls cursor orientation (normal or flipped) + * * When normal: When flipped: *|-----------------------------------------------| *| * | line stepping | @@ -116,7 +120,7 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri * * Return: 0, if success, or else error code. */ -int cursor_show(void *line, struct video_priv *vid_priv, uint height, +int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, bool direction); /** diff --git a/include/video_console.h b/include/video_console.h index ba34bb8e19f..d86cac42110 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -330,9 +330,9 @@ struct vidconsole_ops { int (*entry_restore)(struct udevice *dev, struct abuf *buf); /** - * set_cursor_visible() - Show or hide the cursor + * get_cursor_info() - Get cursor position info * - * Shows or hides a cursor at the current position + * Calculates and stores cursor position information * * @dev: Console device to use * @visible: true to show the cursor, false to hide it @@ -341,8 +341,8 @@ struct vidconsole_ops { * @index: Character position (0 = at start) * Return: 0 if OK, -ve on error */ - int (*set_cursor_visible)(struct udevice *dev, bool visible, - uint x, uint y, uint index); + int (*get_cursor_info)(struct udevice *dev, bool visible, + uint x, uint y, uint index); }; /* Get a pointer to the driver operations for a video console device */ @@ -430,6 +430,21 @@ int vidconsole_entry_save(struct udevice *dev, struct abuf *buf); int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf); #ifdef CONFIG_CURSOR +/** + * vidconsole_show_cursor() - Show the cursor + * + * Shows a cursor at the specified position. The position is passed in, but for + * the truetype console it is not actually used, since it tracks where the + * cursor must go. + * + * @dev: Console device to use + * @x: X position in pixels + * @y: Y position in pixels + * @index: Character position (0 = at start) + * Return: 0 if OK, -ve on error + */ +int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index); + /** * vidconsole_set_cursor_visible() - Show or hide the cursor * @@ -445,6 +460,12 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf); int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, uint x, uint y, uint index); #else +static inline int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, + uint index) +{ + return 0; +} + static inline int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, uint x, uint y, uint index) -- 2.43.0

From: Simon Glass <sjg@chromium.org> Keep track of the current character index in the current CLI entry. This corresponds to the cursor position and is numbered from zero. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/vidconsole-uclass.c | 4 ++++ include/video_console.h | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 479793bc227..830e3ca306e 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -79,6 +79,9 @@ static int vidconsole_back(struct udevice *dev) if (priv->ycur < 0) priv->ycur = 0; } + assert(priv->cli_index); + cli_index_adjust(priv, -1); + return video_sync(dev->parent, false); } @@ -455,6 +458,7 @@ static int vidconsole_output_glyph(struct udevice *dev, int ch) priv->last_ch = ch; if (priv->xcur_frac >= priv->xsize_frac) vidconsole_newline(dev); + cli_index_adjust(priv, 1); return 0; } diff --git a/include/video_console.h b/include/video_console.h index d86cac42110..5074880c674 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -70,6 +70,7 @@ struct vidconsole_cursor { * @xsize_frac: Width of the display in fractional units * @xstart_frac: Left margin for the text console in fractional units * @last_ch: Last character written to the text console on this line + * @cli_index: Character index into the CLI text (0=start) * @escape: TRUE if currently accumulating an ANSI escape sequence * @escape_len: Length of accumulated escape sequence so far * @col_saved: Saved X position, in fractional units (VID_TO_POS(x)) @@ -91,6 +92,7 @@ struct vidconsole_priv { int xsize_frac; int xstart_frac; int last_ch; + int cli_index; /* * ANSI escape sequences are accumulated character by character, * starting after the ESC char (0x1b) until the entire sequence @@ -474,6 +476,12 @@ static inline int vidconsole_set_cursor_visible(struct udevice *dev, } #endif /* CONFIG_CURSOR */ +static inline void cli_index_adjust(struct vidconsole_priv *priv, int by) +{ + if (CONFIG_IS_ENABLED(CURSOR)) + priv->cli_index += by; +} + /** * vidconsole_push_colour() - Temporarily change the font colour * -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a new mark_start() method for the console, which indicates that the CLI prompt has been written to the display and any following characters will be user input. There are two cases to consider, tracked by an indent flag in struct vidconsole_cursor: - normal CLI entry where new lines start at the left of the console - expo entry where new lines start at the same position as the previous line (indent=true) Record this position in the uclass info, so it is available to console drivers. Signed-off-by: Simon Glass <sjg@chromium.org> --- common/cli_readline.c | 5 ++++ drivers/video/vidconsole-uclass.c | 39 +++++++++++++++++++++++++++ include/video_console.h | 44 +++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/common/cli_readline.c b/common/cli_readline.c index 2326e4b4f37..dc27a962e9d 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -16,6 +16,7 @@ #include <pager.h> #include <time.h> #include <watchdog.h> +#include <video_console.h> #include <linux/errno.h> #include <asm/global_data.h> @@ -676,6 +677,8 @@ int cli_readline_into_buffer(const char *const prompt, char *buffer, if (prompt) puts(prompt); + /* tell the vidconsole the cursor is at its start position */ + vidconsole_readline_start(false); rc = cread_line(prompt, p, &len, timeout); rc = rc < 0 ? rc : len; @@ -686,5 +689,7 @@ int cli_readline_into_buffer(const char *const prompt, char *buffer, pager_set_bypass(gd_pager(), old_bypass); pager_reset(gd_pager()); + vidconsole_readline_end(); + return rc; } diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 830e3ca306e..0a7cf5ad81a 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -761,6 +761,25 @@ int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, } #endif /* CONFIG_CURSOR */ +int vidconsole_mark_start(struct udevice *dev) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + + priv->xmark_frac = priv->xcur_frac; + priv->ymark = priv->ycur; + priv->cli_index = 0; + if (ops->mark_start) { + int ret; + + ret = ops->mark_start(dev); + if (ret != -ENOSYS) + return ret; + } + + return 0; +} + void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg, enum colour_idx bg, struct vidconsole_colour *old) { @@ -884,3 +903,23 @@ void vidconsole_set_bitmap_font(struct udevice *dev, void vidconsole_idle(struct udevice *dev) { } + +#ifdef CONFIG_CURSOR +void vidconsole_readline_start(bool indent) +{ + struct uclass *uc; + struct udevice *dev; + + uclass_id_foreach_dev(UCLASS_VIDEO_CONSOLE, dev, uc) { + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + + priv->curs.indent = indent; + vidconsole_mark_start(dev); + } +} + +void vidconsole_readline_end(void) +{ + /* TODO: mark the end */ +} +#endif /* CURSOR */ diff --git a/include/video_console.h b/include/video_console.h index 5074880c674..c5450f70c4d 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -30,6 +30,7 @@ enum { * vertical bar of width VIDCONSOLE_CURSOR_WIDTH shown in the foreground colour. * * @visible: cursor is currently visible + * @indent: indent subsequent lines to the same position as the first line * @x: cursor left X position in pixels * @y: cursor top Y position in pixels * @height: height of cursor in pixels @@ -37,6 +38,7 @@ enum { */ struct vidconsole_cursor { bool visible; + bool indent; /* filled in by get_cursor_info(): */ uint x; @@ -70,6 +72,8 @@ struct vidconsole_cursor { * @xsize_frac: Width of the display in fractional units * @xstart_frac: Left margin for the text console in fractional units * @last_ch: Last character written to the text console on this line + * @xmark_frac: X position of start of CLI text entry, in fractional units + * @ymark: Y position of start of CLI text * @cli_index: Character index into the CLI text (0=start) * @escape: TRUE if currently accumulating an ANSI escape sequence * @escape_len: Length of accumulated escape sequence so far @@ -92,6 +96,8 @@ struct vidconsole_priv { int xsize_frac; int xstart_frac; int last_ch; + int xmark_frac; + int ymark; int cli_index; /* * ANSI escape sequences are accumulated character by character, @@ -345,6 +351,17 @@ struct vidconsole_ops { */ int (*get_cursor_info)(struct udevice *dev, bool visible, uint x, uint y, uint index); + + /** + * mark_start() - Mark the current position as the state of CLI entry + * + * This indicates that a new CLI entry is starting, so the user will be + * entering characters from this point. The console can use this to set + * the beginning point for the cursor. + * + * @dev: Console device to use + */ + int (*mark_start)(struct udevice *dev); }; /* Get a pointer to the driver operations for a video console device */ @@ -461,6 +478,24 @@ int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index); */ int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, uint x, uint y, uint index); + +/** + * vidconsole_readline_start() - Enable cursor for all video consoles + * + * Called at the start of command line input to show cursors on all + * active video consoles + * + * @indent: indent subsequent lines to the same position as the first line + */ +void vidconsole_readline_start(bool indent); + +/** + * vidconsole_readline_end() - Disable cursor for all video consoles + * + * Called at the end of command line input to hide cursors on all + * active video consoles + */ +void vidconsole_readline_end(void); #else static inline int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index) @@ -474,6 +509,15 @@ static inline int vidconsole_set_cursor_visible(struct udevice *dev, { return 0; } + +static inline void vidconsole_readline_start(bool indent) +{ +} + +static inline void vidconsole_readline_end(void) +{ +} + #endif /* CONFIG_CURSOR */ static inline void cli_index_adjust(struct vidconsole_priv *priv, int by) -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add some debugging which can be used to manually check that truetype is kerning against the expected character. This is tested by the image-based tests but they are sometimes hard to debug. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 10 ++++++++++ drivers/video/vidconsole-uclass.c | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index eee4ea2e2a9..d87b3828bb0 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -6,6 +6,7 @@ #define LOG_CATEGORY UCLASS_VIDEO #include <abuf.h> +#include <console.h> #include <dm.h> #include <log.h> #include <malloc.h> @@ -321,8 +322,17 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, if (vc_priv->last_ch) { kern = stbtt_GetCodepointKernAdvance(font, vc_priv->last_ch, cp); + if (_DEBUG) { + console_printf_select_stderr(true, "kern %c (%02x)", + vc_priv->last_ch, + vc_priv->last_ch); + } xpos += met->scale * kern; } + if (_DEBUG) { + console_printf_select_stderr(true, " %c (%02x)\n", + cp >= ' ' ? cp : ' ', cp); + } /* * Figure out where the cursor will move to after this character, and diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 0a7cf5ad81a..9d161f4688e 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -442,6 +442,11 @@ static int vidconsole_output_glyph(struct udevice *dev, int ch) struct vidconsole_priv *priv = dev_get_uclass_priv(dev); int ret; + if (_DEBUG) { + console_printf_select_stderr(true, + "glyph last_ch '%c': ch '%c' (%02x): ", + priv->last_ch, ch >= ' ' ? ch : ' ', ch); + } /* * Failure of this function normally indicates an unsupported * colour depth. Check this and return an error to help with -- 2.43.0

From: Simon Glass <sjg@chromium.org> Implement the mark_start() method for the truetype console by recording which pos[] record corresponds to this event. We can be sure that the user will not be able to backspace past this point. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index d87b3828bb0..edd2eb0a309 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -173,6 +173,8 @@ struct console_tt_metrics { * start of the current command line. * @pos_ptr: Current position in the position history * @cur_fontdata: Current fixed font data (NULL if using TrueType) + * @pos_start: Value of pos_ptr when the cursor is at the start of the text + * being entered by the user */ struct console_tt_priv { struct console_tt_metrics *cur_met; @@ -181,6 +183,7 @@ struct console_tt_priv { struct pos_info pos[POS_HISTORY_SIZE]; int pos_ptr; struct video_fontdata *cur_fontdata; + int pos_start; }; /** @@ -1060,6 +1063,15 @@ const char *console_truetype_get_font_size(struct udevice *dev, uint *sizep) } } +static int truetype_mark_start(struct udevice *dev) +{ + struct console_tt_priv *priv = dev_get_priv(dev); + + priv->pos_start = priv->pos_ptr; + + return 0; +} + static int console_truetype_probe(struct udevice *dev) { struct console_tt_priv *priv = dev_get_priv(dev); @@ -1106,6 +1118,7 @@ struct vidconsole_ops console_truetype_ops = { .entry_save = truetype_entry_save, .entry_restore = truetype_entry_restore, .get_cursor_info = truetype_get_cursor_info, + .mark_start = truetype_mark_start, }; U_BOOT_DRIVER(vidconsole_truetype) = { -- 2.43.0

From: Simon Glass <sjg@chromium.org> The Truetype driver maintains a list of x and y positions for every character in the line being entered by the user. This allows it to backspace reliably without having to re-measure lots of text. For kerning, the video console maintains a last_ch variable which holds the last character written to the console. This allows accurate kerning between one character and the next. At present lash_ch is cleared on backspace, since we cannot know what the character before last_ch is. The slightly strange part is that the truetype console currently has no knowledge about what the characters were, only their x and y positions, with the x position being fractional. It also has no idea of the width of each character, since it doesn't need to: the CLI will always write out a new character in order to move forward during command-editing, since there is no actual concept of 'move the cursor to the right'. Part of the reason this works is that truetype implements backspace by actually clearing the character from the display. So if you type some text and then press the left arrow, it looks like it is doing a backspace. This has been a known limitation for some time. The correct way to implement left-arrow is to leave the display alone, only clearing it if characters are later added. This is necessary since Truetype fonts are OR'd onto the screen, which is assumed to be initially cleared to the background colour. We cannot do this clearing without knowing the width of the characters we need to clear, so add a 'width' to the struct pos_info for that. For kerning we must know the previous character to kern against, but we cannot yet make that change, since we don't want to kern against characters that were there before an erase. So that will be dealt with later, in 'Clear after the current char on insert'. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index edd2eb0a309..aabacd10afe 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -120,10 +120,14 @@ static double tt_acos(double val) * * @xpos_frac: Fractional X position in pixels (multiplied by VID_FRAC_DIV) * @ypos: Y position (pixels from the top) + * @width: Width of the character at this position in pixels (rounded up) + * @cp: Unicode code point of the character */ struct pos_info { int xpos_frac; int ypos; + int width; + int cp; }; /* @@ -175,6 +179,7 @@ struct console_tt_metrics { * @cur_fontdata: Current fixed font data (NULL if using TrueType) * @pos_start: Value of pos_ptr when the cursor is at the start of the text * being entered by the user + * @pos_count: Maximum value reached by pos_ptr (initially zero) */ struct console_tt_priv { struct console_tt_metrics *cur_met; @@ -184,6 +189,7 @@ struct console_tt_priv { int pos_ptr; struct video_fontdata *cur_fontdata; int pos_start; + int pos_count; }; /** @@ -354,7 +360,11 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, pos = &priv->pos[priv->pos_ptr]; pos->xpos_frac = vc_priv->xcur_frac; pos->ypos = vc_priv->ycur; + pos->width = (width_frac + VID_FRAC_DIV - 1) / VID_FRAC_DIV; + pos->cp = cp; priv->pos_ptr++; + if (priv->pos_ptr > priv->pos_count) + priv->pos_count = priv->pos_ptr; } /* @@ -530,6 +540,7 @@ static int console_truetype_entry_start(struct udevice *dev) /* A new input line has start, so clear our history */ priv->pos_ptr = 0; + priv->pos_count = 0; vc_priv->last_ch = 0; return 0; @@ -1000,6 +1011,7 @@ static int truetype_entry_restore(struct udevice *dev, struct abuf *buf) vc_priv->xcur_frac = store.cur.xpos_frac; vc_priv->ycur = store.cur.ypos; priv->pos_ptr = store.priv.pos_ptr; + priv->pos_count = store.priv.pos_count; memcpy(priv->pos, store.priv.pos, store.priv.pos_ptr * sizeof(struct pos_info)); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Call the appropriate vidconsole functions to ensure that the cursor will be enabled while a textline is open. Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/scene_textline.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boot/scene_textline.c b/boot/scene_textline.c index b595d3477e4..ba39cfb7cee 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -145,6 +145,9 @@ int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline, /* Copy the backup text from the scene buffer */ memcpy(abuf_data(&tline->buf), abuf_data(&scn->buf), abuf_size(&scn->buf)); + + /* cursor is not needed now */ + vidconsole_readline_end(); } else { event->type = EXPOACT_QUIT; log_debug("menu quit\n"); @@ -241,5 +244,8 @@ int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline) if (ret) return log_msg_ret("sav", ret); + /* make sure the cursor is visible */ + vidconsole_readline_start(true); + return 0; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> The cursor should only be enabled if the user is entering something. This can be at the CLI or in an expo. Provide a flag to track it, which we can (later) use to determine whether or not to draw the cursor. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/vidconsole-uclass.c | 10 +++++++++- include/video_console.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 9d161f4688e..9ab331af68a 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -919,12 +919,20 @@ void vidconsole_readline_start(bool indent) struct vidconsole_priv *priv = dev_get_uclass_priv(dev); priv->curs.indent = indent; + priv->curs.enabled = true; vidconsole_mark_start(dev); } } void vidconsole_readline_end(void) { - /* TODO: mark the end */ + struct uclass *uc; + struct udevice *dev; + + uclass_id_foreach_dev(UCLASS_VIDEO_CONSOLE, dev, uc) { + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + + priv->curs.enabled = false; + } } #endif /* CURSOR */ diff --git a/include/video_console.h b/include/video_console.h index c5450f70c4d..af2b8499bb4 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -29,6 +29,7 @@ enum { * The cursor is set up and maintained by the vidconsole. It is a simple * vertical bar of width VIDCONSOLE_CURSOR_WIDTH shown in the foreground colour. * + * @enabled: cursor is active (e.g. during readline) * @visible: cursor is currently visible * @indent: indent subsequent lines to the same position as the first line * @x: cursor left X position in pixels @@ -37,6 +38,7 @@ enum { * @index: cursor index within the CLI or field being edited */ struct vidconsole_cursor { + bool enabled; bool visible; bool indent; -- 2.43.0

From: Simon Glass <sjg@chromium.org> There is only one user of this function. Update it to use the new vidconsole_show_cursor() instead. Remove the now-unused vidconsole_set_cursor_visible() Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/scene_textline.c | 4 ++-- drivers/video/vidconsole-uclass.c | 13 ------------- include/video_console.h | 24 +----------------------- 3 files changed, 3 insertions(+), 38 deletions(-) diff --git a/boot/scene_textline.c b/boot/scene_textline.c index ba39cfb7cee..3d4269a8e05 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -214,8 +214,8 @@ int scene_textline_render_deps(struct scene *scn, if (ret) return log_msg_ret("sav", ret); - vidconsole_set_cursor_visible(cons, true, txt->obj.bbox.x0, - txt->obj.bbox.y0, scn->cls.num); + vidconsole_show_cursor(cons, txt->obj.bbox.x0, + txt->obj.bbox.y0, scn->cls.num); } return 0; diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 9ab331af68a..65c912a4f6f 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -751,19 +751,6 @@ int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index) return 0; } -int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, - uint x, uint y, uint index) -{ - if (visible) { - int ret; - - ret = vidconsole_show_cursor(dev, x, y, index); - if (ret) - return ret; - } - - return 0; -} #endif /* CONFIG_CURSOR */ int vidconsole_mark_start(struct udevice *dev) diff --git a/include/video_console.h b/include/video_console.h index af2b8499bb4..0b8742c5ee9 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -466,21 +466,6 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf); */ int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index); -/** - * vidconsole_set_cursor_visible() - Show or hide the cursor - * - * Shows or hides a cursor at the current position - * - * @dev: Console device to use - * @visible: true to show the cursor, false to hide it - * @x: X position in pixels - * @y: Y position in pixels - * @index: Character position (0 = at start) - * Return: 0 if OK, -ve on error - */ -int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, - uint x, uint y, uint index); - /** * vidconsole_readline_start() - Enable cursor for all video consoles * @@ -505,13 +490,6 @@ static inline int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, return 0; } -static inline int vidconsole_set_cursor_visible(struct udevice *dev, - bool visible, uint x, uint y, - uint index) -{ - return 0; -} - static inline void vidconsole_readline_start(bool indent) { } @@ -519,7 +497,6 @@ static inline void vidconsole_readline_start(bool indent) static inline void vidconsole_readline_end(void) { } - #endif /* CONFIG_CURSOR */ static inline void cli_index_adjust(struct vidconsole_priv *priv, int by) @@ -529,6 +506,7 @@ static inline void cli_index_adjust(struct vidconsole_priv *priv, int by) } /** + * vidconsole_push_colour() - Temporarily change the font colour * * @dev: Device to adjust -- 2.43.0

From: Simon Glass <sjg@chromium.org> The console supports keeping track of the index and the start position of the CLI entry. Use this instead of the passed-in values. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_normal.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index ad7eb4661a4..4b00732f98d 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -80,31 +80,28 @@ static __maybe_unused int console_get_cursor_info(struct udevice *dev, uint index) { struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); - struct udevice *vid = dev->parent; - struct video_priv *vid_priv = dev_get_uclass_priv(vid); struct console_simple_priv *priv = dev_get_priv(dev); struct video_fontdata *fontdata = priv->fontdata; struct vidconsole_cursor *curs = &vc_priv->curs; - int pbytes = VNBYTES(vid_priv->bpix); - void *start, *line; /* for now, this is not used outside expo */ if (!IS_ENABLED(CONFIG_EXPO)) return -ENOSYS; + x = VID_TO_PIXEL(vc_priv->xmark_frac); + y = vc_priv->ymark; + index = vc_priv->cli_index; x += index * fontdata->width; /* place the cursor 1 pixel before the start of the next char */ if (x > 0) x -= 1; - start = vid_priv->fb + y * vid_priv->line_length + x * pbytes; - line = start; - /* Store line pointer and height in cursor struct */ curs->x = x; curs->y = y; curs->height = vc_priv->y_charsize; + curs->index = index; return 0; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide these two methods so that we can use expo lineedits with the normal console (i.e. no truetype). This allows the cursor to be positioned correctly when editing the lineedit and rendering the expo. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_normal.c | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 4b00732f98d..ac7053d60a8 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -8,11 +8,18 @@ #include <charset.h> #include <dm.h> +#include <spl.h> #include <video.h> #include <video_console.h> #include <video_font.h> /* Get font data, width and height */ #include "vidconsole_internal.h" +struct console_store { + int xpos_frac; + int ypos; + int cli_index; +}; + static int console_set_row(struct udevice *dev, uint row, int clr) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); @@ -106,6 +113,45 @@ static __maybe_unused int console_get_cursor_info(struct udevice *dev, return 0; } +static __maybe_unused int normal_entry_save(struct udevice *dev, + struct abuf *buf) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct console_store store; + const uint size = sizeof(store); + + if (xpl_phase() <= PHASE_SPL) + return -ENOSYS; + + if (!abuf_realloc(buf, size)) + return log_msg_ret("sav", -ENOMEM); + + store.xpos_frac = vc_priv->xcur_frac; + store.ypos = vc_priv->ycur; + store.cli_index = vc_priv->cli_index; + memcpy(abuf_data(buf), &store, size); + + return 0; +} + +static __maybe_unused int normal_entry_restore(struct udevice *dev, + struct abuf *buf) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct console_store store; + + if (xpl_phase() <= PHASE_SPL) + return -ENOSYS; + + memcpy(&store, abuf_data(buf), sizeof(store)); + + vc_priv->xcur_frac = store.xpos_frac; + vc_priv->ycur = store.ypos; + vc_priv->cli_index = store.cli_index; + + return 0; +} + static int console_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp) { return console_normal_putc_xy(dev, x_frac, y, cp); @@ -120,6 +166,8 @@ struct vidconsole_ops console_ops = { .select_font = console_simple_select_font, #ifdef CONFIG_CURSOR .get_cursor_info = console_get_cursor_info, + .entry_save = normal_entry_save, + .entry_restore = normal_entry_restore, #endif }; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Now that the console tracks the CLI index, remove the unnecessary parameters. Both the normal and truetype consoles use the information provided by the console. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_normal.c | 5 ++--- drivers/video/console_truetype.c | 20 +++++++++----------- drivers/video/vidconsole-uclass.c | 11 ++++++----- include/video_console.h | 11 ++++------- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index ac7053d60a8..5ef1cb1c68f 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -82,14 +82,13 @@ int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp) return console_fixed_putc_xy(dev, x_frac, y, cp, priv->fontdata); } -static __maybe_unused int console_get_cursor_info(struct udevice *dev, - bool visible, uint x, uint y, - uint index) +static __maybe_unused int console_get_cursor_info(struct udevice *dev) { struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct console_simple_priv *priv = dev_get_priv(dev); struct video_fontdata *fontdata = priv->fontdata; struct vidconsole_cursor *curs = &vc_priv->curs; + int x, y, index; /* for now, this is not used outside expo */ if (!IS_ENABLED(CONFIG_EXPO)) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index aabacd10afe..e215a3e0e54 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -1018,12 +1018,12 @@ static int truetype_entry_restore(struct udevice *dev, struct abuf *buf) return 0; } -static int truetype_get_cursor_info(struct udevice *dev, bool visible, - uint x, uint y, uint index) +static int truetype_get_cursor_info(struct udevice *dev) { struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); struct console_tt_priv *priv = dev_get_priv(dev); struct vidconsole_cursor *curs = &vc_priv->curs; + int x, y, index; uint height; if (xpl_phase() <= PHASE_SPL) @@ -1034,14 +1034,12 @@ static int truetype_get_cursor_info(struct udevice *dev, bool visible, * passed-in values, since an entry_restore() must have been done before * calling this function. */ - if (visible) { - index = priv->pos_ptr; - if (index < priv->pos_ptr) - x = VID_TO_PIXEL(priv->pos[index].xpos_frac); - else - x = VID_TO_PIXEL(vc_priv->xcur_frac); - y = vc_priv->ycur; - } + index = priv->pos_ptr; + if (index < priv->pos_ptr) + x = VID_TO_PIXEL(priv->pos[index].xpos_frac); + else + x = VID_TO_PIXEL(vc_priv->xcur_frac); + y = vc_priv->ycur; /* Get font height from current font type */ if (priv->cur_fontdata) @@ -1052,8 +1050,8 @@ static int truetype_get_cursor_info(struct udevice *dev, bool visible, /* Store line pointer and height in cursor struct */ curs->x = x; curs->y = y; - curs->index = index; curs->height = height; + curs->index = index; return 0; } diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 65c912a4f6f..f62e34673db 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -720,11 +720,12 @@ int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index) int ret; /* find out where the cursor should be drawn */ - if (ops->get_cursor_info) { - ret = ops->get_cursor_info(dev, true, x, y, index); - if (ret && ret != -ENOSYS) - return ret; - } + if (!ops->get_cursor_info) + return -ENOSYS; + + ret = ops->get_cursor_info(dev); + if (ret) + return ret; /* If the driver stored cursor line and height, use them for drawing */ if (curs->height) { diff --git a/include/video_console.h b/include/video_console.h index 0b8742c5ee9..669292c97d7 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -342,17 +342,14 @@ struct vidconsole_ops { /** * get_cursor_info() - Get cursor position info * - * Calculates and stores cursor position information + * Calculates and stores cursor position information. This must fill in + * @x, @y, @height and @index using struct vidconsole_priv fields + * @xmark_frac, @ymark and @index * * @dev: Console device to use - * @visible: true to show the cursor, false to hide it - * @x: X position in pixels - * @y: Y position in pixels - * @index: Character position (0 = at start) * Return: 0 if OK, -ve on error */ - int (*get_cursor_info)(struct udevice *dev, bool visible, - uint x, uint y, uint index); + int (*get_cursor_info)(struct udevice *dev); /** * mark_start() - Mark the current position as the state of CLI entry -- 2.43.0

From: Simon Glass <sjg@chromium.org> For expo, lineedit only supports a single line. For the CLI, the text can extend across multiple lines. Add support for this in the normal console, calculating the x and y offset of the cursor position based on the display width and font size. The truetype console already works, since it has had this tracking for a while. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_normal.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 5ef1cb1c68f..8f936191dd8 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -88,7 +88,7 @@ static __maybe_unused int console_get_cursor_info(struct udevice *dev) struct console_simple_priv *priv = dev_get_priv(dev); struct video_fontdata *fontdata = priv->fontdata; struct vidconsole_cursor *curs = &vc_priv->curs; - int x, y, index; + int x, y, index, xspace, xpos; /* for now, this is not used outside expo */ if (!IS_ENABLED(CONFIG_EXPO)) @@ -97,7 +97,30 @@ static __maybe_unused int console_get_cursor_info(struct udevice *dev) x = VID_TO_PIXEL(vc_priv->xmark_frac); y = vc_priv->ymark; index = vc_priv->cli_index; - x += index * fontdata->width; + + /* rounded up character position in this line */ + xpos = (x + vc_priv->x_charsize - 1) / vc_priv->x_charsize; + + /* number of characters which can fit on this (first) line */ + xspace = vc_priv->cols - xpos; + + if (!curs->indent && index > xspace) { + /* move to the next line */ + y += vc_priv->y_charsize; + index -= xspace; + + /* figure out the available space in subsequent lines */ + if (!curs->indent) { + xspace = vc_priv->cols; + x = 0; + } + + /* calculate the line based on that */ + y += index / xspace; + x += (index % xspace) * fontdata->width; + } else { + x += index * fontdata->width; + } /* place the cursor 1 pixel before the start of the next char */ if (x > 0) @@ -107,7 +130,7 @@ static __maybe_unused int console_get_cursor_info(struct udevice *dev) curs->x = x; curs->y = y; curs->height = vc_priv->y_charsize; - curs->index = index; + curs->index = vc_priv->cli_index; return 0; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> Now that both console drivers use the CLI index, we don't need the extra parameters for this. Drop them. Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/scene_textline.c | 3 +-- drivers/video/vidconsole-uclass.c | 4 ++-- include/video_console.h | 12 +++--------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/boot/scene_textline.c b/boot/scene_textline.c index 3d4269a8e05..7e01959c40d 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -214,8 +214,7 @@ int scene_textline_render_deps(struct scene *scn, if (ret) return log_msg_ret("sav", ret); - vidconsole_show_cursor(cons, txt->obj.bbox.x0, - txt->obj.bbox.y0, scn->cls.num); + vidconsole_show_cursor(cons); } return 0; diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index f62e34673db..15b62d160cd 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -712,7 +712,7 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf) } #ifdef CONFIG_CURSOR -int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index) +int vidconsole_show_cursor(struct udevice *dev) { struct vidconsole_priv *priv = dev_get_uclass_priv(dev); struct vidconsole_ops *ops = vidconsole_get_ops(dev); @@ -747,7 +747,7 @@ int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index) curs->height); } - priv->curs.visible = true; + curs->visible = true; return 0; } diff --git a/include/video_console.h b/include/video_console.h index 669292c97d7..b40253b218d 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -451,17 +451,12 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf); /** * vidconsole_show_cursor() - Show the cursor * - * Shows a cursor at the specified position. The position is passed in, but for - * the truetype console it is not actually used, since it tracks where the - * cursor must go. + * Shows a cursor at the current position. * * @dev: Console device to use - * @x: X position in pixels - * @y: Y position in pixels - * @index: Character position (0 = at start) * Return: 0 if OK, -ve on error */ -int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, uint index); +int vidconsole_show_cursor(struct udevice *dev); /** * vidconsole_readline_start() - Enable cursor for all video consoles @@ -481,8 +476,7 @@ void vidconsole_readline_start(bool indent); */ void vidconsole_readline_end(void); #else -static inline int vidconsole_show_cursor(struct udevice *dev, uint x, uint y, - uint index) +static inline int vidconsole_show_cursor(struct udevice *dev) { return 0; } -- 2.43.0

From: Simon Glass <sjg@chromium.org> Drawing the cursor is a destructive operation, so we must save the previous contents of the affected part of the framebuffer, so it can be restored afterwards. Add this to the cursor info and set it up when probing the console device. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_core.c | 41 ++++++++++++++++++++++++++++- drivers/video/console_truetype.c | 4 +++ drivers/video/vidconsole_internal.h | 10 +++++++ include/video_console.h | 4 +++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index 6db42e63ea9..b1688e717c9 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -9,6 +9,8 @@ #include <video.h> #include <video_console.h> #include <dm.h> +#include <malloc.h> +#include <spl.h> #include <video_font.h> #include "vidconsole_internal.h" @@ -198,9 +200,46 @@ int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, return 0; } +int console_alloc_cursor(struct udevice *dev) +{ + struct vidconsole_priv *vc_priv; + struct vidconsole_cursor *curs; + struct video_priv *vid_priv; + struct udevice *vid; + int save_count; + + if (!CONFIG_IS_ENABLED(CURSOR) || xpl_phase() < PHASE_BOARD_R) + return 0; + + vc_priv = dev_get_uclass_priv(dev); + vid = dev_get_parent(dev); + vid_priv = dev_get_uclass_priv(vid); + curs = &vc_priv->curs; + + /* Allocate cursor save buffer for maximum possible cursor height */ + save_count = vid_priv->ysize * VIDCONSOLE_CURSOR_WIDTH; + curs->save_data = malloc(save_count * sizeof(u32)); + if (!curs->save_data) + return -ENOMEM; + + return 0; +} + int console_probe(struct udevice *dev) { - return console_set_font(dev, fonts); + int ret; + + ret = console_set_font(dev, fonts); + if (ret) + return ret; + + if (CONFIG_IS_ENABLED(CURSOR) && xpl_phase() == PHASE_BOARD_R) { + ret = console_alloc_cursor(dev); + if (ret) + return ret; + } + + return 0; } const char *console_simple_get_font_size(struct udevice *dev, uint *sizep) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index e215a3e0e54..fc2985ed92f 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -1111,6 +1111,10 @@ static int console_truetype_probe(struct udevice *dev) debug("%s: ready\n", __func__); + ret = console_alloc_cursor(dev); + if (ret) + return ret; + return 0; } diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index c008b9cf7d3..4cb6ba4e15f 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -123,6 +123,16 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, bool direction); +/** + * console_alloc_cursor() - Allocate cursor save buffer + * + * Allocates memory for saving pixels under the cursor + * + * @dev: vidconsole device + * Return: 0 if success, -ENOMEM if allocation fails + */ +int console_alloc_cursor(struct udevice *dev); + /** * console probe function. * diff --git a/include/video_console.h b/include/video_console.h index b40253b218d..ffe331c5803 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -32,6 +32,8 @@ enum { * @enabled: cursor is active (e.g. during readline) * @visible: cursor is currently visible * @indent: indent subsequent lines to the same position as the first line + * @saved: true if save_data contains valid data + * @save_data: saved pixels under cursor * @x: cursor left X position in pixels * @y: cursor top Y position in pixels * @height: height of cursor in pixels @@ -41,6 +43,8 @@ struct vidconsole_cursor { bool enabled; bool visible; bool indent; + bool saved; + u32 *save_data; /* filled in by get_cursor_info(): */ uint x; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Create a variant of fill_pixel_and_goto_next() function which returns the old pixel value. This will make it easy to save the framebuffer pixels as they are overwritten by drawing the cursor. Leave the current function alone, since it increases code size about 16 bytes and may slow down blitting. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_core.c | 25 +++++++++++++++++++++++++ drivers/video/vidconsole_internal.h | 12 ++++++++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index b1688e717c9..4fab5a2605e 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -61,6 +61,31 @@ inline void fill_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int ste *dstp = dst_byte + step; } +inline u32 swap_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int step) +{ + u8 *dst_byte = *dstp; + u32 old_value = 0; + + if (pbytes == 4) { + u32 *dst = *dstp; + old_value = *dst; + *dst = value; + } + if (pbytes == 2) { + u16 *dst = *dstp; + old_value = *dst; + *dst = value; + } + if (pbytes == 1) { + u8 *dst = *dstp; + old_value = *dst; + *dst = value; + } + *dstp = dst_byte + step; + + return old_value; +} + int fill_char_vertically(uchar *pfont, void **line, struct video_priv *vid_priv, struct video_fontdata *fontdata, bool direction) { diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index 4cb6ba4e15f..93f9c7b4e56 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -45,6 +45,18 @@ int check_bpix_support(int bpix); */ void fill_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int step); +/** + * swap_pixel_and_goto_next() - Swap 1 pixel in framebuffer, and go to next one + * + * @param dstp a pointer to pointer to framebuffer. + * @param value value to write to framebuffer. + * @param pbytes framebuffer bytes per pixel. + * @param step framebuffer pointer increment. Usually is equal to pbytes, + * and may be negative to control filling direction. + * Return: old value of the pixel + */ +u32 swap_pixel_and_goto_next(void **dstp, u32 value, int pbytes, int step); + /** * Fills 1 character in framebuffer vertically. Vertically means we're filling char font data rows * across the lines. -- 2.43.0

From: Simon Glass <sjg@chromium.org> Save the pixels overwritten by the cursor into the save area. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_core.c | 63 ++++++++++++++++++++++++++--- drivers/video/vidconsole-uclass.c | 36 +++++++++++++++++ drivers/video/vidconsole_internal.h | 15 ++++++- include/video_console.h | 16 +++++++- 4 files changed, 122 insertions(+), 8 deletions(-) diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index 4fab5a2605e..3f3efb94ab1 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -190,8 +190,9 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, bool direction) { - int step, line_step, pbytes, ret; + int step, line_step, pbytes, ret, row; void *line, *dst; + u32 *save_ptr; uint value; ret = check_bpix_support(vid_priv->bpix); @@ -207,20 +208,72 @@ int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, line_step = vid_priv->line_length; } + /* we should not already have saved data */ + if (curs->saved) { + debug("Trying to show cursor but data is already saved\n"); + return -EINVAL; + } + /* Figure out where to write the cursor in the frame buffer */ line = vid_priv->fb + curs->y * vid_priv->line_length + curs->x * VNBYTES(vid_priv->bpix); + /* save pixels under cursor and draw new cursor in one pass */ value = vid_priv->colour_fg; - - for (int row = 0; row < curs->height; row++) { + save_ptr = curs->save_data; + for (row = 0; row < curs->height; row++) { dst = line; for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++) - fill_pixel_and_goto_next(&dst, value, pbytes, step); - + *save_ptr++ = swap_pixel_and_goto_next(&dst, value, + pbytes, step); line += line_step; } + curs->saved = true; + + return 0; +} + +int cursor_hide(struct vidconsole_cursor *curs, struct video_priv *vid_priv, + bool direction) +{ + int step, line_step, pbytes, ret; + void *line, *dst; + + ret = check_bpix_support(vid_priv->bpix); + if (ret) + return ret; + + pbytes = VNBYTES(vid_priv->bpix); + if (direction) { + step = -pbytes; + line_step = -vid_priv->line_length; + } else { + step = pbytes; + line_step = vid_priv->line_length; + } + + /* Trying to hide cursor - we should have saved data */ + if (!curs->saved) { + debug("Trying to hide cursor but no data was saved\n"); + return -EINVAL; + } + + /* Figure out where to write the cursor in the frame buffer */ + line = vid_priv->fb + curs->y * vid_priv->line_length + + curs->x * VNBYTES(vid_priv->bpix); + + /* Restore saved pixels */ + u32 *save_ptr = curs->save_data; + dst = line; + for (int row = 0; row < curs->height; row++) { + void *row_dst = dst; + for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++) + fill_pixel_and_goto_next(&row_dst, *save_ptr++, pbytes, + step); + dst += line_step; + } + curs->saved = false; return 0; } diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 15b62d160cd..3621714c742 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -71,6 +71,9 @@ static int vidconsole_back(struct udevice *dev) return ret; } + /* Hide cursor at old position if it's visible */ + vidconsole_hide_cursor(dev); + priv->xcur_frac -= VID_TO_POS(priv->x_charsize); if (priv->xcur_frac < priv->xstart_frac) { priv->xcur_frac = (priv->cols - 1) * @@ -128,6 +131,9 @@ void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y) { struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + /* Hide cursor at old position if it's visible */ + vidconsole_hide_cursor(dev); + priv->xcur_frac = VID_TO_POS(x); priv->xstart_frac = priv->xcur_frac; priv->ycur = y; @@ -473,6 +479,9 @@ int vidconsole_put_char(struct udevice *dev, char ch) struct vidconsole_priv *priv = dev_get_uclass_priv(dev); int cp, ret; + /* Hide cursor to avoid artifacts */ + vidconsole_hide_cursor(dev); + if (priv->escape) { vidconsole_escape_char(dev, ch); return 0; @@ -752,6 +761,33 @@ int vidconsole_show_cursor(struct udevice *dev) return 0; } +int vidconsole_hide_cursor(struct udevice *dev) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct vidconsole_cursor *curs = &priv->curs; + int ret; + + if (!curs->visible) + return 0; + + /* If the driver stored cursor line and height, use them for drawing */ + if (curs->height) { + struct udevice *vid = dev_get_parent(dev); + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + + ret = cursor_hide(curs, vid_priv, NORMAL_DIRECTION); + if (ret) + return ret; + + /* Update display damage for cursor area */ + video_damage(vid, curs->x, curs->y, VIDCONSOLE_CURSOR_WIDTH, + curs->height); + } + + curs->visible = false; + + return 0; +} #endif /* CONFIG_CURSOR */ int vidconsole_mark_start(struct udevice *dev) diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index 93f9c7b4e56..241be149ac9 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -112,7 +112,7 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri struct video_fontdata *fontdata, bool direction); /** - * cursor_show() - Draw a simple vertical cursor + * cursor_show() - Show cursor by saving and drawing pixels * * @curs: cursor information * @vid_priv: video-device info @@ -130,11 +130,22 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri *|---!!we're starting from upper left char corner| *|-----------------------------------------------| * - * Return: 0, if success, or else error code. + * Return: 0 on success, -EINVAL if cursor data already saved */ int cursor_show(struct vidconsole_cursor *curs, struct video_priv *vid_priv, bool direction); +/** + * cursor_hide() - Hide cursor by restoring saved pixels + * + * @curs: cursor information + * @vid_priv: video-device info + * @direction: controls cursor orientation (normal or flipped) + * Return: 0 if success, -EINVAL if no cursor data was saved + */ +int cursor_hide(struct vidconsole_cursor *curs, struct video_priv *vid_priv, + bool direction); + /** * console_alloc_cursor() - Allocate cursor save buffer * diff --git a/include/video_console.h b/include/video_console.h index ffe331c5803..9005e9f4442 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -462,6 +462,16 @@ int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf); */ int vidconsole_show_cursor(struct udevice *dev); +/** + * vidconsole_hide_cursor() - Hide the cursor + * + * Hides the cursor if it's currently visible + * + * @dev: Console device to use + * Return: 0 if OK, -ve on error + */ +int vidconsole_hide_cursor(struct udevice *dev); + /** * vidconsole_readline_start() - Enable cursor for all video consoles * @@ -485,6 +495,11 @@ static inline int vidconsole_show_cursor(struct udevice *dev) return 0; } +static inline int vidconsole_hide_cursor(struct udevice *dev) +{ + return 0; +} + static inline void vidconsole_readline_start(bool indent) { } @@ -501,7 +516,6 @@ static inline void cli_index_adjust(struct vidconsole_priv *priv, int by) } /** - * vidconsole_push_colour() - Temporarily change the font colour * * @dev: Device to adjust -- 2.43.0

From: Simon Glass <sjg@chromium.org> When the console is idle and at the CLI, ensure the cursor is visible. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/vidconsole-uclass.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 3621714c742..52a51b5e1c1 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -931,6 +931,18 @@ void vidconsole_set_bitmap_font(struct udevice *dev, void vidconsole_idle(struct udevice *dev) { + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct vidconsole_cursor *curs = &priv->curs; + + /* Only handle cursor if it's enabled */ + if (curs->enabled && !curs->visible) { + /* + * TODO(sjg@chromium.org): We are using a saved position here, + * but vidconsole_show_cursor() calls get_cursor_info() to + * recalc the position anyway. + */ + vidconsole_show_cursor(dev); + } } #ifdef CONFIG_CURSOR -- 2.43.0

From: Simon Glass <sjg@chromium.org> Within the CLI, inserting a character works by writing out the new char and then all the ones after it. With the truetype console this results in gibberish since the new chars are written on top of the old. To resolve this, clear the rest of the input when a character is inserted. Consider that the end of the input, at least until furture characters are written. As an optimisation, don't clear if the new character is the same as the old. This cleans up a dot above the 'g' of greatness which should not be there, so update the dm_test_video_truetype() test. It also clean up the part of the 't' of 'not be' which should not be there, so update dm_test_video_truetype_bs() too. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 76 ++++++++++++++++++++++++++++++-- test/dm/video.c | 4 +- 2 files changed, 74 insertions(+), 6 deletions(-) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index fc2985ed92f..a42ae318fc8 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -295,6 +295,58 @@ static int console_truetype_move_rows(struct udevice *dev, uint rowdst, return 0; } +/** + * clear_from() - Clear characters on the display from given index onwards + * + * Erases all characters from the specified position index in the position + * history to the end of the position array (pos_count). This handles line + * wrapping by clearing to the end of lines and continuing on subsequent lines. + * + * @dev: Device to update + * @index: Starting index in priv->pos array to erase from + */ +static void clear_from(struct udevice *dev, int index) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct console_tt_priv *priv = dev_get_priv(dev); + struct udevice *vid_dev = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid_dev); + struct pos_info *start_pos, *end_pos; + int xstart, xend; + int ystart, yend; + + assert(priv->pos_count && index && index < priv->pos_count); + + start_pos = &priv->pos[index]; + xstart = VID_TO_PIXEL(start_pos->xpos_frac); + ystart = start_pos->ypos; + + /* End position is the last character in the position array */ + end_pos = &priv->pos[priv->pos_count - 1]; + xend = VID_TO_PIXEL(end_pos->xpos_frac) + end_pos->width; + yend = end_pos->ypos; + + /* If on the same line, just erase from start to end position */ + if (ystart == yend) { + video_fill_part(vid_dev, xstart, ystart, xend, ystart + vc_priv->y_charsize, + vid_priv->colour_bg); + } else { + /* Different lines - erase to end of first line */ + video_fill_part(vid_dev, xstart, ystart, vid_priv->xsize, + ystart + vc_priv->y_charsize, vid_priv->colour_bg); + + /* Erase any complete lines in between */ + if (yend > ystart + vc_priv->y_charsize) { + video_fill_part(vid_dev, 0, ystart + vc_priv->y_charsize, + vid_priv->xsize, yend, vid_priv->colour_bg); + } + + /* Erase from start of final line to end of last character */ + video_fill_part(vid_dev, 0, yend, xend, yend + vc_priv->y_charsize, + vid_priv->colour_bg); + } +} + static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, int cp) { @@ -326,15 +378,19 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, * First out our current X position in fractional pixels. If we wrote * a character previously, use kerning to fine-tune the position of * this character */ + pos = priv->pos_ptr < priv->pos_count ? &priv->pos[priv->pos_ptr] : + NULL; xpos = frac(VID_TO_PIXEL((double)x)); kern = 0; if (vc_priv->last_ch) { - kern = stbtt_GetCodepointKernAdvance(font, vc_priv->last_ch, - cp); + int last_cp = vc_priv->last_ch; + + if (pos) + last_cp = pos->cp; + kern = stbtt_GetCodepointKernAdvance(font, last_cp, cp); if (_DEBUG) { console_printf_select_stderr(true, "kern %c (%02x)", - vc_priv->last_ch, - vc_priv->last_ch); + last_cp, last_cp); } xpos += met->scale * kern; } @@ -357,6 +413,18 @@ static int console_truetype_putc_xy(struct udevice *dev, uint x, uint y, /* Write the current cursor position into history */ if (priv->pos_ptr < POS_HISTORY_SIZE) { + bool erase = false; + + /* Check if we're overwriting a different character */ + if (pos && pos->cp != cp) { + erase = true; + /* Erase using the old character's position before updating */ + clear_from(dev, priv->pos_ptr); + + /* After erasing, we don't care about erased characters */ + priv->pos_count = priv->pos_ptr; + } + pos = &priv->pos[priv->pos_ptr]; pos->xpos_frac = vc_priv->xcur_frac; pos->ypos = vc_priv->ycur; diff --git a/test/dm/video.c b/test/dm/video.c index 3ec12956909..3395fd9f1b3 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -594,7 +594,7 @@ static int dm_test_video_truetype(struct unit_test_state *uts) ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); vidconsole_put_string(con, test_string); vidconsole_put_stringn(con, test_string, 30); - ut_asserteq(13055, video_compress_fb(uts, dev, false)); + ut_asserteq(13073, video_compress_fb(uts, dev, false)); ut_assertok(video_check_copy_fb(uts, dev)); return 0; @@ -648,7 +648,7 @@ static int dm_test_video_truetype_bs(struct unit_test_state *uts) ut_assertok(video_get_nologo(uts, &dev)); ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); vidconsole_put_string(con, test_string); - ut_asserteq(29223, video_compress_fb(uts, dev, false)); + ut_asserteq(29310, video_compress_fb(uts, dev, false)); ut_assertok(video_check_copy_fb(uts, dev)); return 0; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Now that the truetype console properly handles clearing text from the display during editing, we don't need to clear the character when processing a backspace. This allows arrow keys to work as expected on the truetype console. Signed-off-by: Simon Glass <sjg@chromium.org> --- drivers/video/console_truetype.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index a42ae318fc8..4ddf133f2e0 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -590,10 +590,6 @@ static int console_truetype_backspace(struct udevice *dev) else xend = vid_priv->xsize; - video_fill_part(vid_dev, VID_TO_PIXEL(pos->xpos_frac), pos->ypos, - xend, pos->ypos + vc_priv->y_charsize, - vid_priv->colour_bg); - /* Move the cursor back to where it was when we pushed this record */ vc_priv->xcur_frac = pos->xpos_frac; vc_priv->ycur = pos->ypos; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Provide a few notes about how the cursor works in the video console. Signed-off-by: Simon Glass <sjg@chromium.org> --- include/video_console.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/video_console.h b/include/video_console.h index 9005e9f4442..ac04aeb3aef 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -29,6 +29,26 @@ enum { * The cursor is set up and maintained by the vidconsole. It is a simple * vertical bar of width VIDCONSOLE_CURSOR_WIDTH shown in the foreground colour. * + * No cursor processing is done unless @enabled is true. + * + * To figure out where to draw the cursor, the vidconsole's get_cursor_info() is + * called. It fills in the @x, @y, @height and @index information below. That + * information remains valid while the cursor is shown, so it can be used to + * hide the cursor. + * + * The cursor is drawn only when idle (by vidconsole_show_cursor() called from + * vidconsole_idle()). It is erased as soon as any output needs to be written to + * the display - vidconsole_hide_cursor() is called from a few places in the + * vidconsole uclass. + * + * Under the hood, vidconsole_show_cursor() calls cursor_show() which saves the + * pixels under the cursor as it draws it. Once finished it sets @visible to + * true, so that we know we must erase the cursor before drawing anything else. + * + * The old pixels end up in @save_data and are used by cursor_hide() (called + * from vidconsole_hide_cursor()) to restore the display contents to what they + * were. Once that is done, @visible is set back to false. + * * @enabled: cursor is active (e.g. during readline) * @visible: cursor is currently visible * @indent: indent subsequent lines to the same position as the first line -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a few tests of cursor operation. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <sjg@chromium.org> --- test/dm/video.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/test/dm/video.c b/test/dm/video.c index 3395fd9f1b3..bb88c17e272 100644 --- a/test/dm/video.c +++ b/test/dm/video.c @@ -997,3 +997,87 @@ static int dm_test_video_font_switch(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_video_font_switch, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +/* cursor backspace without artifacts */ +static int check_cursor_backspace(struct unit_test_state *uts, + struct udevice *dev, struct udevice *con, + int exp_height) +{ + int with_a, with_cursor, after_backspace, after_idle, after_hide; + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(con); + struct vidconsole_cursor *curs = &vc_priv->curs; + + /* Output chars without cursor */ + ut_assert(!curs->visible); + ut_assert(!curs->enabled); + ut_assert(!curs->saved); + ut_assert(!curs->height); + ut_assertok(vidconsole_put_char(con, ' ')); + ut_assertok(vidconsole_put_char(con, 'a')); + with_a = video_compress_fb(uts, dev, false); + + /* Show cursor at current position (after 'a') */ + ut_assertok(vidconsole_show_cursor(con)); + ut_assert(curs->visible); + ut_assert(curs->saved); + ut_asserteq(exp_height, curs->height); + with_cursor = video_compress_fb(uts, dev, false); + + /* Enable the cursor so that backspace will move it */ + curs->enabled = true; + + /* Do backspace - the cursor will be hidden */ + ut_assertok(vidconsole_put_char(con, '\b')); + ut_assert(!curs->visible); + ut_assert(!curs->saved); + after_backspace = video_compress_fb(uts, dev, false); + ut_asserteq(with_a, after_backspace); + ut_assert(curs->enabled); + + /* Run idle function - this should show the cursor */ + vidconsole_idle(con); + ut_assert(curs->visible); + ut_assert(curs->saved); + after_idle = video_compress_fb(uts, dev, false); + ut_assert(after_idle != with_a); + + /* Hide the cursor */ + ut_assertok(vidconsole_hide_cursor(con)); + ut_assert(curs->enabled); + ut_assert(!curs->visible); + ut_assert(!curs->saved); + after_hide = video_compress_fb(uts, dev, false); + + ut_asserteq(with_a, after_hide); + + return 0; +} + +/* cursor backspace without artifacts */ +static int dm_test_video_backspace_normal(struct unit_test_state *uts) +{ + struct udevice *dev, *con; + + ut_assertok(select_vidconsole(uts, "vidconsole0")); + ut_assertok(video_get_nologo(uts, &dev)); + ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); + ut_assertok(vidconsole_select_font(con, "8x16", 0)); + ut_assertok(check_cursor_backspace(uts, dev, con, 16)); + + return 0; +} +DM_TEST(dm_test_video_backspace_normal, UTF_SCAN_PDATA | UTF_SCAN_FDT); + +/* cursor backspace without artifacts on truetype */ +static int dm_test_video_backspace_truetype(struct unit_test_state *uts) +{ + struct udevice *dev, *con; + + ut_assertok(video_get_nologo(uts, &dev)); + ut_assertok(uclass_get_device(UCLASS_VIDEO_CONSOLE, 0, &con)); + ut_assertok(vidconsole_select_font(con, NULL, 30)); + ut_assertok(check_cursor_backspace(uts, dev, con, 30)); + + return 0; +} +DM_TEST(dm_test_video_backspace_truetype, UTF_SCAN_PDATA | UTF_SCAN_FDT); -- 2.43.0
participants (1)
-
Simon Glass