// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2000 * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DECLARE_GLOBAL_DATA_PTR; static int on_console(const char *name, const char *value, enum env_op op, int flags) { int console = -1; /* Check for console redirection */ if (strcmp(name, "stdin") == 0) console = stdin; else if (strcmp(name, "stdout") == 0) console = stdout; else if (strcmp(name, "stderr") == 0) console = stderr; /* if not actually setting a console variable, we don't care */ if (console == -1 || (gd->flags & GD_FLG_DEVINIT) == 0) return 0; switch (op) { case env_op_create: case env_op_overwrite: if (CONFIG_IS_ENABLED(CONSOLE_MUX)) { if (iomux_doenv(console, value)) return 1; } else { /* Try assigning specified device */ if (console_assign(console, value) < 0) return 1; } return 0; case env_op_delete: if ((flags & H_FORCE) == 0) printf("Can't delete \"%s\"\n", name); return 1; default: return 0; } } U_BOOT_ENV_CALLBACK(console, on_console); #ifdef CONFIG_SILENT_CONSOLE static int on_silent(const char *name, const char *value, enum env_op op, int flags) { if (!CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_SET)) if (flags & H_INTERACTIVE) return 0; if (!CONFIG_IS_ENABLED(SILENT_CONSOLE_UPDATE_ON_RELOC)) if ((flags & H_INTERACTIVE) == 0) return 0; if (value != NULL) gd->flags |= GD_FLG_SILENT; else gd->flags &= ~GD_FLG_SILENT; return 0; } U_BOOT_ENV_CALLBACK(silent, on_silent); #endif #ifdef CONFIG_CONSOLE_RECORD /* helper function: access to gd->console_out and gd->console_in */ static void console_record_putc(const char c) { if (!(gd->flags & GD_FLG_RECORD)) return; if (gd->console_out.start) membuff_putbyte((struct membuff *)&gd->console_out, c); } 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)); } static int console_record_getc(void) { if (!(gd->flags & GD_FLG_RECORD)) return -1; if (!gd->console_in.start) return -1; return membuff_getbyte((struct membuff *)&gd->console_in); } static int console_record_tstc(void) { if (!(gd->flags & GD_FLG_RECORD)) return 0; if (gd->console_in.start) { if (membuff_peekbyte((struct membuff *)&gd->console_in) != -1) return 1; } return 0; } #else static void console_record_putc(char c) { } static void console_record_puts(const char *s) { } static int console_record_getc(void) { return -1; } static int console_record_tstc(void) { return 0; } #endif #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) /* * if overwrite_console returns 1, the stdin, stderr and stdout * are switched to the serial port, else the settings in the * environment are used */ #ifdef CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE extern int overwrite_console(void); #define OVERWRITE_CONSOLE overwrite_console() #else #define OVERWRITE_CONSOLE 0 #endif /* CONFIG_SYS_CONSOLE_OVERWRITE_ROUTINE */ #endif /* CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */ static int console_setfile(int file, struct stdio_dev * dev) { int error = 0; if (dev == NULL) return -1; switch (file) { case stdin: case stdout: case stderr: error = console_start(file, dev); if (error) break; /* Assign the new device (leaving the existing one started) */ stdio_devices[file] = dev; /* * Update monitor functions * (to use the console stuff by other applications) */ switch (file) { case stdin: gd->jt->getc = getchar; gd->jt->tstc = tstc; break; case stdout: gd->jt->putc = putc; gd->jt->puts = puts; gd->jt->printf = printf; break; } break; default: /* Invalid file ID */ error = -1; } return error; } /** * 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, * whether it is called "serial". */ static bool console_dev_is_serial(struct stdio_dev *sdev) { bool is_serial; if (IS_ENABLED(CONFIG_DM_SERIAL) && (sdev->flags & DEV_FLAGS_DM)) { struct udevice *dev = sdev->priv; is_serial = device_get_uclass_id(dev) == UCLASS_SERIAL; } else { is_serial = !strcmp(sdev->name, "serial"); } return is_serial; } #if CONFIG_IS_ENABLED(CONSOLE_MUX) /** Console I/O multiplexing *******************************************/ /* tstcdev: save the last stdio device with pending characters, with tstc != 0 */ static struct stdio_dev *tstcdev; struct stdio_dev **console_devices[MAX_FILES]; int cd_count[MAX_FILES]; 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; } /* * This depends on tstc() always being called before getchar(). * This is guaranteed to be true because this routine is called * only from fgetc() which assures it. * No attempt is made to demultiplex multiple input sources. */ static int console_getc(int file) { unsigned char ret; /* This is never called with testcdev == NULL */ ret = tstcdev->getc(tstcdev); tstcdev = NULL; return ret; } /* Upper layer may have already called tstc(): check the saved result */ static bool console_has_tstc(void) { return !!tstcdev; } static int console_tstc(int file) { int i, ret; struct stdio_dev *dev; int prev; prev = disable_ctrlc(1); for_each_console_dev(i, file, dev) { if (dev->tstc != NULL) { ret = dev->tstc(dev); if (ret > 0) { tstcdev = dev; disable_ctrlc(prev); return ret; } } } disable_ctrlc(prev); return 0; } static void console_putc(int file, const char c) { int i; struct stdio_dev *dev; for_each_console_dev(i, file, dev) { if (dev->putc != NULL) dev->putc(dev, c); } } /** * console_puts_select() - Output a string to all console devices * * @file: File number to output to (e,g, stdout, see stdio.h) * @serial_only: true to output only to serial, false to output to everything * else * @s: String to output */ static void console_puts_select(int file, bool serial_only, const char *s) { int i; struct stdio_dev *dev; for_each_console_dev(i, file, dev) { bool 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); } static void console_puts(int file, const char *s) { int i; struct stdio_dev *dev; for_each_console_dev(i, file, dev) { if (dev->puts != NULL) dev->puts(dev, s); } } #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) static inline void console_doenv(int file, struct stdio_dev *dev) { iomux_doenv(file, dev->name); } #endif #else 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) { return stdio_devices[file]->getc(stdio_devices[file]); } static bool console_has_tstc(void) { return false; } static inline int console_tstc(int file) { return stdio_devices[file]->tstc(stdio_devices[file]); } static inline void console_putc(int file, const char c) { stdio_devices[file]->putc(stdio_devices[file], c); } void console_puts_select(int file, bool serial_only, const char *s) { if (serial_only == console_dev_is_serial(stdio_devices[file])) stdio_devices[file]->puts(stdio_devices[file], s); } static inline void console_puts(int file, const char *s) { stdio_devices[file]->puts(stdio_devices[file], s); } #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) static inline void console_doenv(int file, struct stdio_dev *dev) { console_setfile(file, 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); /* If it's not started don't use it */ if (error < 0) return error; } return 0; } void console_stop(int file, struct stdio_dev *sdev) { if (!console_needs_start_stop(file, sdev)) return; if (sdev->stop) sdev->stop(sdev); } /** U-Boot INITIAL CONSOLE-NOT COMPATIBLE FUNCTIONS *************************/ int serial_printf(const char *fmt, ...) { va_list args; uint i; char printbuffer[CONFIG_SYS_PBSIZE]; va_start(args, fmt); /* For this to work, printbuffer must be larger than * anything we ever want to print. */ i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); va_end(args); serial_puts(printbuffer); return i; } int fgetc(int file) { if (file < MAX_FILES) { /* * Effectively poll for input wherever it may be available. */ for (;;) { WATCHDOG_RESET(); if (CONFIG_IS_ENABLED(CONSOLE_MUX)) { /* * Upper layer may have already called tstc() so * check for that first. */ if (console_has_tstc()) return console_getc(file); console_tstc(file); } else { if (console_tstc(file)) return console_getc(file); } /* * If the watchdog must be rate-limited then it should * already be handled in board-specific code. */ if (IS_ENABLED(CONFIG_WATCHDOG)) udelay(1); } } return -1; } int ftstc(int file) { if (file < MAX_FILES) return console_tstc(file); return -1; } void fputc(int file, const char c) { if (file < MAX_FILES) console_putc(file, c); } void fputs(int file, const char *s) { if (file < MAX_FILES) console_puts(file, s); } int fprintf(int file, const char *fmt, ...) { va_list args; uint i; char printbuffer[CONFIG_SYS_PBSIZE]; va_start(args, fmt); /* For this to work, printbuffer must be larger than * anything we ever want to print. */ i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); va_end(args); /* Send to desired file */ fputs(file, printbuffer); return i; } /** U-Boot INITIAL CONSOLE-COMPATIBLE FUNCTION *****************************/ int getchar(void) { int ch; if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return 0; if (!gd->have_console) return 0; ch = console_record_getc(); if (ch != -1) return ch; if (gd->flags & GD_FLG_DEVINIT) { /* Get from the standard input */ return fgetc(stdin); } /* Send directly to the handler */ return serial_getc(); } int tstc(void) { if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return 0; if (!gd->have_console) return 0; if (console_record_tstc()) return 1; if (gd->flags & GD_FLG_DEVINIT) { /* Test the standard input */ return ftstc(stdin); } /* Send directly to the handler */ return serial_tstc(); } #define PRE_CONSOLE_FLUSHPOINT1_SERIAL 0 #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) static void pre_console_putc(const char c) { char *buffer; buffer = map_sysmem(CONFIG_PRE_CON_BUF_ADDR, CONFIG_PRE_CON_BUF_SZ); buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c; unmap_sysmem(buffer); } static void pre_console_puts(const char *s) { 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]; 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; while (in < gd->precon_buf_idx) buf_out[out++] = buf_in[CIRC_BUF_IDX(in++)]; unmap_sysmem(buf_in); buf_out[out] = 0; switch (flushpoint) { case PRE_CONSOLE_FLUSHPOINT1_SERIAL: puts(buf_out); break; case PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL: console_puts_select(stdout, false, buf_out); break; } } #else static inline void pre_console_putc(const char c) {} static inline void pre_console_puts(const char *s) {} static inline void print_pre_console_buffer(int flushpoint) {} #endif void putc(const char c) { if (!gd) return; console_record_putc(c); /* sandbox can send characters to stdout before it has a console */ if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) { os_putc(c); return; } /* if we don't have a console yet, use the debug UART */ if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) { printch(c); return; } if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) { if (!(gd->flags & GD_FLG_DEVINIT)) pre_console_putc(c); return; } if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return; if (!gd->have_console) return pre_console_putc(c); if (gd->flags & GD_FLG_DEVINIT) { /* Send to the standard output */ fputc(stdout, c); } else { /* Send directly to the handler */ pre_console_putc(c); serial_putc(c); } } void puts(const char *s) { if (!gd) return; console_record_puts(s); /* sandbox can send characters to stdout before it has a console */ if (IS_ENABLED(CONFIG_SANDBOX) && !(gd->flags & GD_FLG_SERIAL_READY)) { os_puts(s); return; } if (IS_ENABLED(CONFIG_DEBUG_UART) && !(gd->flags & GD_FLG_SERIAL_READY)) { while (*s) { int ch = *s++; printch(ch); } return; } if (IS_ENABLED(CONFIG_SILENT_CONSOLE) && (gd->flags & GD_FLG_SILENT)) { if (!(gd->flags & GD_FLG_DEVINIT)) pre_console_puts(s); return; } if (IS_ENABLED(CONFIG_DISABLE_CONSOLE) && (gd->flags & GD_FLG_DISABLE_CONSOLE)) return; if (!gd->have_console) return pre_console_puts(s); if (gd->flags & GD_FLG_DEVINIT) { /* Send to the standard output */ fputs(stdout, s); } else { /* Send directly to the handler */ pre_console_puts(s); serial_puts(s); } } #ifdef CONFIG_CONSOLE_RECORD int console_record_init(void) { int ret; ret = membuff_new((struct membuff *)&gd->console_out, CONFIG_CONSOLE_RECORD_OUT_SIZE); if (ret) return ret; ret = membuff_new((struct membuff *)&gd->console_in, CONFIG_CONSOLE_RECORD_IN_SIZE); return ret; } void console_record_reset(void) { membuff_purge((struct membuff *)&gd->console_out); membuff_purge((struct membuff *)&gd->console_in); } int console_record_reset_enable(void) { console_record_reset(); gd->flags |= GD_FLG_RECORD; return 0; } int console_record_readline(char *str, int maxlen) { return membuff_readline((struct membuff *)&gd->console_out, str, maxlen, ' '); } int console_record_avail(void) { return membuff_avail((struct membuff *)&gd->console_out); } #endif /* test if ctrl-c was pressed */ static int ctrlc_disabled = 0; /* see disable_ctrl() */ static int ctrlc_was_pressed = 0; int ctrlc(void) { if (!ctrlc_disabled && gd->have_console) { if (tstc()) { switch (getchar()) { case 0x03: /* ^C - Control C */ ctrlc_was_pressed = 1; return 1; default: break; } } } return 0; } /* Reads user's confirmation. Returns 1 if user's input is "y", "Y", "yes" or "YES" */ int confirm_yesno(void) { int i; char str_input[5]; /* Flush input */ while (tstc()) getchar(); i = 0; while (i < sizeof(str_input)) { str_input[i] = getchar(); putc(str_input[i]); if (str_input[i] == '\r') break; i++; } putc('\n'); if (strncmp(str_input, "y\r", 2) == 0 || strncmp(str_input, "Y\r", 2) == 0 || strncmp(str_input, "yes\r", 4) == 0 || strncmp(str_input, "YES\r", 4) == 0) return 1; return 0; } /* pass 1 to disable ctrlc() checking, 0 to enable. * returns previous state */ int disable_ctrlc(int disable) { int prev = ctrlc_disabled; /* save previous state */ ctrlc_disabled = disable; return prev; } int had_ctrlc (void) { return ctrlc_was_pressed; } void clear_ctrlc(void) { ctrlc_was_pressed = 0; } /** U-Boot INIT FUNCTIONS *************************************************/ struct stdio_dev *console_search_dev(int flags, const char *name) { struct stdio_dev *dev; dev = stdio_get_by_name(name); #ifdef CONFIG_VIDCONSOLE_AS_LCD if (!dev && !strcmp(name, CONFIG_VIDCONSOLE_AS_NAME)) dev = stdio_get_by_name("vidconsole"); #endif if (dev && (dev->flags & flags)) return dev; return NULL; } int console_assign(int file, const char *devname) { int flag; struct stdio_dev *dev; /* Check for valid file */ flag = stdio_file_to_flags(file); if (flag < 0) return flag; /* Check for valid device name */ dev = console_search_dev(flag, devname); if (dev) return console_setfile(file, dev); return -1; } /* return true if the 'silent' flag is removed */ static bool console_update_silent(void) { unsigned long flags = gd->flags; if (!IS_ENABLED(CONFIG_SILENT_CONSOLE)) return false; if (env_get("silent")) { gd->flags |= GD_FLG_SILENT; return false; } gd->flags &= ~GD_FLG_SILENT; return !!(flags & GD_FLG_SILENT); } int console_announce_r(void) { #if !CONFIG_IS_ENABLED(PRE_CONSOLE_BUFFER) char buf[DISPLAY_OPTIONS_BANNER_LENGTH]; display_options_get_banner(false, buf, sizeof(buf)); console_puts_select(stdout, false, buf); #endif return 0; } /* Called before relocation - use serial functions */ int console_init_f(void) { gd->have_console = 1; console_update_silent(); print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL); return 0; } void stdio_print_current_devices(void) { /* Print information */ puts("In: "); if (stdio_devices[stdin] == NULL) { puts("No input devices available!\n"); } else { printf ("%s\n", stdio_devices[stdin]->name); } puts("Out: "); if (stdio_devices[stdout] == NULL) { puts("No output devices available!\n"); } else { printf ("%s\n", stdio_devices[stdout]->name); } puts("Err: "); if (stdio_devices[stderr] == NULL) { puts("No error devices available!\n"); } else { printf ("%s\n", stdio_devices[stderr]->name); } } #if CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) /* Called after the relocation - use desired console functions */ int console_init_r(void) { char *stdinname, *stdoutname, *stderrname; struct stdio_dev *inputdev = NULL, *outputdev = NULL, *errdev = NULL; int i; int iomux_err = 0; int flushpoint; /* update silent for env loaded from flash (initr_env) */ if (console_update_silent()) flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL; else flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL; /* set default handlers at first */ gd->jt->getc = serial_getc; gd->jt->tstc = serial_tstc; gd->jt->putc = serial_putc; gd->jt->puts = serial_puts; gd->jt->printf = serial_printf; /* stdin stdout and stderr are in environment */ /* scan for it */ stdinname = env_get("stdin"); stdoutname = env_get("stdout"); stderrname = env_get("stderr"); if (OVERWRITE_CONSOLE == 0) { /* if not overwritten by config switch */ 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); iomux_err += iomux_doenv(stderr, stderrname); if (!iomux_err) /* Successful, so skip all the code below. */ goto done; } } /* if the devices are overwritten or not found, use default device */ if (inputdev == NULL) { inputdev = console_search_dev(DEV_FLAGS_INPUT, "serial"); } if (outputdev == NULL) { outputdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial"); } if (errdev == NULL) { errdev = console_search_dev(DEV_FLAGS_OUTPUT, "serial"); } /* Initializes output console first */ if (outputdev != NULL) { /* need to set a console if not done above. */ console_doenv(stdout, outputdev); } if (errdev != NULL) { /* need to set a console if not done above. */ console_doenv(stderr, errdev); } if (inputdev != NULL) { /* need to set a console if not done above. */ console_doenv(stdin, inputdev); } done: if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET)) stdio_print_current_devices(); #ifdef CONFIG_VIDCONSOLE_AS_LCD if (strstr(stdoutname, CONFIG_VIDCONSOLE_AS_NAME)) printf("Warning: Please change '%s' to 'vidconsole' in stdout/stderr environment vars\n", CONFIG_VIDCONSOLE_AS_NAME); #endif if (IS_ENABLED(CONFIG_SYS_CONSOLE_ENV_OVERWRITE)) { /* set the environment variables (will overwrite previous env settings) */ for (i = 0; i < MAX_FILES; i++) env_set(stdio_names[i], stdio_devices[i]->name); } gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ print_pre_console_buffer(flushpoint); return 0; } #else /* !CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */ /* Called after the relocation - use desired console functions */ int console_init_r(void) { struct stdio_dev *inputdev = NULL, *outputdev = NULL; int i; struct list_head *list = stdio_get_list(); struct list_head *pos; struct stdio_dev *dev; int flushpoint; /* update silent for env loaded from flash (initr_env) */ if (console_update_silent()) flushpoint = PRE_CONSOLE_FLUSHPOINT1_SERIAL; else flushpoint = PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL; /* * suppress all output if splash screen is enabled and we have * a bmp to display. We redirect the output from frame buffer * console to serial console in this case or suppress it if * "silent" mode was requested. */ if (IS_ENABLED(CONFIG_SPLASH_SCREEN) && env_get("splashimage")) { if (!(gd->flags & GD_FLG_SILENT)) outputdev = console_search_dev (DEV_FLAGS_OUTPUT, "serial"); } /* Scan devices looking for input and output devices */ list_for_each(pos, list) { dev = list_entry(pos, struct stdio_dev, list); if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) { inputdev = dev; } if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) { outputdev = dev; } if(inputdev && outputdev) break; } /* Initializes output console first */ if (outputdev != NULL) { console_setfile_and_devices(stdout, outputdev); console_setfile_and_devices(stderr, outputdev); } /* Initializes input console */ if (inputdev != NULL) console_setfile_and_devices(stdin, inputdev); if (!IS_ENABLED(CONFIG_SYS_CONSOLE_INFO_QUIET)) stdio_print_current_devices(); /* Setting environment variables */ for (i = 0; i < MAX_FILES; i++) { env_set(stdio_names[i], stdio_devices[i]->name); } gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */ print_pre_console_buffer(flushpoint); return 0; } #endif /* CONFIG_IS_ENABLED(SYS_CONSOLE_IS_IN_ENV) */