diff options
author | Yang Zhang <yang.z.zhang@intel.com> | 2015-08-28 09:58:54 +0800 |
---|---|---|
committer | Yang Zhang <yang.z.zhang@intel.com> | 2015-09-01 12:44:00 +0800 |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/u-boot/common/console.c | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff) |
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5
Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/u-boot/common/console.c')
-rw-r--r-- | qemu/roms/u-boot/common/console.c | 846 |
1 files changed, 846 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/common/console.c b/qemu/roms/u-boot/common/console.c new file mode 100644 index 000000000..2dfb78888 --- /dev/null +++ b/qemu/roms/u-boot/common/console.c @@ -0,0 +1,846 @@ +/* + * (C) Copyright 2000 + * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <stdarg.h> +#include <malloc.h> +#include <os.h> +#include <serial.h> +#include <stdio_dev.h> +#include <exports.h> +#include <environment.h> + +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: + +#ifdef CONFIG_CONSOLE_MUX + if (iomux_doenv(console, value)) + return 1; +#else + /* Try assigning specified device */ + if (console_assign(console, value) < 0) + return 1; +#endif /* CONFIG_CONSOLE_MUX */ + 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) +{ +#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_SET + if (flags & H_INTERACTIVE) + return 0; +#endif +#ifndef CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC + if ((flags & H_INTERACTIVE) == 0) + return 0; +#endif + + 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_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_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: + /* Start new device */ + if (dev->start) { + error = dev->start(); + /* If it's not started dont use it */ + if (error < 0) + 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[XF_getc] = dev->getc; + gd->jt[XF_tstc] = dev->tstc; + break; + case stdout: + gd->jt[XF_putc] = dev->putc; + gd->jt[XF_puts] = dev->puts; + gd->jt[XF_printf] = printf; + break; + } + break; + + default: /* Invalid file ID */ + error = -1; + } + return error; +} + +#if defined(CONFIG_CONSOLE_MUX) +/** Console I/O multiplexing *******************************************/ + +static struct stdio_dev *tstcdev; +struct stdio_dev **console_devices[MAX_FILES]; +int cd_count[MAX_FILES]; + +/* + * This depends on tstc() always being called before getc(). + * 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 = NULL; + return ret; +} + +static int console_tstc(int file) +{ + int i, ret; + struct stdio_dev *dev; + + disable_ctrlc(1); + for (i = 0; i < cd_count[file]; i++) { + dev = console_devices[file][i]; + if (dev->tstc != NULL) { + ret = dev->tstc(); + if (ret > 0) { + tstcdev = dev; + disable_ctrlc(0); + return ret; + } + } + } + disable_ctrlc(0); + + return 0; +} + +static void console_putc(int file, const char c) +{ + int i; + struct stdio_dev *dev; + + for (i = 0; i < cd_count[file]; i++) { + dev = console_devices[file][i]; + if (dev->putc != NULL) + dev->putc(c); + } +} + +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]; + if (dev->puts != NULL) + dev->puts(s); + } +} + +static inline void console_printdevs(int file) +{ + iomux_printdevs(file); +} + +static inline void console_doenv(int file, struct stdio_dev *dev) +{ + iomux_doenv(file, dev->name); +} +#else +static inline int console_getc(int file) +{ + return stdio_devices[file]->getc(); +} + +static inline int console_tstc(int file) +{ + return stdio_devices[file]->tstc(); +} + +static inline void console_putc(int file, const char c) +{ + stdio_devices[file]->putc(c); +} + +static inline void console_puts(int file, const char *s) +{ + stdio_devices[file]->puts(s); +} + +static inline void console_printdevs(int file) +{ + printf("%s\n", stdio_devices[file]->name); +} + +static inline void console_doenv(int file, struct stdio_dev *dev) +{ + console_setfile(file, dev); +} +#endif /* defined(CONFIG_CONSOLE_MUX) */ + +/** 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) { +#if defined(CONFIG_CONSOLE_MUX) + /* + * Effectively poll for input wherever it may be available. + */ + for (;;) { + /* + * Upper layer may have already called tstc() so + * check for that first. + */ + if (tstcdev != NULL) + return console_getc(file); + console_tstc(file); +#ifdef CONFIG_WATCHDOG + /* + * If the watchdog must be rate-limited then it should + * already be handled in board-specific code. + */ + udelay(1); +#endif + } +#else + return console_getc(file); +#endif + } + + 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 getc(void) +{ +#ifdef CONFIG_DISABLE_CONSOLE + if (gd->flags & GD_FLG_DISABLE_CONSOLE) + return 0; +#endif + + if (!gd->have_console) + return 0; + + 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) +{ +#ifdef CONFIG_DISABLE_CONSOLE + if (gd->flags & GD_FLG_DISABLE_CONSOLE) + return 0; +#endif + + if (!gd->have_console) + return 0; + + if (gd->flags & GD_FLG_DEVINIT) { + /* Test the standard input */ + return ftstc(stdin); + } + + /* Send directly to the handler */ + return serial_tstc(); +} + +#ifdef CONFIG_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 = (char *)CONFIG_PRE_CON_BUF_ADDR; + + buffer[CIRC_BUF_IDX(gd->precon_buf_idx++)] = c; +} + +static void pre_console_puts(const char *s) +{ + while (*s) + pre_console_putc(*s++); +} + +static void print_pre_console_buffer(void) +{ + unsigned long i = 0; + char *buffer = (char *)CONFIG_PRE_CON_BUF_ADDR; + + if (gd->precon_buf_idx > CONFIG_PRE_CON_BUF_SZ) + i = gd->precon_buf_idx - CONFIG_PRE_CON_BUF_SZ; + + while (i < gd->precon_buf_idx) + putc(buffer[CIRC_BUF_IDX(i++)]); +} +#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(void) {} +#endif + +void putc(const char c) +{ +#ifdef CONFIG_SANDBOX + if (!gd) { + os_putc(c); + return; + } +#endif +#ifdef CONFIG_SILENT_CONSOLE + if (gd->flags & GD_FLG_SILENT) + return; +#endif + +#ifdef CONFIG_DISABLE_CONSOLE + if (gd->flags & GD_FLG_DISABLE_CONSOLE) + return; +#endif + + 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 */ + serial_putc(c); + } +} + +void puts(const char *s) +{ +#ifdef CONFIG_SANDBOX + if (!gd) { + os_puts(s); + return; + } +#endif + +#ifdef CONFIG_SILENT_CONSOLE + if (gd->flags & GD_FLG_SILENT) + return; +#endif + +#ifdef CONFIG_DISABLE_CONSOLE + if (gd->flags & GD_FLG_DISABLE_CONSOLE) + return; +#endif + + 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 */ + serial_puts(s); + } +} + +int printf(const char *fmt, ...) +{ + va_list args; + uint i; + char printbuffer[CONFIG_SYS_PBSIZE]; + +#if !defined(CONFIG_SANDBOX) && !defined(CONFIG_PRE_CONSOLE_BUFFER) + if (!gd->have_console) + return 0; +#endif + + 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); + + /* Print the string */ + puts(printbuffer); + return i; +} + +int vprintf(const char *fmt, va_list args) +{ + uint i; + char printbuffer[CONFIG_SYS_PBSIZE]; + +#ifndef CONFIG_PRE_CONSOLE_BUFFER + if (!gd->have_console) + return 0; +#endif + + /* For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args); + + /* Print the string */ + puts(printbuffer); + return i; +} + +/* 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 (getc()) { + case 0x03: /* ^C - Control C */ + ctrlc_was_pressed = 1; + return 1; + default: + break; + } + } + } + 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; +} + +#ifdef CONFIG_MODEM_SUPPORT_DEBUG +char screen[1024]; +char *cursor = screen; +int once = 0; +inline void dbg(const char *fmt, ...) +{ + va_list args; + uint i; + char printbuffer[CONFIG_SYS_PBSIZE]; + + if (!once) { + memset(screen, 0, sizeof(screen)); + once++; + } + + va_start(args, fmt); + + /* For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args); + va_end(args); + + if ((screen + sizeof(screen) - 1 - cursor) + < strlen(printbuffer) + 1) { + memset(screen, 0, sizeof(screen)); + cursor = screen; + } + sprintf(cursor, printbuffer); + cursor += strlen(printbuffer); + +} +#else +inline void dbg(const char *fmt, ...) +{ +} +#endif + +/** U-Boot INIT FUNCTIONS *************************************************/ + +struct stdio_dev *search_device(int flags, const char *name) +{ + struct stdio_dev *dev; + + dev = stdio_get_by_name(name); + + 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 */ + switch (file) { + case stdin: + flag = DEV_FLAGS_INPUT; + break; + case stdout: + case stderr: + flag = DEV_FLAGS_OUTPUT; + break; + default: + return -1; + } + + /* Check for valid device name */ + + dev = search_device(flag, devname); + + if (dev) + return console_setfile(file, dev); + + return -1; +} + +/* Called before relocation - use serial functions */ +int console_init_f(void) +{ + gd->have_console = 1; + +#ifdef CONFIG_SILENT_CONSOLE + if (getenv("silent") != NULL) + gd->flags |= GD_FLG_SILENT; +#endif + + print_pre_console_buffer(); + + 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); + } +} + +#ifdef CONFIG_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; +#ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE + int i; +#endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */ +#ifdef CONFIG_CONSOLE_MUX + int iomux_err = 0; +#endif + + /* set default handlers at first */ + gd->jt[XF_getc] = serial_getc; + gd->jt[XF_tstc] = serial_tstc; + gd->jt[XF_putc] = serial_putc; + gd->jt[XF_puts] = serial_puts; + gd->jt[XF_printf] = serial_printf; + + /* stdin stdout and stderr are in environment */ + /* scan for it */ + stdinname = getenv("stdin"); + stdoutname = getenv("stdout"); + stderrname = getenv("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); +#ifdef CONFIG_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; +#endif + } + /* if the devices are overwritten or not found, use default device */ + if (inputdev == NULL) { + inputdev = search_device(DEV_FLAGS_INPUT, "serial"); + } + if (outputdev == NULL) { + outputdev = search_device(DEV_FLAGS_OUTPUT, "serial"); + } + if (errdev == NULL) { + errdev = search_device(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); + } + +#ifdef CONFIG_CONSOLE_MUX +done: +#endif + +#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET + stdio_print_current_devices(); +#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ + +#ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE + /* set the environment variables (will overwrite previous env settings) */ + for (i = 0; i < 3; i++) { + setenv(stdio_names[i], stdio_devices[i]->name); + } +#endif /* CONFIG_SYS_CONSOLE_ENV_OVERWRITE */ + + 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 + return 0; +} + +#else /* CONFIG_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; + +#ifdef CONFIG_SPLASH_SCREEN + /* + * 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 (getenv("splashimage") != NULL) { + if (!(gd->flags & GD_FLG_SILENT)) + outputdev = search_device (DEV_FLAGS_OUTPUT, "serial"); + } +#endif + + /* 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(stdout, outputdev); + console_setfile(stderr, outputdev); +#ifdef CONFIG_CONSOLE_MUX + console_devices[stdout][0] = outputdev; + console_devices[stderr][0] = outputdev; +#endif + } + + /* Initializes input console */ + if (inputdev != NULL) { + console_setfile(stdin, inputdev); +#ifdef CONFIG_CONSOLE_MUX + console_devices[stdin][0] = inputdev; +#endif + } + +#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET + stdio_print_current_devices(); +#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */ + + /* Setting environment variables */ + for (i = 0; i < 3; i++) { + setenv(stdio_names[i], stdio_devices[i]->name); + } + + 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 + + return 0; +} + +#endif /* CONFIG_SYS_CONSOLE_IS_IN_ENV */ |