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(-)
@@ -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"
@@ -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;
@@ -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
*