[PATCH 4/7] console: make console_puts and friends accept a console_device

Ahmad Fatoum
2026-04-13T10:11:56Z

Ideally, stdout, stderr and stdin would be real consoles wit a custom
implementation that multiplexes onto all registered consoles that
are active for a given stream.

This will need some more carefulness though as not to increase size too
much for uninterested users.

We can already switch the API to a console_device-centric ones and reap
the benefits though by special casing the stdout/stderr/stdin types, so
do just that.

Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
---
common/console.c | 49 ++++++++++++++++++++++------------
common/console_common.c | 14 +++++-----
common/console_simple.c | 4 +--
efi/loader/protocols/console.c | 2 +-
include/console.h | 21 +++++++++++----
include/stdio.h | 4 +--
pbl/console.c | 12 ++++-----
7 files changed, 66 insertions(+), 40 deletions(-)

diff --git a/common/console.c b/common/console.c
index d7013e72e358..014ce2916835 100644
--- a/common/console.c
+++ b/common/console.c
@@ -116,7 +116,7 @@ int console_set_active(struct console_device *cdev, unsigned flag)
puts_ll("]\n");
barebox_banner();
while (kfifo_getc(console_output_fifo, &ch) == 0)
- console_putc(CONSOLE_STDOUT, ch);
+ console_putc(CONSOLE_DEV_STDOUT, ch);
} else if (IS_ENABLED(CONFIG_BANNER) && cdev->puts &&
flag_new == CONSOLE_STDIOE) {
cdev->puts(cdev, version_string, strlen(version_string));
@@ -571,10 +571,18 @@ int tstc(void)
}
EXPORT_SYMBOL(tstc);

-int console_putc(unsigned int ch, char c)
+int console_putc(struct console_device *con, char c)
{
int init = initialized;
bool crlf = c == '\n';
+ unsigned int ch;
+
+ ch = console_dev_is_std(con);
+ if (!ch) {
+ if (crlf)
+ con->putc(con, '\r');
+ con->putc(con, c);
+ }

switch (init) {
case CONSOLE_UNINITIALIZED:
@@ -589,11 +597,8 @@ int console_putc(unsigned int ch, char c)

case CONSOLE_INIT_FULL:
for_each_console(cdev) {
- if (cdev->f_active & ch) {
- if (crlf)
- cdev->putc(cdev, '\r');
- cdev->putc(cdev, c);
- }
+ if (cdev->f_active & ch)
+ console_putc(cdev, c);
}
return 1 + crlf;
default:
@@ -605,16 +610,20 @@ int console_putc(unsigned int ch, char c)
}
EXPORT_SYMBOL(console_putc);

-int console_puts(unsigned int ch, const char *str)
+int console_puts(struct console_device *con, const char *str)
{
const char *s = str;
+ unsigned int ch;
int n = 0;

+ ch = console_dev_is_std(con);
+ if (!ch)
+ return con->puts(con, str, strlen(str));
+
if (initialized == CONSOLE_INIT_FULL) {
for_each_console(cdev) {
- if (cdev->f_active & ch) {
- n = cdev->puts(cdev, str, strlen(str));
- }
+ if (cdev->f_active & ch)
+ n = console_puts(cdev, str);
}
return n;
}
@@ -627,8 +636,17 @@ int console_puts(unsigned int ch, const char *str)
}
EXPORT_SYMBOL(console_puts);

-void console_putbin(unsigned int ch, const u8 *str, size_t len)
+void console_putbin(struct console_device *con, const u8 *str, size_t len)
{
+ unsigned int ch;
+
+ ch = console_dev_is_std(con);
+ if (!ch) {
+ for (size_t i = 0; i < len; i++)
+ con->putc(con, str[i]);
+ return;
+ }
+
switch (initialized) {
case CONSOLE_UNINITIALIZED:
console_init_early();
@@ -640,11 +658,8 @@ void console_putbin(unsigned int ch, const u8 *str, size_t len)
return;
case CONSOLE_INIT_FULL:
for_each_console(cdev) {
- if (!(cdev->f_active & ch))
- continue;
-
- for (size_t i = 0; i < len; i++)
- cdev->putc(cdev, str[i]);
+ if (cdev->f_active & ch)
+ console_putbin(cdev, str, len);
}
return;
default:
diff --git a/common/console_common.c b/common/console_common.c
index 1d98e4ec1bcc..86d9f523b1c5 100644
--- a/common/console_common.c
+++ b/common/console_common.c
@@ -73,7 +73,7 @@ void log_clean(unsigned int limit)
}
}

-static void print_colored_log_level(unsigned int ch, const int level)
+static void print_colored_log_level(struct console_device *con, const int level)
{
if (!console_allow_color())
return;
@@ -82,7 +82,7 @@ static void print_colored_log_level(unsigned int ch, const int level)
if (!colored_log_level[level])
return;

- console_puts(ch, colored_log_level[level]);
+ console_puts(con, colored_log_level[level]);
}

static void pr_puts(int level, const char *str)
@@ -116,8 +116,8 @@ static void pr_puts(int level, const char *str)
if (level > barebox_loglevel)
return;

- print_colored_log_level(CONSOLE_STDERR, level);
- console_puts(CONSOLE_STDERR, str);
+ print_colored_log_level(CONSOLE_DEV_STDERR, level);
+ console_puts(CONSOLE_DEV_STDERR, str);
}

