#include <common.h>
#include <console.h>
#include <debug_uart.h>
+#include <display_options.h>
#include <dm.h>
#include <env.h>
#include <stdarg.h>
#include <exports.h>
#include <env_internal.h>
#include <watchdog.h>
+#include <asm/global_data.h>
#include <linux/delay.h>
DECLARE_GLOBAL_DATA_PTR;
{
if (!(gd->flags & GD_FLG_RECORD))
return;
- if (gd->console_out.start)
- membuff_putbyte((struct membuff *)&gd->console_out, c);
+ if (gd->console_out.start &&
+ !membuff_putbyte((struct membuff *)&gd->console_out, c))
+ gd->flags |= GD_FLG_RECORD_OVF;
}
static void console_record_puts(const char *s)
{
if (!(gd->flags & GD_FLG_RECORD))
return;
- if (gd->console_out.start)
- membuff_put((struct membuff *)&gd->console_out, s, strlen(s));
+ if (gd->console_out.start) {
+ int len = strlen(s);
+
+ if (membuff_put((struct membuff *)&gd->console_out, s, len) !=
+ len)
+ gd->flags |= GD_FLG_RECORD_OVF;
+ }
}
static int console_record_getc(void)
case stdout:
gd->jt->putc = putc;
gd->jt->puts = puts;
+ STDIO_DEV_ASSIGN_FLUSH(gd->jt, flush);
gd->jt->printf = printf;
break;
}
* console_dev_is_serial() - Check if a stdio device is a serial device
*
* @sdev: Device to check
- * @return true if this device is in the serial uclass (or for pre-driver-model,
+ * Return: true if this device is in the serial uclass (or for pre-driver-model,
* whether it is called "serial".
*/
static bool console_dev_is_serial(struct stdio_dev *sdev)
struct stdio_dev **console_devices[MAX_FILES];
int cd_count[MAX_FILES];
-static void __maybe_unused console_devices_set(int file, struct stdio_dev *dev)
+static void console_devices_set(int file, struct stdio_dev *dev)
{
console_devices[file][0] = dev;
+ cd_count[file] = 1;
+}
+
+/**
+ * console_needs_start_stop() - check if we need to start or stop the STDIO device
+ * @file: STDIO file
+ * @sdev: STDIO device in question
+ *
+ * This function checks if we need to start or stop the stdio device used for
+ * a console. For IOMUX case it simply enforces one time start and one time
+ * stop of the device independently of how many STDIO files are using it. In
+ * other words, we start console once before first STDIO device wants it and
+ * stop after the last is gone.
+ */
+static bool console_needs_start_stop(int file, struct stdio_dev *sdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cd_count); i++) {
+ if (i == file)
+ continue;
+
+ if (iomux_match_device(console_devices[i], cd_count[i], sdev) >= 0)
+ return false;
+ }
+ return true;
}
/*
int prev;
prev = disable_ctrlc(1);
- for (i = 0; i < cd_count[file]; i++) {
- dev = console_devices[file][i];
+ for_each_console_dev(i, file, dev) {
if (dev->tstc != NULL) {
ret = dev->tstc(dev);
if (ret > 0) {
int i;
struct stdio_dev *dev;
- for (i = 0; i < cd_count[file]; i++) {
- dev = console_devices[file][i];
+ for_each_console_dev(i, file, dev) {
if (dev->putc != NULL)
dev->putc(dev, c);
}
int i;
struct stdio_dev *dev;
- for (i = 0; i < cd_count[file]; i++) {
- bool is_serial;
+ for_each_console_dev(i, file, dev) {
+ bool is_serial = console_dev_is_serial(dev);
- dev = console_devices[file][i];
- is_serial = console_dev_is_serial(dev);
if (dev->puts && serial_only == is_serial)
dev->puts(dev, s);
}
void console_puts_select_stderr(bool serial_only, const char *s)
{
- console_puts_select(stderr, serial_only, s);
+ if (gd->flags & GD_FLG_DEVINIT)
+ console_puts_select(stderr, serial_only, s);
}
static void console_puts(int file, const char *s)
int i;
struct stdio_dev *dev;
- for (i = 0; i < cd_count[file]; i++) {
- dev = console_devices[file][i];
+ for_each_console_dev(i, file, dev) {
if (dev->puts != NULL)
dev->puts(dev, 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)
{
#endif
#else
-static void __maybe_unused console_devices_set(int file, struct stdio_dev *dev)
+static void console_devices_set(int file, struct stdio_dev *dev)
+{
+}
+
+static inline bool console_needs_start_stop(int file, struct stdio_dev *sdev)
{
+ return true;
}
static inline int console_getc(int file)
void console_puts_select(int file, bool serial_only, const char *s)
{
- if (serial_only == console_dev_is_serial(stdio_devices[file]))
+ if ((gd->flags & GD_FLG_DEVINIT) &&
+ serial_only == console_dev_is_serial(stdio_devices[file]))
stdio_devices[file]->puts(stdio_devices[file], 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)
{
#endif
#endif /* CONIFIG_IS_ENABLED(CONSOLE_MUX) */
+static void __maybe_unused console_setfile_and_devices(int file, struct stdio_dev *dev)
+{
+ console_setfile(file, dev);
+ console_devices_set(file, dev);
+}
+
int console_start(int file, struct stdio_dev *sdev)
{
int error;
+ if (!console_needs_start_stop(file, sdev))
+ return 0;
+
/* Start new device */
if (sdev->start) {
error = sdev->start(sdev);
void console_stop(int file, struct stdio_dev *sdev)
{
+ if (!console_needs_start_stop(file, sdev))
+ return;
+
if (sdev->stop)
sdev->stop(sdev);
}
* Effectively poll for input wherever it may be available.
*/
for (;;) {
- WATCHDOG_RESET();
+ schedule();
if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
/*
* Upper layer may have already called tstc() so
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;
#define PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL 1
#if CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER)
-#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_PRE_CON_BUF_SZ)
+#define CIRC_BUF_IDX(idx) ((idx) % (unsigned long)CONFIG_VAL(PRE_CON_BUF_SZ))
static void pre_console_putc(const char c)
{
char *buffer;
- buffer = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ);
+ if (gd->precon_buf_idx < 0)
+ return;
+
+ buffer = map_sysmem(CONFIG_VAL(PRE_CON_BUF_ADDR), CONFIG_VAL(PRE_CON_BUF_SZ));
buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c;
static void pre_console_puts(const char *s)
{
+ if (gd->precon_buf_idx < 0)
+ return;
+
while (*s)
pre_console_putc(*s++);
}
static void print_pre_console_buffer(int flushpoint)
{
- unsigned long in = 0, out = 0;
- char buf_out[CONFIG_PRE_CON_BUF_SZ + 1];
+ long in = 0, out = 0;
+ char buf_out[CONFIG_VAL(PRE_CON_BUF_SZ) + 1];
char *buf_in;
if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT))
return;
- buf_in = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ);
- if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ)
- in = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ;
+ buf_in = map_sysmem(CONFIG_VAL(PRE_CON_BUF_ADDR), CONFIG_VAL(PRE_CON_BUF_SZ));
+ if (gd->precon_buf_idx > CONFIG_VAL(PRE_CON_BUF_SZ))
+ in = gd->precon_buf_idx - CONFIG_VAL(PRE_CON_BUF_SZ);
while (in < gd->precon_buf_idx)
buf_out[out++] = buf_in[CIRC_BUF_IDX(in++)];
buf_out[out] = 0;
+ gd->precon_buf_idx = -1;
switch (flushpoint) {
case PRE_CONSOLE_FLUSHPOINT1_SERIAL:
puts(buf_out);
console_puts_select(stdout, false, buf_out);
break;
}
+ gd->precon_buf_idx = in;
}
#else
static inline void pre_console_putc(const char c) {}
}
}
+#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);
+ } else {
+ /* Send directly to the handler */
+ serial_flush();
+ }
+}
+#endif
+
#ifdef CONFIG_CONSOLE_RECORD
int console_record_init(void)
{
int ret;
ret = membuff_new((struct membuff *)&gd->console_out,
- CONFIG_CONSOLE_RECORD_OUT_SIZE);
+ gd->flags & GD_FLG_RELOC ?
+ CONFIG_CONSOLE_RECORD_OUT_SIZE :
+ CONFIG_CONSOLE_RECORD_OUT_SIZE_F);
if (ret)
return ret;
ret = membuff_new((struct membuff *)&gd->console_in,
{
membuff_purge((struct membuff *)&gd->console_out);
membuff_purge((struct membuff *)&gd->console_in);
+ gd->flags &= ~GD_FLG_RECORD_OVF;
}
int console_record_reset_enable(void)
int console_record_readline(char *str, int maxlen)
{
+ if (gd->flags & GD_FLG_RECORD_OVF)
+ return -ENOSPC;
+
return membuff_readline((struct membuff *)&gd->console_out, str,
maxlen, ' ');
}
return membuff_avail((struct membuff *)&gd->console_out);
}
+int console_in_puts(const char *str)
+{
+ return membuff_put((struct membuff *)&gd->console_in, str, strlen(str));
+}
+
#endif
/* test if ctrl-c was pressed */
/** U-Boot INIT FUNCTIONS *************************************************/
-struct stdio_dev *search_device(int flags, const char *name)
+struct stdio_dev *console_search_dev(int flags, const char *name)
{
struct stdio_dev *dev;
struct stdio_dev *dev;
/* Check for valid file */
- switch (file) {
- case stdin:
- flag = DEV_FLAGS_INPUT;
- break;
- case stdout:
- case stderr:
- flag = DEV_FLAGS_OUTPUT;
- break;
- default:
- return -1;
- }
+ flag = stdio_file_to_flags(file);
+ if (flag < 0)
+ return flag;
/* Check for valid device name */
- dev = search_device(flag, devname);
+ dev = console_search_dev(flag, devname);
if (dev)
return console_setfile(file, dev);
stderrname = env_get("stderr");
if (OVERWRITE_CONSOLE == 0) { /* if not overwritten by config switch */
- inputdev = search_device(DEV_FLAGS_INPUT, stdinname);
- outputdev = search_device(DEV_FLAGS_OUTPUT, stdoutname);
- errdev = search_device(DEV_FLAGS_OUTPUT, stderrname);
+ inputdev = console_search_dev(DEV_FLAGS_INPUT, stdinname);
+ outputdev = console_search_dev(DEV_FLAGS_OUTPUT, stdoutname);
+ errdev = console_search_dev(DEV_FLAGS_OUTPUT, stderrname);
if (CONFIG_IS_ENABLED(CONSOLE_MUX)) {
iomux_err = iomux_doenv(stdin, stdinname);
iomux_err += iomux_doenv(stdout, stdoutname);
}
/* if the devices are overwritten or not found, use default device */
if (inputdev == NULL) {
- inputdev = search_device(DEV_FLAGS_INPUT, "serial");
+ inputdev = console_search_dev(DEV_FLAGS_INPUT, "serial");
}
if (outputdev == NULL) {
- outputdev = search_device(DEV_FLAGS_OUTPUT, "serial");
+ outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
}
if (errdev == NULL) {
- errdev = search_device(DEV_FLAGS_OUTPUT, "serial");
+ errdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial");
}
/* Initializes output console first */
if (outputdev != NULL) {
gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
-#if 0
- /* If nothing usable installed, use only the initial console */
- if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
- return 0;
-#endif
print_pre_console_buffer(flushpoint);
return 0;
}
*/
if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) {
if (!(gd->flags & GD_FLG_SILENT))
- outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
+ outputdev = console_search_dev (DEV_FLAGS_OUTPUT, "serial");
}
/* Scan devices looking for input and output devices */
/* Initializes output console first */
if (outputdev != NULL) {
- console_setfile(stdout, outputdev);
- console_setfile(stderr, outputdev);
- console_devices_set(stdout, outputdev);
- console_devices_set(stderr, outputdev);
+ console_setfile_and_devices(stdout, outputdev);
+ console_setfile_and_devices(stderr, outputdev);
}
/* Initializes input console */
- if (inputdev != NULL) {
- console_setfile(stdin, inputdev);
- console_devices_set(stdin, inputdev);
- }
+ if (inputdev != NULL)
+ console_setfile_and_devices(stdin, inputdev);
if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET))
stdio_print_current_devices();
gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
-#if 0
- /* If nothing usable installed, use only the initial console */
- if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
- return 0;
-#endif
print_pre_console_buffer(flushpoint);
return 0;
}