[Concept,07/13] console: Add putsn() support to struct stdio_dev

Message ID 20260204001002.2638622-8-sjg@u-boot.org
State New
Headers
Series Add putsn() for length-based console output |

Commit Message

Simon Glass Feb. 4, 2026, 12:09 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add an optional putsn() method to struct stdio_dev to allow devices to
provide optimised length-based output. The field is added
unconditionally but only used when CONFIG_CONSOLE_PUTSN is enabled.

Add console_putsn_pager() and fputsn() to route length-based output
through console devices. If a device provides a putsn method, it is
used; otherwise, the output falls back to calling putc in a loop.

Co-developed-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 common/console.c    | 31 ++++++++++++++++++++++++-------
 include/stdio_dev.h | 12 ++++++++++++
 2 files changed, 36 insertions(+), 7 deletions(-)
  

Patch

diff --git a/common/console.c b/common/console.c
index c058d3d30a2..67d87c6edfa 100644
--- a/common/console.c
+++ b/common/console.c
@@ -271,6 +271,7 @@  static int console_tstc(int file)
 }
 
 static void console_puts_pager(int file, const char *s);
+static void console_putsn_pager(int file, const char *s, int len);
 
 static void console_putc_pager(int file, const char c)
 {
@@ -355,18 +356,28 @@  static void console_puts(int file, bool use_pager, const char *s)
 	}
 }
 
+static void console_putsn_pager(int file, const char *s, int len)
+{
+	struct stdio_dev *dev;
+	int i;
+
+	for_each_console_dev(i, file, dev) {
+		if (dev->putsn)
+			dev->putsn(dev, s, len);
+		else if (dev->puts)
+			dev->puts(dev, s);
+		else
+			while (len--)
+				dev->putc(dev, *s++);
+	}
+}
+
 static void console_puts_pager(int file, const char *s)
 {
 	if (IS_ENABLED(CONFIG_CONSOLE_PAGER) && gd_pager()) {
 		console_puts(file, true, s);
 	} else {
-		struct stdio_dev *dev;
-		int i;
-
-		for_each_console_dev(i, file, dev) {
-			if (dev->puts != NULL)
-				dev->puts(dev, s);
-		}
+		console_putsn_pager(file, s, strlen(s));
 	}
 }
 
@@ -629,6 +640,12 @@  void fputs(int file, const char *s)
 		console_puts_pager(file, s);
 }
 
+void fputsn(int file, const char *s, int len)
+{
+	if ((unsigned int)file < MAX_FILES)
+		console_putsn_pager(file, s, len);
+}
+
 #ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
 void fflush(int file)
 {
diff --git a/include/stdio_dev.h b/include/stdio_dev.h
index 4e3c4708f80..2b2334c9918 100644
--- a/include/stdio_dev.h
+++ b/include/stdio_dev.h
@@ -38,6 +38,18 @@  struct stdio_dev {
 	void (*putc)(struct stdio_dev *dev, const char c);
 	/* To put a string (accelerator) */
 	void (*puts)(struct stdio_dev *dev, const char *s);
+	/**
+	 * putsn() - Output a string with specified length
+	 *
+	 * This outputs exactly @len characters from @s, regardless of any nul
+	 * characters that may be present. This is an optional accelerator - if
+	 * NULL, the console will fall back to calling putc() in a loop.
+	 *
+	 * @dev: Device to output to
+	 * @s: String to output (need not be nul-terminated)
+	 * @len: Number of characters to output
+	 */
+	void (*putsn)(struct stdio_dev *dev, const char *s, int len);
 #ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
 	/* To flush output queue */
 	void (*flush)(struct stdio_dev *dev);