int pr_print(int level, const char *fmt, ...)
@@ -237,7 +237,7 @@ int log_print(unsigned flags, unsigned levels)

if (!(flags & (BAREBOX_LOG_PRINT_RAW | BAREBOX_LOG_PRINT_TIME
| BAREBOX_LOG_DIFF_TIME)))
- print_colored_log_level(CONSOLE_STDOUT, log->level);
+ print_colored_log_level(CONSOLE_DEV_STDOUT, log->level);

if (flags & BAREBOX_LOG_PRINT_RAW)
printf("<%i>", log->level);
@@ -407,7 +407,7 @@ int dputs(int fd, const char *s)
if (fd == 1)
return puts(s);
else if (fd == 2)
- return console_puts(CONSOLE_STDERR, s);
+ return console_puts(CONSOLE_DEV_STDERR, s);
else
return write(fd, s, strlen(s));
}
@@ -418,7 +418,7 @@ int dputc(int fd, char c)
if (fd == 1)
putchar(c);
else if (fd == 2)
- return console_putc(CONSOLE_STDERR, c);
+ return console_putc(CONSOLE_DEV_STDERR, c);
else
return write(fd, &c, 1);

diff --git a/common/console_simple.c b/common/console_simple.c
index dfc180e70f98..563fc542be58 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -11,7 +11,7 @@ LIST_HEAD(console_list);
EXPORT_SYMBOL(console_list);
static struct console_device *console;

-int console_puts(unsigned int ch, const char *str)
+int console_puts(struct console_device *con, const char *str)
{
const char *s = str;
int i = 0;
@@ -25,7 +25,7 @@ int console_puts(unsigned int ch, const char *str)
}
EXPORT_SYMBOL(console_puts);

