[Concept,05/16] console: Plumb in the pager

Message ID 20250822142153.3404275-6-sjg@u-boot.org
State New
Headers
Series Introduce a pager for the console |

Commit Message

Simon Glass Aug. 22, 2025, 2:21 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Send all console output via the pager. If it is disabled, it will do
nothing.

The pager is only supported if CONSOLE_MUX and SYS_CONSOLE_IS_IN_ENV are
enabled. This is the common case for more richly featured boards, i.e.
those that can cope with the extra code size of this feature.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 common/Kconfig                    |  9 ++++++
 common/console.c                  | 52 +++++++++++++++++++++++++------
 include/asm-generic/global_data.h | 11 +++++++
 3 files changed, 63 insertions(+), 9 deletions(-)
  

Patch

diff --git a/common/Kconfig b/common/Kconfig
index 048530adff3..6c54f90109c 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -343,6 +343,15 @@  config CONSOLE_PAGER
 	  controlled by the 'pager' environment variable. If the variable is
 	  not set or is empty, paging is disabled.
 
+config CONSOLE_PAGER_LINES
+	int "Number of lines per page"
+	depends on CONSOLE_PAGER
+	default 25
+	help
+	  Sets the default number of lines that the pager assumes is visible on
+	  the display. This is used as a default if the "pager" environment
+	  variable is unset.
+
 endmenu
 
 menu "Logging"
diff --git a/common/console.c b/common/console.c
index fdccf156b5a..9bc506f0464 100644
--- a/common/console.c
+++ b/common/console.c
@@ -16,6 +16,7 @@ 
 #include <malloc.h>
 #include <mapmem.h>
 #include <os.h>
+#include <pager.h>
 #include <serial.h>
 #include <stdio_dev.h>
 #include <exports.h>
@@ -377,17 +378,32 @@  int console_printf_select_stderr(bool serial_only, const char *fmt, ...)
 	return ret;
 }
 
-static void console_puts_pager(int file, const char *s)
+static void console_puts(int file, bool use_pager, const char *s)
 {
-	int i;
-	struct stdio_dev *dev;
+	int key = 0;
 
-	for_each_console_dev(i, file, dev) {
-		if (dev->puts != NULL)
-			dev->puts(dev, s);
+	for (s = pager_post(gd_pager(), use_pager, s); s;
+	     s = pager_next(gd_pager(), use_pager, key)) {
+		struct stdio_dev *dev;
+		int i;
+
+		key = 0;
+		if (s == PAGER_WAITING) {
+			key = getchar();
+		} else if (*s) {
+			for_each_console_dev(i, file, dev) {
+				if (dev->puts != NULL)
+					dev->puts(dev, s);
+			}
+		}
 	}
 }
 
+static void console_puts_pager(int file, const char *s)
+{
+	console_puts(file, true, s);
+}
+
 #ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
 static void console_flush(int file)
 {
@@ -407,7 +423,8 @@  static inline void console_doenv(int file, struct stdio_dev *dev)
 	iomux_doenv(file, dev->name);
 }
 #endif
-#else
+
+#else /* !CONSOLE_MUX */
 
 static void console_devices_set(int file, struct stdio_dev *dev)
 {
@@ -780,8 +797,8 @@  void puts(const char *s)
 		return pre_console_puts(s);
 
 	if (gd->flags & GD_FLG_DEVINIT) {
-		/* Send to the standard output */
-		fputs(stdout, s);
+		/* Send to the standard output through pager system */
+		console_puts_pager(stdout, s);
 	} else {
 		/* Send directly to the handler */
 		pre_console_puts(s);
@@ -1101,6 +1118,21 @@  static void stdio_print_current_devices(void)
 	printf("%s\n", stderrname);
 }
 
+static void setup_pager(void)
+{
+	/* Init pager now that console is ready */
+	if (IS_ENABLED(CONFIG_CONSOLE_PAGER)) {
+		int lines = IF_ENABLED_INT(CONFIG_CONSOLE_PAGER,
+					   CONFIG_CONSOLE_PAGER_LINES);
+		int ret;
+
+		ret = pager_init(gd_pagerp(), env_get_hex("pager", lines),
+				 PAGER_BUF_SIZE);
+		if (ret)
+			printf("Failed to init pager\n");
+	}
+}
+
 #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
 /* Called after the relocation - use desired console functions */
 int console_init_r(void)
@@ -1185,6 +1217,7 @@  done:
 	}
 
 	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+	setup_pager();
 
 	print_pre_console_buffer(flushpoint);
 	return 0;
@@ -1252,6 +1285,7 @@  int console_init_r(void)
 	}
 
 	gd->flags |= GD_FLG_DEVINIT;	/* device initialization completed */
+	setup_pager();
 
 	print_pre_console_buffer(flushpoint);
 	return 0;
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 464b9c3eee1..0157fead337 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -477,6 +477,9 @@  struct global_data {
 	 */
 	struct upl *upl;
 #endif
+#if CONFIG_IS_ENABLED(CONSOLE_PAGER)
+	struct pager *pager;
+#endif
 };
 #ifndef DO_DEPS_ONLY
 static_assert(sizeof(struct global_data) == GD_SIZE);
@@ -618,6 +621,14 @@  static_assert(sizeof(struct global_data) == GD_SIZE);
 #define gd_passage_dtb()	0
 #endif
 
+#if CONFIG_IS_ENABLED(CONSOLE_PAGER)
+#define gd_pager()		gd->pager
+#define gd_pagerp()		&gd->pager
+#else
+#define gd_pager()		NULL
+#define gd_pagerp()		NULL
+#endif
+
 /**
  * enum gd_flags - global data flags
  *