console: Implement flush() function
authorPali Rohár <pali@kernel.org>
Mon, 5 Sep 2022 09:31:17 +0000 (11:31 +0200)
committerTom Rini <trini@konsulko.com>
Sat, 24 Sep 2022 14:47:01 +0000 (10:47 -0400)
On certain places it is required to flush output print buffers to ensure
that text strings were sent to console or serial devices. For example when
printing message that U-Boot is going to boot kernel or when U-Boot is
going to change baudrate of terminal device.

Therefore introduce a new flush() and fflush() functions into console code.
These functions will call .flush callback of associated stdio_dev device.

As this function may increase U-Boot side, allow to compile U-Boot without
this function. For this purpose there is a new config CONSOLE_FLUSH_SUPPORT
which is enabled by default and can be disabled. It is a good idea to have
this option enabled for all boards which have enough space for it.

When option is disabled when U-Boot defines just empty static inline
function fflush() to avoid ifdefs in other code.

Signed-off-by: Pali Rohár <pali@kernel.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
common/Kconfig
common/console.c
include/_exports.h
include/stdio.h
include/stdio_dev.h

index b776c5c..6591acd 100644 (file)
@@ -186,6 +186,12 @@ config PRE_CON_BUF_ADDR
          We should consider removing this option and allocating the memory
          in board_init_f_init_reserve() instead.
 
+config CONSOLE_FLUSH_SUPPORT
+       bool "Enable console flush support"
+       default y
+       help
+         This enables compilation of flush() function for console flush support.
+
 config CONSOLE_MUX
        bool "Enable console multiplexing"
        default y if DM_VIDEO || VIDEO || LCD
index e5be6ff..ce0c9b6 100644 (file)
@@ -199,6 +199,7 @@ static int console_setfile(int file, struct stdio_dev * dev)
                case stdout:
                        gd->jt->putc  = putc;
                        gd->jt->puts  = puts;
+                       STDIO_DEV_ASSIGN_FLUSH(gd->jt, flush);
                        gd->jt->printf = printf;
                        break;
                }
@@ -364,6 +365,19 @@ static void console_puts(int file, const char *s)
        }
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static void console_flush(int file)
+{
+       int i;
+       struct stdio_dev *dev;
+
+       for_each_console_dev(i, file, dev) {
+               if (dev->flush != NULL)
+                       dev->flush(dev);
+       }
+}
+#endif
+
 #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
 static inline void console_doenv(int file, struct stdio_dev *dev)
 {
@@ -413,6 +427,14 @@ static inline void console_puts(int file, const char *s)
        stdio_devices[file]->puts(stdio_devices[file], s);
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+static inline void console_flush(int file)
+{
+       if (stdio_devices[file]->flush)
+               stdio_devices[file]->flush(stdio_devices[file]);
+}
+#endif
+
 #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV)
 static inline void console_doenv(int file, struct stdio_dev *dev)
 {
@@ -526,6 +548,14 @@ void fputs(int file, const char *s)
                console_puts(file, s);
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void fflush(int file)
+{
+       if (file < MAX_FILES)
+               console_flush(file);
+}
+#endif
+
 int fprintf(int file, const char *fmt, ...)
 {
        va_list args;
@@ -740,6 +770,37 @@ void puts(const char *s)
        }
 }
 
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void flush(void)
+{
+       if (!gd)
+               return;
+
+       /* sandbox can send characters to stdout before it has a console */
+       if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) {
+               os_flush();
+               return;
+       }
+
+       if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY))
+               return;
+
+       if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
+               return;
+
+       if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE))
+               return;
+
+       if (!gd->have_console)
+               return;
+
+       if (gd->flags & GD_FLG_DEVINIT) {
+               /* Send to the standard output */
+               fflush(stdout);
+       }
+}
+#endif
+
 #ifdef CONFIG_CONSOLE_RECORD
 int console_record_init(void)
 {
index f6df8b6..1af946f 100644 (file)
@@ -12,6 +12,9 @@
        EXPORT_FUNC(tstc, int, tstc, void)
        EXPORT_FUNC(putc, void, putc, const char)
        EXPORT_FUNC(puts, void, puts, const char *)
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+       EXPORT_FUNC(flush, void, flush, void)
+#endif
        EXPORT_FUNC(printf, int, printf, const char*, ...)
 #if (defined(CONFIG_X86) && !defined(CONFIG_X86_64)) || defined(CONFIG_PPC)
        EXPORT_FUNC(irq_install_handler, void, install_hdlr,
index 1939a48..3241e2d 100644 (file)
@@ -15,6 +15,11 @@ int tstc(void);
                defined(CONFIG_SPL_SERIAL))
 void putc(const char c);
 void puts(const char *s);
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void flush(void);
+#else
+static inline void flush(void) {}
+#endif
 int __printf(1, 2) printf(const char *fmt, ...);
 int vprintf(const char *fmt, va_list args);
 #else
@@ -26,6 +31,10 @@ static inline void puts(const char *s)
 {
 }
 
+static inline void flush(void)
+{
+}
+
 static inline int __printf(1, 2) printf(const char *fmt, ...)
 {
        return 0;
@@ -48,11 +57,17 @@ static inline int vprintf(const char *fmt, va_list args)
 /* stderr */
 #define eputc(c)               fputc(stderr, c)
 #define eputs(s)               fputs(stderr, s)
+#define eflush()               fflush(stderr)
 #define eprintf(fmt, args...)  fprintf(stderr, fmt, ##args)
 
 int __printf(2, 3) fprintf(int file, const char *fmt, ...);
 void fputs(int file, const char *s);
 void fputc(int file, const char c);
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+void fflush(int file);
+#else
+static inline void fflush(int file) {}
+#endif
 int ftstc(int file);
 int fgetc(int file);
 
index 270fa27..3105928 100644 (file)
@@ -37,6 +37,13 @@ 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);
+#ifdef CONFIG_CONSOLE_FLUSH_SUPPORT
+       /* To flush output queue */
+       void (*flush)(struct stdio_dev *dev);
+#define STDIO_DEV_ASSIGN_FLUSH(dev, flush_func) ((dev)->flush = (flush_func))
+#else
+#define STDIO_DEV_ASSIGN_FLUSH(dev, flush_func)
+#endif
 
 /* INPUT functions */