-int console_putc(unsigned int ch, char c)
+int console_putc(struct console_device *con, char c)
{
bool crlf = c == '\n';
if (!console) {
diff --git a/efi/loader/protocols/console.c b/efi/loader/protocols/console.c
index 4545d94c6fae..a7395a24ad18 100644
--- a/efi/loader/protocols/console.c
+++ b/efi/loader/protocols/console.c
@@ -124,7 +124,7 @@ static efi_status_t EFIAPI efi_cout_output_string(
end = utf16_to_utf8(utf8, p, is_high_surrogate ? 2 : 1);

/* console_puts turns \n into \r\n, which we want to avoid */
- console_putbin(CONSOLE_STDOUT, utf8, end - utf8);
+ console_putbin(CONSOLE_DEV_STDOUT, utf8, end - utf8);

switch (*p) {
case '\b': /* U+0008, backspace */
diff --git a/include/console.h b/include/console.h
index 082d1ac8a924..5a4dbcdf1327 100644
--- a/include/console.h
+++ b/include/console.h
@@ -21,6 +21,10 @@

#define CONSOLE_STDIOE (CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR)

+#define CONSOLE_DEV_STDIN ((void *)CONSOLE_STDIN)
+#define CONSOLE_DEV_STDOUT ((void *)CONSOLE_STDOUT)
+#define CONSOLE_DEV_STDERR ((void *)CONSOLE_STDERR)
+
enum console_mode {
CONSOLE_MODE_NORMAL,
CONSOLE_MODE_RS485,
@@ -88,6 +92,13 @@ console_is_serdev_node(struct console_device *cdev)
return NULL;
}

+static inline unsigned int console_dev_is_std(struct console_device *con)
+{
+ if ((uintptr_t)con > CONSOLE_STDERR)
+ return 0;
+ return (uintptr_t)con & CONSOLE_STDIOE;
+}
+
int console_register(struct console_device *cdev);
int console_unregister(struct console_device *cdev);

@@ -232,9 +243,9 @@ int arch_ctrlc(void);

#ifndef CONFIG_CONSOLE_NONE
/* stdout */
-int console_putc(unsigned int ch, const char c);
-int console_puts(unsigned int ch, const char *s);
-void console_putbin(unsigned int ch, const u8 *str, size_t len);
+int console_putc(struct console_device *con, const char c);
+int console_puts(struct console_device *con, const char *s);
+void console_putbin(struct console_device *con, const u8 *str, size_t len);
void console_flush(void);

int ctrlc(void);
@@ -243,8 +254,8 @@ void ctrlc_handled(void);
void console_ctrlc_allow(void);
void console_ctrlc_forbid(void);
#else
-static inline int console_puts(unsigned int ch, const char *str) { return 0; }
-static inline int console_putc(unsigned int ch, char c) { return 0;}
+static inline int console_puts(struct console_device *con, const char *str) { return 0; }
+static inline int console_putc(struct console_device *con, char c) { return 0; }
static inline void console_flush(void) {}

/* test if ctrl-c was pressed */
diff --git a/include/stdio.h b/include/stdio.h
index 4c0dff0c0084..f5b23140adde 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -22,8 +22,8 @@ int readline(const char *prompt, char *buf, int len);
#if (IN_PROPER && !defined(CONFIG_CONSOLE_NONE)) || \
(IN_PBL && defined(CONFIG_PBL_CONSOLE))
int vprintf(const char *fmt, va_list args);
-static inline int puts(const char *s) { return console_puts(CONSOLE_STDOUT, s); }
-static inline void putchar(char c) { console_putc(CONSOLE_STDOUT, c); }
+static inline int puts(const char *s) { return console_puts(CONSOLE_DEV_STDOUT, s); }
+static inline void putchar(char c) { console_putc(CONSOLE_DEV_STDOUT, c); }
#else
static inline int puts(const char *s) { return 0; }
static inline void putchar(char c) {}
diff --git a/pbl/console.c b/pbl/console.c
index 1274552b2088..54da10a8e9ae 100644
--- a/pbl/console.c
+++ b/pbl/console.c
@@ -32,7 +32,7 @@ static void __putc(void *ctx, int c)
putc(ctx, c);
}

-int console_putc(unsigned int ch, char c)
+int console_putc(struct console_device *con, char c)
{
if (putc_offset)
__putc(putc_ctx, c);
@@ -42,17 +42,17 @@ int console_putc(unsigned int ch, char c)
return 1;
}

-int console_puts(unsigned int ch, const char *str)
+int console_puts(struct console_device *con, const char *str)
{
int n = 0;

while (*str) {
if (*str == '\n') {
- console_putc(ch, '\r');
+ console_putc(con, '\r');
n++;
}

- console_putc(ch, *str);
+ console_putc(con, *str);
str++;
n++;
}
@@ -72,7 +72,7 @@ int vprintf(const char *fmt, va_list args)
i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args);

/* Print the string */
- console_puts(CONSOLE_STDOUT, printbuffer);
+ console_puts(CONSOLE_DEV_STDOUT, printbuffer);

return i;
}
@@ -99,7 +99,7 @@ int pr_print(int level, const char *fmt, ...)
i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args);
va_end(args);

- console_puts(CONSOLE_STDERR, printbuffer);
+ console_puts(CONSOLE_DEV_STDERR, printbuffer);

return i;
}
--
2.47.3