[Concept,02/13] serial: Support length-based serial output
Commit Message
From: Simon Glass <simon.glass@canonical.com>
Add serial_putsn() to output a string with a specified length through
the serial port. The serial uclass already supports length-based writes
via __serial_puts(), so this just provides a public wrapper function.
Add a test to check it.
Co-developed-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---
drivers/serial/serial-uclass.c | 34 ++++++++++++++++++++++++++++++++++
include/serial.h | 12 ++++++++++++
test/dm/serial.c | 20 ++++++++++++++++++++
3 files changed, 66 insertions(+)
@@ -309,6 +309,34 @@ static void _serial_puts(struct udevice *dev, const char *str)
} while (*str);
}
+static void _serial_putsn(struct udevice *dev, const char *str, size_t len)
+{
+ struct dm_serial_ops *ops = serial_get_ops(dev);
+
+ if (!CONFIG_IS_ENABLED(SERIAL_PUTS) || !ops->puts) {
+ while (len--)
+ _serial_putc(dev, *str++);
+ return;
+ }
+
+ while (len) {
+ const char *newline = memchr(str, '\n', len);
+ size_t seg_len = newline ? newline - str : len;
+
+ if (__serial_puts(dev, str, seg_len))
+ return;
+
+ if (newline && __serial_puts(dev, "\r\n", 2))
+ return;
+
+ if (IS_ENABLED(CONFIG_CONSOLE_FLUSH_ON_NEWLINE) && newline)
+ _serial_flush(dev);
+
+ str += seg_len + !!newline;
+ len -= seg_len + !!newline;
+ }
+}
+
static int __serial_getc(struct udevice *dev)
{
struct dm_serial_ops *ops = serial_get_ops(dev);
@@ -391,6 +419,12 @@ void serial_puts(const char *str)
_serial_puts(gd->cur_serial_dev, str);
}
+void serial_putsn(const char *str, int len)
+{
+ if (gd->cur_serial_dev)
+ _serial_putsn(gd->cur_serial_dev, str, len);
+}
+
#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
void serial_flush(void)
{
@@ -392,6 +392,18 @@ void serial_setbrg(void);
void serial_putc(const char ch);
void serial_putc_raw(const char ch);
void serial_puts(const char *str);
+
+/**
+ * serial_putsn() - Write a string with specified length to the serial console
+ *
+ * This outputs exactly @len characters from @str, regardless of any nul
+ * characters that may be present. This is useful for printing substrings or
+ * binary data that may contain embedded nuls.
+ *
+ * @str: String to output (need not be nul-terminated)
+ * @len: Number of characters to output
+ */
+void serial_putsn(const char *str, int len);
#if defined(CONFIG_CONSOLE_FLUSH_SUPPORT) && CONFIG_IS_ENABLED(DM_SERIAL)
void serial_flush(void);
#else
@@ -88,3 +88,23 @@ static int dm_test_serial(struct unit_test_state *uts)
return 0;
}
DM_TEST(dm_test_serial, UTF_SCAN_FDT);
+
+/* Test serial_putsn() function */
+static int dm_test_serial_putsn(struct unit_test_state *uts)
+{
+ const char *test_str = "testing string";
+ size_t test_len = 4;
+ size_t start, written;
+
+ /* Test that serial_putsn() writes the correct number of characters */
+ sandbox_serial_endisable(false);
+ start = sandbox_serial_written();
+ serial_putsn(test_str, test_len);
+ sandbox_serial_endisable(true);
+
+ written = sandbox_serial_written() - start;
+ ut_asserteq(test_len, written);
+
+ return 0;
+}
+DM_TEST(dm_test_serial_putsn, UTF_SCAN_FDT);