summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuriyan Ramasami <suriyan.r@gmail.com>2013-10-16 21:59:20 +0400
committerMauro Ribeiro <git@mdrjr.net>2013-10-16 21:59:20 +0400
commit29d4c3b97c8e30504a951105fb6452210c56528a (patch)
tree3b76d21cc86441ac0404817ce861b3c5b599386b
parent286a81158f01dcb08e16d77790c21fd2a40afc6c (diff)
downloadu-boot-29d4c3b97c8e30504a951105fb6452210c56528a.tar.xz
Enable netconsole and usb keyboard with console mux.
-rw-r--r--arch/arm/include/asm/u-boot-arm.h2
-rw-r--r--arch/arm/lib/board.c2
-rw-r--r--board/samsung/smdk4212/u-boot.lds6
-rw-r--r--common/Makefile3
-rw-r--r--common/cmd_fastboot.c4
-rw-r--r--common/cmd_help.c34
-rw-r--r--common/cmd_nvedit.c948
-rw-r--r--common/command.c153
-rw-r--r--common/console.c170
-rw-r--r--common/env_attr.c213
-rw-r--r--common/env_auto.c6
-rw-r--r--common/env_callback.c128
-rw-r--r--common/env_common.c263
-rw-r--r--common/env_flags.c544
-rw-r--r--common/hush.c254
-rw-r--r--common/image.c10
-rw-r--r--common/iomux.c30
-rw-r--r--common/main.c667
-rw-r--r--common/stdio.c49
-rw-r--r--common/usb_kbd.c1055
-rw-r--r--drivers/net/netconsole.c267
-rw-r--r--drivers/usb/host/ehci-hcd.c38
-rw-r--r--include/command.h133
-rw-r--r--include/common.h92
-rw-r--r--include/configs/smdk4412.h13
-rw-r--r--include/env_attr.h39
-rw-r--r--include/env_callback.h73
-rw-r--r--include/env_default.h138
-rw-r--r--include/env_flags.h156
-rw-r--r--include/environment.h132
-rw-r--r--include/exports.h6
-rw-r--r--include/fdtdec.h530
-rw-r--r--include/hush.h21
-rw-r--r--include/image.h2
-rw-r--r--include/iomux.h20
-rw-r--r--include/linker_lists.h288
-rw-r--r--include/linux/ctype.h8
-rw-r--r--include/linux/linux_string.h8
-rw-r--r--include/linux/string.h11
-rw-r--r--include/linux/stringify.h12
-rw-r--r--include/malloc.h8
-rw-r--r--include/menu.h26
-rw-r--r--include/search.h93
-rw-r--r--include/slre.h100
-rw-r--r--include/stdio_dev.h31
-rw-r--r--include/vsprintf.h176
-rw-r--r--lib/Makefile1
-rw-r--r--lib/ctype.c20
-rw-r--r--lib/hashtable.c441
-rw-r--r--lib/linux_string.c51
-rw-r--r--lib/vsprintf.c445
-rw-r--r--net/net.c6
52 files changed, 5631 insertions, 2295 deletions
diff --git a/arch/arm/include/asm/u-boot-arm.h b/arch/arm/include/asm/u-boot-arm.h
index 33973a32e0..fabb1dd892 100644
--- a/arch/arm/include/asm/u-boot-arm.h
+++ b/arch/arm/include/asm/u-boot-arm.h
@@ -62,7 +62,7 @@ void setup_revision_tag (struct tag **params);
/* To be fixed! */
/* ------------------------------------------------------------ */
/* common/cmd_nvedit.c */
-int setenv (char *, char *);
+int setenv (const char *, const char *);
/* cpu/.../interrupt.c */
int arch_interrupt_init (void);
diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 122ac1be2f..da877bb20c 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -549,7 +549,7 @@ void board_init_r (gd_t *id, ulong dest_addr)
api_init ();
#endif
- //console_init_r (); /* fully init console as a device */
+ console_init_r (); /* fully init console as a device */
#if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
diff --git a/board/samsung/smdk4212/u-boot.lds b/board/samsung/smdk4212/u-boot.lds
index 9b989bff21..a4302abc1d 100644
--- a/board/samsung/smdk4212/u-boot.lds
+++ b/board/samsung/smdk4212/u-boot.lds
@@ -53,10 +53,8 @@ SECTIONS
. = ALIGN(4);
. = .;
- __u_boot_cmd_start = .;
- .u_boot_cmd : { *(.u_boot_cmd) }
- __u_boot_cmd_end = .;
-
+ . = ALIGN(4);
+ .u_boot_list : { KEEP(*(SORT(.u_boot_list*))); }
. = ALIGN(4);
.rel.dyn : {
diff --git a/common/Makefile b/common/Makefile
index 2ec669efc5..028323259f 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -55,6 +55,9 @@ COBJS-y += cmd_version.o
# environment
COBJS-y += env_common.o
+COBJS-y += env_callback.o
+COBJS-y += env_flags.o
+COBJS-y += env_attr.o
COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o
diff --git a/common/cmd_fastboot.c b/common/cmd_fastboot.c
index 88a1ffaefd..8b95f5ff27 100644
--- a/common/cmd_fastboot.c
+++ b/common/cmd_fastboot.c
@@ -88,14 +88,14 @@ extern unsigned int OmPin;
#if defined(CONFIG_FASTBOOT)
/* Use do_reset for fastboot's 'reboot' command */
-extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
/* Use do_fat_fsload for direct image fusing from sd card */
extern int do_fat_fsload (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
/* Use do_setenv and do_saveenv to permenantly save data */
int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
int do_setenv ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
/* Use do_bootm and do_go for fastboot's 'boot' command */
-int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
#if defined(CFG_FASTBOOT_ONENANDBSP)
diff --git a/common/cmd_help.c b/common/cmd_help.c
index 7a94f53f3f..6ff494d79b 100644
--- a/common/cmd_help.c
+++ b/common/cmd_help.c
@@ -2,39 +2,17 @@
* Copyright 2000-2009
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <command.h>
-extern cmd_tbl_t __u_boot_cmd_bdinfo;
-extern cmd_tbl_t __u_boot_cmd_showvar;
-
-int do_help(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+static int do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
-// return _do_help(&__u_boot_cmd_start,
-// &__u_boot_cmd_end - &__u_boot_cmd_start,
-// cmdtp, flag, argc, argv);
- return _do_help(&__u_boot_cmd_bdinfo,
- &__u_boot_cmd_showvar - &__u_boot_cmd_bdinfo + 1,
- cmdtp, flag, argc, argv);
+ cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd);
+ const int len = ll_entry_count(cmd_tbl_t, cmd);
+ return _do_help(start, len, cmdtp, flag, argc, argv);
}
U_BOOT_CMD(
@@ -47,7 +25,7 @@ U_BOOT_CMD(
);
/* This does not use the U_BOOT_CMD macro as ? can't be used in symbol names */
-cmd_tbl_t __u_boot_cmd_question_mark Struct_Section = {
+ll_entry_declare(cmd_tbl_t, question_mark, cmd) = {
"?", CONFIG_SYS_MAXARGS, 1, do_help,
"alias for 'help'",
#ifdef CONFIG_SYS_LONGHELP
diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c
index 9e123e3776..b99a1f9d45 100644
--- a/common/cmd_nvedit.c
+++ b/common/cmd_nvedit.c
@@ -1,27 +1,13 @@
/*
- * (C) Copyright 2000-2010
+ * (C) Copyright 2000-2013
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
-
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright 2011 Freescale Semiconductor, Inc.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
/*
@@ -45,45 +31,34 @@
#include <errno.h>
#include <malloc.h>
#include <watchdog.h>
-#include <serial.h>
#include <linux/stddef.h>
#include <asm/byteorder.h>
-#if defined(CONFIG_CMD_NET)
-#include <net.h>
-#endif
DECLARE_GLOBAL_DATA_PTR;
-#if !defined(CONFIG_ENV_IS_IN_EEPROM) && \
- !defined(CONFIG_ENV_IS_IN_FLASH) && \
- !defined(CONFIG_ENV_IS_IN_DATAFLASH) && \
- !defined(CONFIG_ENV_IS_IN_MG_DISK) && \
- !defined(CONFIG_ENV_IS_IN_MMC) && \
- !defined(CONFIG_ENV_IS_IN_NAND) && \
- !defined(CONFIG_ENV_IS_IN_NVRAM) && \
- !defined(CONFIG_ENV_IS_IN_ONENAND) && \
- !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \
- !defined(CONFIG_ENV_IS_IN_AUTO) && \
- !defined(CONFIG_ENV_IS_NOWHERE)
+#if !defined(CONFIG_ENV_IS_IN_EEPROM) && \
+ !defined(CONFIG_ENV_IS_IN_FLASH) && \
+ !defined(CONFIG_ENV_IS_IN_DATAFLASH) && \
+ !defined(CONFIG_ENV_IS_IN_MMC) && \
+ !defined(CONFIG_ENV_IS_IN_FAT) && \
+ !defined(CONFIG_ENV_IS_IN_NAND) && \
+ !defined(CONFIG_ENV_IS_IN_NVRAM) && \
+ !defined(CONFIG_ENV_IS_IN_ONENAND) && \
+ !defined(CONFIG_ENV_IS_IN_SPI_FLASH) && \
+ !defined(CONFIG_ENV_IS_IN_REMOTE) && \
+ !defined(CONFIG_ENV_IS_IN_UBI) && \
+ !defined(CONFIG_ENV_IS_IN_AUTO) && \
+ !defined(CONFIG_ENV_IS_NOWHERE)
# error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|ONENAND|\
-SPI_FLASH|MG_DISK|NVRAM|MMC|NOWHERE}
+SPI_FLASH|NVRAM|MMC|FAT|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE
#endif
-#define XMK_STR(x) #x
-#define MK_STR(x) XMK_STR(x)
-
/*
* Maximum expected input data size for import command
*/
#define MAX_ENV_SIZE (1 << 20) /* 1 MiB */
/*
- * Table with supported baudrates (defined in config_xyz.h)
- */
-static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
-#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0]))
-
-/*
* This variable is incremented on each do_env_set(), so it can
* be used via get_env_id() as an indication, if the environment
* has changed or not. So it is possible to reread an environment
@@ -92,35 +67,36 @@ static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE;
*/
static int env_id = 1;
-int get_env_id (void)
+int get_env_id(void)
{
return env_id;
}
+#ifndef CONFIG_SPL_BUILD
/*
* Command interface: print one or all environment variables
*
* Returns 0 in case of error, or length of printed string
*/
-static int env_print(char *name)
+static int env_print(char *name, int flag)
{
char *res = NULL;
- size_t len;
+ ssize_t len;
if (name) { /* print a single name */
ENTRY e, *ep;
e.key = name;
e.data = NULL;
- ep = hsearch (e, FIND);
+ hsearch_r(e, FIND, &ep, &env_htab, flag);
if (ep == NULL)
return 0;
- len = printf ("%s=%s\n", ep->key, ep->data);
+ len = printf("%s=%s\n", ep->key, ep->data);
return len;
}
/* print whole list */
- len = hexport('\n', &res, 0);
+ len = hexport_r(&env_htab, '\n', flag, &res, 0, 0, NULL);
if (len > 0) {
puts(res);
@@ -129,17 +105,26 @@ static int env_print(char *name)
}
/* should never happen */
+ printf("## Error: cannot export environment\n");
return 0;
}
-int do_env_print (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
{
int i;
int rcode = 0;
+ int env_flag = H_HIDE_DOT;
+
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'a') {
+ argc--;
+ argv++;
+ env_flag &= ~H_HIDE_DOT;
+ }
if (argc == 1) {
/* print all env vars */
- rcode = env_print(NULL);
+ rcode = env_print(NULL, env_flag);
if (!rcode)
return 1;
printf("\nEnvironment size: %d/%ld bytes\n",
@@ -148,8 +133,9 @@ int do_env_print (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
/* print selected env vars */
+ env_flag &= ~H_HIDE_DOT;
for (i = 1; i < argc; ++i) {
- int rc = env_print(argv[i]);
+ int rc = env_print(argv[i], env_flag);
if (!rc) {
printf("## Error: \"%s\" not defined\n", argv[i]);
++rcode;
@@ -159,142 +145,133 @@ int do_env_print (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
return rcode;
}
+#ifdef CONFIG_CMD_GREPENV
+static int do_env_grep(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
+{
+ char *res = NULL;
+ int len, grep_how, grep_what;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ grep_how = H_MATCH_SUBSTR; /* default: substring search */
+ grep_what = H_MATCH_BOTH; /* default: grep names and values */
+
+ while (argc > 1 && **(argv + 1) == '-') {
+ char *arg = *++argv;
+
+ --argc;
+ while (*++arg) {
+ switch (*arg) {
+#ifdef CONFIG_REGEX
+ case 'e': /* use regex matching */
+ grep_how = H_MATCH_REGEX;
+ break;
+#endif
+ case 'n': /* grep for name */
+ grep_what = H_MATCH_KEY;
+ break;
+ case 'v': /* grep for value */
+ grep_what = H_MATCH_DATA;
+ break;
+ case 'b': /* grep for both */
+ grep_what = H_MATCH_BOTH;
+ break;
+ case '-':
+ goto DONE;
+ default:
+ return CMD_RET_USAGE;
+ }
+ }
+ }
+
+DONE:
+ len = hexport_r(&env_htab, '\n',
+ flag | grep_what | grep_how,
+ &res, 0, argc, argv);
+
+ if (len > 0) {
+ puts(res);
+ free(res);
+ }
+
+ if (len < 2)
+ return 1;
+
+ return 0;
+}
+#endif
+#endif /* CONFIG_SPL_BUILD */
+
/*
* Set a new environment variable,
* or replace or delete an existing one.
*/
-
-int _do_env_set (int flag, int argc, char * const argv[])
+static int _do_env_set(int flag, int argc, char * const argv[])
{
- bd_t *bd = gd->bd;
int i, len;
- int console = -1;
char *name, *value, *s;
ENTRY e, *ep;
+ int env_flag = H_INTERACTIVE;
+ debug("Initial value for argc=%d\n", argc);
+ while (argc > 1 && **(argv + 1) == '-') {
+ char *arg = *++argv;
+
+ --argc;
+ while (*++arg) {
+ switch (*arg) {
+ case 'f': /* force */
+ env_flag |= H_FORCE;
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+ }
+ }
+ debug("Final value for argc=%d\n", argc);
name = argv[1];
+ value = argv[2];
if (strchr(name, '=')) {
- printf ("## Error: illegal character '=' in variable name \"%s\"\n", name);
+ printf("## Error: illegal character '='"
+ "in variable name \"%s\"\n", name);
return 1;
}
env_id++;
- /*
- * search if variable with this name already exists
- */
- e.key = name;
- e.data = NULL;
- ep = hsearch (e, FIND);
-
- /* 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 (console != -1) {
- if (argc < 3) { /* Cannot delete it! */
- printf("Can't delete \"%s\"\n", name);
- return 1;
- }
-
-#ifdef CONFIG_CONSOLE_MUX
- i = iomux_doenv(console, argv[2]);
- if (i)
- return i;
-#else
- /* Try assigning specified device */
- if (console_assign (console, argv[2]) < 0)
- return 1;
-
-#ifdef CONFIG_SERIAL_MULTI
- if (serial_assign (argv[2]) < 0)
- return 1;
-#endif
-#endif /* CONFIG_CONSOLE_MUX */
- }
-
- /*
- * Some variables like "ethaddr" and "serial#" can be set only
- * once and cannot be deleted; also, "ver" is readonly.
- */
- if (ep) { /* variable exists */
-#ifndef CONFIG_ENV_OVERWRITE
- if ((strcmp (name, "serial#") == 0) ||
- ((strcmp (name, "ethaddr") == 0)
-#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR)
- && (strcmp (ep->data,MK_STR(CONFIG_ETHADDR)) != 0)
-#endif /* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */
- ) ) {
- printf ("Can't overwrite \"%s\"\n", name);
- return 1;
- }
-#endif
- /*
- * Switch to new baudrate if new baudrate is supported
- */
- if (strcmp(name,"baudrate") == 0) {
- int baudrate = simple_strtoul(argv[2], NULL, 10);
- int i;
- for (i=0; i<N_BAUDRATES; ++i) {
- if (baudrate == baudrate_table[i])
- break;
- }
- if (i == N_BAUDRATES) {
- printf ("## Baudrate %d bps not supported\n",
- baudrate);
- return 1;
- }
- printf ("## Switch baudrate to %d bps and press ENTER ...\n",
- baudrate);
- udelay(50000);
- gd->baudrate = baudrate;
-#if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2)
- gd->bd->bi_baudrate = baudrate;
-#endif
-
- serial_setbrg ();
- udelay(50000);
- for (;;) {
- if (getc() == '\r')
- break;
- }
- }
- }
/* Delete only ? */
- if ((argc < 3) || argv[2] == NULL) {
- int rc = hdelete(name);
+ if (argc < 3 || argv[2] == NULL) {
+ int rc = hdelete_r(name, &env_htab, env_flag);
return !rc;
}
/*
* Insert / replace new value
*/
- for (i=2,len=0; i<argc; ++i) {
+ for (i = 2, len = 0; i < argc; ++i)
len += strlen(argv[i]) + 1;
- }
- if ((value = malloc(len)) == NULL) {
+
+ value = malloc(len);
+ if (value == NULL) {
printf("## Can't malloc %d bytes\n", len);
return 1;
}
- for (i=2,s=value; i<argc; ++i) {
+ for (i = 2, s = value; i < argc; ++i) {
char *v = argv[i];
while ((*s++ = *v++) != '\0')
;
- *(s-1) = ' ';
+ *(s - 1) = ' ';
}
if (s != value)
*--s = '\0';
- e.key = name;
- e.data = value;
- ep = hsearch(e, ENTER);
+ e.key = name;
+ e.data = value;
+ hsearch_r(e, ENTER, &ep, &env_htab, env_flag);
free(value);
if (!ep) {
printf("## Error inserting \"%s\" variable, errno=%d\n",
@@ -302,111 +279,128 @@ int _do_env_set (int flag, int argc, char * const argv[])
return 1;
}
- /*
- * Some variables should be updated when the corresponding
- * entry in the environment is changed
- */
-
- if (strcmp(name,"ipaddr") == 0) {
- char *s = argv[2]; /* always use only one arg */
- char *e;
- unsigned long addr;
- bd->bi_ip_addr = 0;
- for (addr=0, i=0; i<4; ++i) {
- ulong val = s ? simple_strtoul(s, &e, 10) : 0;
- addr <<= 8;
- addr |= (val & 0xFF);
- if (s) s = (*e) ? e+1 : e;
- }
- bd->bi_ip_addr = htonl(addr);
- return 0;
- } else if (strcmp(argv[1],"loadaddr") == 0) {
- load_addr = simple_strtoul(argv[2], NULL, 16);
- return 0;
- }
-#if defined(CONFIG_CMD_NET)
- else if (strcmp(argv[1],"bootfile") == 0) {
- copy_filename (BootFile, argv[2], sizeof(BootFile));
- return 0;
- }
-#endif
return 0;
}
-int setenv (char *varname, char *varvalue)
+int setenv(const char *varname, const char *varvalue)
{
- char * const argv[4] = { "setenv", varname, varvalue, NULL };
- if ((varvalue == NULL) || (varvalue[0] == '\0'))
- return _do_env_set(0, 2, argv);
+ const char * const argv[4] = { "setenv", varname, varvalue, NULL };
+
+ /* before import into hashtable */
+ if (!(gd->flags & GD_FLG_ENV_READY))
+ return 1;
+
+ if (varvalue == NULL || varvalue[0] == '\0')
+ return _do_env_set(0, 2, (char * const *)argv);
else
- return _do_env_set(0, 3, argv);
+ return _do_env_set(0, 3, (char * const *)argv);
}
-int do_env_set (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+/**
+ * Set an environment variable to an integer value
+ *
+ * @param varname Environment variable to set
+ * @param value Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+int setenv_ulong(const char *varname, ulong value)
{
- if (argc < 2)
- return cmd_usage(cmdtp);
+ /* TODO: this should be unsigned */
+ char *str = simple_itoa(value);
- return _do_env_set(flag, argc, argv);
+ return setenv(varname, str);
}
-/*
+/**
* Set an environment variable to an value in hex
*
- * @param varname Environment variable to set
- * @param value Value to set it to
+ * @param varname Environment variable to set
+ * @param value Value to set it to
* @return 0 if ok, 1 on error
*/
int setenv_hex(const char *varname, ulong value)
{
- char str[17];
+ char str[17];
+
+ sprintf(str, "%lx", value);
+ return setenv(varname, str);
+}
+
+ulong getenv_hex(const char *varname, ulong default_val)
+{
+ const char *s;
+ ulong value;
+ char *endp;
+
+ s = getenv(varname);
+ if (s)
+ value = simple_strtoul(s, &endp, 16);
+ if (!s || endp == s)
+ return default_val;
+
+ return value;
+}
+
+#ifndef CONFIG_SPL_BUILD
+int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ if (argc < 2)
+ return CMD_RET_USAGE;
- sprintf(str, "%lx", value);
- return setenv(varname, str);
+ return _do_env_set(flag, argc, argv);
}
/*
* Prompt for environment variable
*/
#if defined(CONFIG_CMD_ASKENV)
-int do_env_ask ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_env_ask(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
- extern char console_buffer[CONFIG_SYS_CBSIZE];
char message[CONFIG_SYS_CBSIZE];
- int size = CONFIG_SYS_CBSIZE - 1;
- int i, len, pos;
+ int i, len, pos, size;
char *local_args[4];
+ char *endptr;
local_args[0] = argv[0];
local_args[1] = argv[1];
local_args[2] = NULL;
local_args[3] = NULL;
- /* Check the syntax */
- switch (argc) {
- case 1:
- return cmd_usage(cmdtp);
-
- case 2: /* env_ask envname */
- sprintf(message, "Please enter '%s':", argv[1]);
- break;
+ /*
+ * Check the syntax:
+ *
+ * env_ask envname [message1 ...] [size]
+ */
+ if (argc == 1)
+ return CMD_RET_USAGE;
- case 3: /* env_ask envname size */
- sprintf(message, "Please enter '%s':", argv[1]);
- size = simple_strtoul(argv[2], NULL, 10);
- break;
+ /*
+ * We test the last argument if it can be converted
+ * into a decimal number. If yes, we assume it's
+ * the size. Otherwise we echo it as part of the
+ * message.
+ */
+ i = simple_strtoul(argv[argc - 1], &endptr, 10);
+ if (*endptr != '\0') { /* no size */
+ size = CONFIG_SYS_CBSIZE - 1;
+ } else { /* size given */
+ size = i;
+ --argc;
+ }
- default: /* env_ask envname message1 ... messagen size */
- for (i=2,pos=0; i < argc - 1; i++) {
- if (pos) {
+ if (argc <= 2) {
+ sprintf(message, "Please enter '%s': ", argv[1]);
+ } else {
+ /* env_ask envname message1 ... messagen [size] */
+ for (i = 2, pos = 0; i < argc; i++) {
+ if (pos)
message[pos++] = ' ';
- }
- strcpy(message+pos, argv[i]);
+
+ strcpy(message + pos, argv[i]);
pos += strlen(argv[i]);
}
+ message[pos++] = ' ';
message[pos] = '\0';
- size = simple_strtoul(argv[argc - 1], NULL, 10);
- break;
}
if (size >= CONFIG_SYS_CBSIZE)
@@ -432,53 +426,201 @@ int do_env_ask ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
}
#endif
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+static int print_static_binding(const char *var_name, const char *callback_name)
+{
+ printf("\t%-20s %-20s\n", var_name, callback_name);
+
+ return 0;
+}
+
+static int print_active_callback(ENTRY *entry)
+{
+ struct env_clbk_tbl *clbkp;
+ int i;
+ int num_callbacks;
+
+ if (entry->callback == NULL)
+ return 0;
+
+ /* look up the callback in the linker-list */
+ num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+ for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+ i < num_callbacks;
+ i++, clbkp++) {
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ if (entry->callback == clbkp->callback + gd->reloc_off)
+#else
+ if (entry->callback == clbkp->callback)
+#endif
+ break;
+ }
+
+ if (i == num_callbacks)
+ /* this should probably never happen, but just in case... */
+ printf("\t%-20s %p\n", entry->key, entry->callback);
+ else
+ printf("\t%-20s %-20s\n", entry->key, clbkp->name);
+
+ return 0;
+}
+
+/*
+ * Print the callbacks available and what they are bound to
+ */
+int do_env_callback(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ struct env_clbk_tbl *clbkp;
+ int i;
+ int num_callbacks;
+
+ /* Print the available callbacks */
+ puts("Available callbacks:\n");
+ puts("\tCallback Name\n");
+ puts("\t-------------\n");
+ num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+ for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+ i < num_callbacks;
+ i++, clbkp++)
+ printf("\t%s\n", clbkp->name);
+ puts("\n");
+
+ /* Print the static bindings that may exist */
+ puts("Static callback bindings:\n");
+ printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+ printf("\t%-20s %-20s\n", "-------------", "-------------");
+ env_attr_walk(ENV_CALLBACK_LIST_STATIC, print_static_binding);
+ puts("\n");
+
+ /* walk through each variable and print the callback if it has one */
+ puts("Active callback bindings:\n");
+ printf("\t%-20s %-20s\n", "Variable Name", "Callback Name");
+ printf("\t%-20s %-20s\n", "-------------", "-------------");
+ hwalk_r(&env_htab, print_active_callback);
+ return 0;
+}
+#endif
+
+#if defined(CONFIG_CMD_ENV_FLAGS)
+static int print_static_flags(const char *var_name, const char *flags)
+{
+ enum env_flags_vartype type = env_flags_parse_vartype(flags);
+ enum env_flags_varaccess access = env_flags_parse_varaccess(flags);
+
+ printf("\t%-20s %-20s %-20s\n", var_name,
+ env_flags_get_vartype_name(type),
+ env_flags_get_varaccess_name(access));
+
+ return 0;
+}
+
+static int print_active_flags(ENTRY *entry)
+{
+ enum env_flags_vartype type;
+ enum env_flags_varaccess access;
+
+ if (entry->flags == 0)
+ return 0;
+
+ type = (enum env_flags_vartype)
+ (entry->flags & ENV_FLAGS_VARTYPE_BIN_MASK);
+ access = env_flags_parse_varaccess_from_binflags(entry->flags);
+ printf("\t%-20s %-20s %-20s\n", entry->key,
+ env_flags_get_vartype_name(type),
+ env_flags_get_varaccess_name(access));
+
+ return 0;
+}
+
+/*
+ * Print the flags available and what variables have flags
+ */
+int do_env_flags(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ /* Print the available variable types */
+ printf("Available variable type flags (position %d):\n",
+ ENV_FLAGS_VARTYPE_LOC);
+ puts("\tFlag\tVariable Type Name\n");
+ puts("\t----\t------------------\n");
+ env_flags_print_vartypes();
+ puts("\n");
+
+ /* Print the available variable access types */
+ printf("Available variable access flags (position %d):\n",
+ ENV_FLAGS_VARACCESS_LOC);
+ puts("\tFlag\tVariable Access Name\n");
+ puts("\t----\t--------------------\n");
+ env_flags_print_varaccess();
+ puts("\n");
+
+ /* Print the static flags that may exist */
+ puts("Static flags:\n");
+ printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+ "Variable Access");
+ printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+ "---------------");
+ env_attr_walk(ENV_FLAGS_LIST_STATIC, print_static_flags);
+ puts("\n");
+
+ /* walk through each variable and print the flags if non-default */
+ puts("Active flags:\n");
+ printf("\t%-20s %-20s %-20s\n", "Variable Name", "Variable Type",
+ "Variable Access");
+ printf("\t%-20s %-20s %-20s\n", "-------------", "-------------",
+ "---------------");
+ hwalk_r(&env_htab, print_active_flags);
+ return 0;
+}
+#endif
+
/*
* Interactively edit an environment variable
*/
#if defined(CONFIG_CMD_EDITENV)
-int do_env_edit(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_env_edit(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
{
char buffer[CONFIG_SYS_CBSIZE];
char *init_val;
- int len;
if (argc < 2)
- return cmd_usage(cmdtp);
+ return CMD_RET_USAGE;
/* Set read buffer to initial value or empty sting */
init_val = getenv(argv[1]);
if (init_val)
- len = sprintf(buffer, "%s", init_val);
+ sprintf(buffer, "%s", init_val);
else
buffer[0] = '\0';
- readline_into_buffer("edit: ", buffer);
+ if (readline_into_buffer("edit: ", buffer, 0) < 0)
+ return 1;
return setenv(argv[1], buffer);
}
#endif /* CONFIG_CMD_EDITENV */
+#endif /* CONFIG_SPL_BUILD */
/*
* Look up variable from environment,
* return address of storage for that variable,
* or NULL if not found
*/
-char *getenv (char *name)
+char *getenv(const char *name)
{
- if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
+ if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
ENTRY e, *ep;
WATCHDOG_RESET();
- e.key = name;
- e.data = NULL;
- ep = hsearch (e, FIND);
+ e.key = name;
+ e.data = NULL;
+ hsearch_r(e, FIND, &ep, &env_htab, 0);
- return (ep ? ep->data : NULL);
+ return ep ? ep->data : NULL;
}
/* restricted capabilities before import */
-
if (getenv_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
return (char *)(gd->env_buf);
@@ -488,45 +630,69 @@ char *getenv (char *name)
/*
* Look up variable from environment for restricted C runtime env.
*/
-int getenv_f (char *name, char *buf, unsigned len)
+int getenv_f(const char *name, char *buf, unsigned len)
{
int i, nxt;
- for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
+ for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
int val, n;
- for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) {
- if (nxt >= CONFIG_ENV_SIZE) {
- return (-1);
- }
+ for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) {
+ if (nxt >= CONFIG_ENV_SIZE)
+ return -1;
}
- if ((val=envmatch((uchar *)name, i)) < 0)
+
+ val = envmatch((uchar *)name, i);
+ if (val < 0)
continue;
/* found; copy out */
- for (n=0; n<len; ++n, ++buf) {
- if ((*buf = env_get_char(val++)) == '\0')
+ for (n = 0; n < len; ++n, ++buf) {
+ *buf = env_get_char(val++);
+ if (*buf == '\0')
return n;
}
if (n)
*--buf = '\0';
- printf("env_buf too small [%d]\n", len);
+ printf("env_buf [%d bytes] too small for value of \"%s\"\n",
+ len, name);
return n;
}
- return (-1);
+
+ return -1;
}
-#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
-int do_env_save (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+/**
+ * Decode the integer value of an environment variable and return it.
+ *
+ * @param name Name of environemnt variable
+ * @param base Number base to use (normally 10, or 16 for hex)
+ * @param default_val Default value to return if the variable is not
+ * found
+ * @return the decoded value, or default_val if not found
+ */
+ulong getenv_ulong(const char *name, int base, ulong default_val)
{
- extern char * env_name_spec;
+ /*
+ * We can use getenv() here, even before relocation, since the
+ * environment variable value is an integer and thus short.
+ */
+ const char *str = getenv(name);
- printf ("Saving Environment to %s...\n", env_name_spec);
+ return str ? simple_strtoul(str, NULL, base) : default_val;
+}
- return (saveenv() ? 1 : 0);
+#ifndef CONFIG_SPL_BUILD
+#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
+static int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ printf("Saving Environment to %s...\n", env_name_spec);
+
+ return saveenv() ? 1 : 0;
}
U_BOOT_CMD(
@@ -534,8 +700,8 @@ U_BOOT_CMD(
"save environment variables to persistent storage",
""
);
-
#endif
+#endif /* CONFIG_SPL_BUILD */
/*
@@ -543,37 +709,99 @@ U_BOOT_CMD(
*
* s1 is either a simple 'name', or a 'name=value' pair.
* i2 is the environment index for a 'name2=value2' pair.
- * If the names match, return the index for the value2, else NULL.
+ * If the names match, return the index for the value2, else -1.
*/
-
-int envmatch (uchar *s1, int i2)
+int envmatch(uchar *s1, int i2)
{
+ if (s1 == NULL)
+ return -1;
while (*s1 == env_get_char(i2++))
if (*s1++ == '=')
- return(i2);
+ return i2;
+
if (*s1 == '\0' && env_get_char(i2-1) == '=')
- return(i2);
- return(-1);
+ return i2;
+
+ return -1;
}
-static int do_env_default(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+#ifndef CONFIG_SPL_BUILD
+static int do_env_default(cmd_tbl_t *cmdtp, int __flag,
+ int argc, char * const argv[])
{
- if ((argc != 2) || (strcmp(argv[1], "-f") != 0)) {
- return cmd_usage(cmdtp);
+ int all = 0, flag = 0;
+
+ debug("Initial value for argc=%d\n", argc);
+ while (--argc > 0 && **++argv == '-') {
+ char *arg = *argv;
+
+ while (*++arg) {
+ switch (*arg) {
+ case 'a': /* default all */
+ all = 1;
+ break;
+ case 'f': /* force */
+ flag |= H_FORCE;
+ break;
+ default:
+ return cmd_usage(cmdtp);
+ }
+ }
}
- set_default_env("## Resetting to default environment\n");
- return 0;
+ debug("Final value for argc=%d\n", argc);
+ if (all && (argc == 0)) {
+ /* Reset the whole environment */
+ set_default_env("## Resetting to default environment\n");
+ return 0;
+ }
+ if (!all && (argc > 0)) {
+ /* Reset individual variables */
+ set_default_vars(argc, argv);
+ return 0;
+ }
+
+ return cmd_usage(cmdtp);
}
-static int do_env_delete(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+static int do_env_delete(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
{
- printf("Not implemented yet\n");
- return 0;
+ int env_flag = H_INTERACTIVE;
+ int ret = 0;
+
+ debug("Initial value for argc=%d\n", argc);
+ while (argc > 1 && **(argv + 1) == '-') {
+ char *arg = *++argv;
+
+ --argc;
+ while (*++arg) {
+ switch (*arg) {
+ case 'f': /* force */
+ env_flag |= H_FORCE;
+ break;
+ default:
+ return CMD_RET_USAGE;
+ }
+ }
+ }
+ debug("Final value for argc=%d\n", argc);
+
+ env_id++;
+
+ while (--argc > 0) {
+ char *name = *++argv;
+
+ if (!hdelete_r(name, &env_htab, env_flag))
+ ret = 1;
+ }
+
+ return ret;
}
+#ifdef CONFIG_CMD_EXPORTENV
/*
- * env export [-t | -b | -c] addr [size]
+ * env export [-t | -b | -c] [-s size] addr [var ...]
* -t: export as text format; if size is given, data will be
* padded with '\0' bytes; if not, one terminating '\0'
* will be added (which is included in the "filesize"
@@ -583,8 +811,12 @@ static int do_env_delete(cmd_tbl_t * cmdtp, int flag, int argc, char * const arg
* '\0', list end marked by double "\0\0")
* -c: export as checksum protected environment format as
* used for example by "saveenv" command
+ * -s size:
+ * size of output buffer
* addr: memory address where environment gets stored
- * size: size of output buffer
+ * var... List of variable names that get included into the
+ * export. Without arguments, the whole environment gets
+ * exported.
*
* With "-c" and size is NOT given, then the export command will
* format the data as currently used for the persistent storage,
@@ -613,11 +845,12 @@ static int do_env_delete(cmd_tbl_t * cmdtp, int flag, int argc, char * const arg
*
* => env import -d -t ${backup_addr}
*/
-static int do_env_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_env_export(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
{
char buf[32];
char *addr, *cmd, *res;
- size_t size;
+ size_t size = 0;
ssize_t len;
env_t *envp;
char sep = '\n';
@@ -641,38 +874,43 @@ static int do_env_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
sep = '\0';
chk = 1;
break;
+ case 's': /* size given */
+ if (--argc <= 0)
+ return cmd_usage(cmdtp);
+ size = simple_strtoul(*++argv, NULL, 16);
+ goto NXTARG;
case 't': /* text format */
if (fmt++)
goto sep_err;
sep = '\n';
break;
default:
- return cmd_usage(cmdtp);
+ return CMD_RET_USAGE;
}
}
+NXTARG: ;
}
- if (argc < 1) {
- return cmd_usage(cmdtp);
- }
+ if (argc < 1)
+ return CMD_RET_USAGE;
addr = (char *)simple_strtoul(argv[0], NULL, 16);
- if (argc == 2) {
- size = simple_strtoul(argv[1], NULL, 16);
+ if (size)
memset(addr, '\0', size);
- } else {
- size = 0;
- }
+
+ argc--;
+ argv++;
if (sep) { /* export as text file */
- len = hexport(sep, &addr, size);
+ len = hexport_r(&env_htab, sep,
+ H_MATCH_KEY | H_MATCH_IDENT,
+ &addr, size, argc, argv);
if (len < 0) {
- error("Cannot export environment: errno = %d\n",
- errno);
+ error("Cannot export environment: errno = %d\n", errno);
return 1;
}
- sprintf(buf, "%zX", len);
+ sprintf(buf, "%zX", (size_t)len);
setenv("filesize", buf);
return 0;
@@ -685,30 +923,31 @@ static int do_env_export(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv
else /* export as raw binary data */
res = addr;
- len = hexport('\0', &res, ENV_SIZE);
+ len = hexport_r(&env_htab, '\0',
+ H_MATCH_KEY | H_MATCH_IDENT,
+ &res, ENV_SIZE, argc, argv);
if (len < 0) {
- error("Cannot export environment: errno = %d\n",
- errno);
+ error("Cannot export environment: errno = %d\n", errno);
return 1;
}
if (chk) {
- envp->crc = crc32(0, envp->data, ENV_SIZE);
+ envp->crc = crc32(0, envp->data, ENV_SIZE);
#ifdef CONFIG_ENV_ADDR_REDUND
envp->flags = ACTIVE_FLAG;
#endif
}
- sprintf(buf, "%zX", len + offsetof(env_t,data));
- setenv("filesize", buf);
+ setenv_hex("filesize", len + offsetof(env_t, data));
return 0;
sep_err:
- printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n",
- cmd);
+ printf("## %s: only one of \"-b\", \"-c\" or \"-t\" allowed\n", cmd);
return 1;
}
+#endif
+#ifdef CONFIG_CMD_IMPORTENV
/*
* env import [-d] [-t | -b | -c] addr [size]
* -d: delete existing environment before importing;
@@ -721,7 +960,8 @@ sep_err:
* size: length of input data; if missing, proper '\0'
* termination is mandatory
*/
-static int do_env_import(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
+static int do_env_import(cmd_tbl_t *cmdtp, int flag,
+ int argc, char * const argv[])
{
char *cmd, *addr;
char sep = '\n';
@@ -756,14 +996,13 @@ static int do_env_import(cmd_tbl_t * cmdtp, int flag, int argc, char * const arg
del = 1;
break;
default:
- return cmd_usage(cmdtp);
+ return CMD_RET_USAGE;
}
}
}
- if (argc < 1) {
- return cmd_usage(cmdtp);
- }
+ if (argc < 1)
+ return CMD_RET_USAGE;
if (!fmt)
printf("## Warning: defaulting to text format\n");
@@ -787,8 +1026,8 @@ static int do_env_import(cmd_tbl_t * cmdtp, int flag, int argc, char * const arg
printf("## Warning: Input data exceeds %d bytes"
" - truncated\n", MAX_ENV_SIZE);
}
- ++size;
- printf("## Info: input data size = %zd = 0x%zX\n", size, size);
+ size += 2;
+ printf("## Info: input data size = %zu = 0x%zX\n", size, size);
}
if (chk) {
@@ -805,7 +1044,8 @@ static int do_env_import(cmd_tbl_t * cmdtp, int flag, int argc, char * const arg
addr = (char *)ep->data;
}
- if (himport(addr, size, sep, del ? 0 : H_NOCLEAR) == 0) {
+ if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR,
+ 0, NULL) == 0) {
error("Environment import failed: errno = %d\n", errno);
return 1;
}
@@ -818,9 +1058,6 @@ sep_err:
cmd);
return 1;
}
-
-#if defined(CONFIG_CMD_RUN)
-extern int do_run (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
#endif
/*
@@ -831,12 +1068,25 @@ static cmd_tbl_t cmd_env_sub[] = {
U_BOOT_CMD_MKENT(ask, CONFIG_SYS_MAXARGS, 1, do_env_ask, "", ""),
#endif
U_BOOT_CMD_MKENT(default, 1, 0, do_env_default, "", ""),
- U_BOOT_CMD_MKENT(delete, 2, 0, do_env_delete, "", ""),
+ U_BOOT_CMD_MKENT(delete, CONFIG_SYS_MAXARGS, 0, do_env_delete, "", ""),
#if defined(CONFIG_CMD_EDITENV)
U_BOOT_CMD_MKENT(edit, 2, 0, do_env_edit, "", ""),
#endif
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+ U_BOOT_CMD_MKENT(callbacks, 1, 0, do_env_callback, "", ""),
+#endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+ U_BOOT_CMD_MKENT(flags, 1, 0, do_env_flags, "", ""),
+#endif
+#if defined(CONFIG_CMD_EXPORTENV)
U_BOOT_CMD_MKENT(export, 4, 0, do_env_export, "", ""),
+#endif
+#if defined(CONFIG_CMD_GREPENV)
+ U_BOOT_CMD_MKENT(grep, CONFIG_SYS_MAXARGS, 1, do_env_grep, "", ""),
+#endif
+#if defined(CONFIG_CMD_IMPORTENV)
U_BOOT_CMD_MKENT(import, 5, 0, do_env_import, "", ""),
+#endif
U_BOOT_CMD_MKENT(print, CONFIG_SYS_MAXARGS, 1, do_env_print, "", ""),
#if defined(CONFIG_CMD_RUN)
U_BOOT_CMD_MKENT(run, CONFIG_SYS_MAXARGS, 1, do_run, "", ""),
@@ -854,12 +1104,12 @@ void env_reloc(void)
}
#endif
-static int do_env (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
cmd_tbl_t *cp;
if (argc < 2)
- return cmd_usage(cmdtp);
+ return CMD_RET_USAGE;
/* drop initial "env" arg */
argc--;
@@ -870,27 +1120,52 @@ static int do_env (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
if (cp)
return cp->cmd(cmdtp, flag, argc, argv);
- return cmd_usage(cmdtp);
+ return CMD_RET_USAGE;
}
-U_BOOT_CMD(
- env, CONFIG_SYS_MAXARGS, 1, do_env,
- "environment handling commands",
+#ifdef CONFIG_SYS_LONGHELP
+static char env_help_text[] =
#if defined(CONFIG_CMD_ASKENV)
"ask name [message] [size] - ask for environment variable\nenv "
#endif
- "default -f - reset default environment\n"
+#if defined(CONFIG_CMD_ENV_CALLBACK)
+ "callbacks - print callbacks and their associated variables\nenv "
+#endif
+ "default [-f] -a - [forcibly] reset default environment\n"
+ "env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"
+ "env delete [-f] var [...] - [forcibly] delete variable(s)\n"
#if defined(CONFIG_CMD_EDITENV)
"env edit name - edit environment variable\n"
#endif
- "env export [-t | -b | -c] addr [size] - export environmnt\n"
- "env import [-d] [-t | -b | -c] addr [size] - import environmnt\n"
- "env print [name ...] - print environment\n"
+#if defined(CONFIG_CMD_EXPORTENV)
+ "env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n"
+#endif
+#if defined(CONFIG_CMD_ENV_FLAGS)
+ "env flags - print variables that have non-default flags\n"
+#endif
+#if defined(CONFIG_CMD_GREPENV)
+#ifdef CONFIG_REGEX
+ "env grep [-e] [-n | -v | -b] string [...] - search environment\n"
+#else
+ "env grep [-n | -v | -b] string [...] - search environment\n"
+#endif
+#endif
+#if defined(CONFIG_CMD_IMPORTENV)
+ "env import [-d] [-t | -b | -c] addr [size] - import environment\n"
+#endif
+ "env print [-a | name ...] - print environment\n"
#if defined(CONFIG_CMD_RUN)
"env run var [...] - run commands in an environment variable\n"
#endif
+#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
"env save - save environment\n"
- "env set [-f] name [arg ...]\n"
+#endif
+ "env set [-f] name [arg ...]\n";
+#endif
+
+U_BOOT_CMD(
+ env, CONFIG_SYS_MAXARGS, 1, do_env,
+ "environment handling commands", env_help_text
);
/*
@@ -898,29 +1173,51 @@ U_BOOT_CMD(
*/
#if defined(CONFIG_CMD_EDITENV)
-U_BOOT_CMD(
+U_BOOT_CMD_COMPLETE(
editenv, 2, 0, do_env_edit,
"edit environment variable",
"name\n"
- " - edit environment variable 'name'"
+ " - edit environment variable 'name'",
+ var_complete
);
#endif
-U_BOOT_CMD(
+U_BOOT_CMD_COMPLETE(
printenv, CONFIG_SYS_MAXARGS, 1, do_env_print,
"print environment variables",
- "\n - print values of all environment variables\n"
+ "[-a]\n - print [all] values of all environment variables\n"
"printenv name ...\n"
- " - print value of environment variable 'name'"
+ " - print value of environment variable 'name'",
+ var_complete
);
-U_BOOT_CMD(
+#ifdef CONFIG_CMD_GREPENV
+U_BOOT_CMD_COMPLETE(
+ grepenv, CONFIG_SYS_MAXARGS, 0, do_env_grep,
+ "search environment variables",
+#ifdef CONFIG_REGEX
+ "[-e] [-n | -v | -b] string ...\n"
+#else
+ "[-n | -v | -b] string ...\n"
+#endif
+ " - list environment name=value pairs matching 'string'\n"
+#ifdef CONFIG_REGEX
+ " \"-e\": enable regular expressions;\n"
+#endif
+ " \"-n\": search variable names; \"-v\": search values;\n"
+ " \"-b\": search both names and values (default)",
+ var_complete
+);
+#endif
+
+U_BOOT_CMD_COMPLETE(
setenv, CONFIG_SYS_MAXARGS, 0, do_env_set,
"set environment variables",
- "name value ...\n"
- " - set environment variable 'name' to 'value ...'\n"
- "setenv name\n"
- " - delete environment variable 'name'"
+ "[-f] name value ...\n"
+ " - [forcibly] set environment variable 'name' to 'value ...'\n"
+ "setenv [-f] name\n"
+ " - [forcibly] delete environment variable 'name'",
+ var_complete
);
#if defined(CONFIG_CMD_ASKENV)
@@ -929,22 +1226,17 @@ U_BOOT_CMD(
askenv, CONFIG_SYS_MAXARGS, 1, do_env_ask,
"get environment variables from stdin",
"name [message] [size]\n"
- " - get environment variable 'name' from stdin (max 'size' chars)\n"
- "askenv name\n"
- " - get environment variable 'name' from stdin\n"
- "askenv name size\n"
- " - get environment variable 'name' from stdin (max 'size' chars)\n"
- "askenv name [message] size\n"
- " - display 'message' string and get environment variable 'name'"
- "from stdin (max 'size' chars)"
+ " - get environment variable 'name' from stdin (max 'size' chars)"
);
#endif
#if defined(CONFIG_CMD_RUN)
-U_BOOT_CMD(
+U_BOOT_CMD_COMPLETE(
run, CONFIG_SYS_MAXARGS, 1, do_run,
"run commands in an environment variable",
"var [...]\n"
- " - run the commands in the environment variable(s) 'var'"
+ " - run the commands in the environment variable(s) 'var'",
+ var_complete
);
#endif
+#endif /* CONFIG_SPL_BUILD */
diff --git a/common/command.c b/common/command.c
index d1a030c229..625571dd4d 100644
--- a/common/command.c
+++ b/common/command.c
@@ -2,23 +2,7 @@
* (C) Copyright 2000-2009
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
/*
@@ -27,10 +11,7 @@
#include <common.h>
#include <command.h>
-
-#if defined(CONFIG_S5P6450)
-DECLARE_GLOBAL_DATA_PTR;
-#endif
+#include <linux/ctype.h>
/*
* Use puts() instead of printf() to avoid printf buffer overflow
@@ -138,18 +119,14 @@ cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
return NULL; /* not found or ambiguous command */
}
-extern cmd_tbl_t __u_boot_cmd_bdinfo;
-extern cmd_tbl_t __u_boot_cmd_showvar;
-
cmd_tbl_t *find_cmd (const char *cmd)
{
- //int len = &__u_boot_cmd_end - &__u_boot_cmd_start;
- int len = &__u_boot_cmd_showvar - &__u_boot_cmd_bdinfo + 1;
- //return find_cmd_tbl(cmd, &__u_boot_cmd_start, len);
- return find_cmd_tbl(cmd, &__u_boot_cmd_bdinfo, len);
+ cmd_tbl_t *start = ll_entry_start(cmd_tbl_t, cmd);
+ const int len = ll_entry_count(cmd_tbl_t, cmd);
+ return find_cmd_tbl(cmd, start, len);
}
-int cmd_usage(cmd_tbl_t *cmdtp)
+int cmd_usage(const cmd_tbl_t *cmdtp)
{
printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
@@ -171,50 +148,27 @@ int cmd_usage(cmd_tbl_t *cmdtp)
int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
{
-#if 0 /* need to reimplement */
static char tmp_buf[512];
int space;
- space = last_char == '\0' || last_char == ' ' || last_char == '\t';
+ space = last_char == '\0' || isblank(last_char);
if (space && argc == 1)
return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
if (!space && argc == 2)
return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
-#endif
- return 0;
-}
-static void install_auto_complete_handler(const char *cmd,
- int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]))
-{
- cmd_tbl_t *cmdtp;
-
- cmdtp = find_cmd(cmd);
- if (cmdtp == NULL)
- return;
-
- cmdtp->complete = complete;
-}
-
-void install_auto_complete(void)
-{
-#if defined(CONFIG_CMD_EDITENV)
- install_auto_complete_handler("editenv", var_complete);
-#endif
- install_auto_complete_handler("printenv", var_complete);
- install_auto_complete_handler("setenv", var_complete);
-#if defined(CONFIG_CMD_RUN)
- install_auto_complete_handler("run", var_complete);
-#endif
+ return 0;
}
/*************************************************************************************/
static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
{
- cmd_tbl_t *cmdtp;
+ cmd_tbl_t *cmdtp = ll_entry_start(cmd_tbl_t, cmd);
+ const int count = ll_entry_count(cmd_tbl_t, cmd);
+ const cmd_tbl_t *cmdend = cmdtp + count;
const char *p;
int len, clen;
int n_found = 0;
@@ -228,19 +182,19 @@ static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv
if (argc == 0) {
/* output full list of commands */
- for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
+ for (; cmdtp != cmdend; cmdtp++) {
if (n_found >= maxv - 2) {
- cmdv[n_found++] = "...";
+ cmdv[n_found] = "...";
break;
}
- cmdv[n_found++] = cmdtp->name;
+ cmdv[n_found] = cmdtp->name;
}
cmdv[n_found] = NULL;
return n_found;
}
/* more than one arg or one but the start of the next */
- if (argc > 1 || (last_char == '\0' || last_char == ' ' || last_char == '\t')) {
+ if (argc > 1 || (last_char == '\0' || isblank(last_char))) {
cmdtp = find_cmd(argv[0]);
if (cmdtp == NULL || cmdtp->complete == NULL) {
cmdv[0] = NULL;
@@ -261,7 +215,7 @@ static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv
len = p - cmd;
/* return the partial matches */
- for (cmdtp = &__u_boot_cmd_start; cmdtp != &__u_boot_cmd_end; cmdtp++) {
+ for (; cmdtp != cmdend; cmdtp++) {
clen = strlen(cmdtp->name);
if (clen < len)
@@ -291,7 +245,7 @@ static int make_argv(char *s, int argvsz, char *argv[])
while (argc < argvsz - 1) {
/* skip any white space */
- while ((*s == ' ') || (*s == '\t'))
+ while (isblank(*s))
++s;
if (*s == '\0') /* end of s, no more args */
@@ -300,7 +254,7 @@ static int make_argv(char *s, int argvsz, char *argv[])
argv[argc++] = s; /* begin of argument string */
/* find end of string */
- while (*s && (*s != ' ') && (*s != '\t'))
+ while (*s && !isblank(*s))
++s;
if (*s == '\0') /* end of s, no more args */
@@ -509,7 +463,78 @@ void fixup_cmdtable(cmd_tbl_t *cmdtp, int size)
cmdtp->help = (char *)addr;
}
#endif
+#ifdef CONFIG_AUTO_COMPLETE
+ if (cmdtp->complete) {
+ addr = (ulong)(cmdtp->complete) + gd->reloc_off;
+ cmdtp->complete =
+ (int (*)(int, char * const [], char, int, char * []))addr;
+ }
+#endif
cmdtp++;
}
}
#endif
+
+/**
+ * Call a command function. This should be the only route in U-Boot to call
+ * a command, so that we can track whether we are waiting for input or
+ * executing a command.
+ *
+ * @param cmdtp Pointer to the command to execute
+ * @param flag Some flags normally 0 (see CMD_FLAG_.. above)
+ * @param argc Number of arguments (arg 0 must be the command text)
+ * @param argv Arguments
+ * @return 0 if command succeeded, else non-zero (CMD_RET_...)
+ */
+static int cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ int result;
+
+ result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
+ if (result)
+ debug("Command failed, result=%d", result);
+ return result;
+}
+
+enum command_ret_t cmd_process(int flag, int argc, char * const argv[],
+ int *repeatable, ulong *ticks)
+{
+ enum command_ret_t rc = CMD_RET_SUCCESS;
+ cmd_tbl_t *cmdtp;
+
+ /* Look up command in command table */
+ cmdtp = find_cmd(argv[0]);
+ if (cmdtp == NULL) {
+ printf("Unknown command '%s' - try 'help'\n", argv[0]);
+ return 1;
+ }
+
+ /* found - check max args */
+ if (argc > cmdtp->maxargs)
+ rc = CMD_RET_USAGE;
+
+#if defined(CONFIG_CMD_BOOTD)
+ /* avoid "bootd" recursion */
+ else if (cmdtp->cmd == do_bootd) {
+ if (flag & CMD_FLAG_BOOTD) {
+ puts("'bootd' recursion detected\n");
+ rc = CMD_RET_FAILURE;
+ } else {
+ flag |= CMD_FLAG_BOOTD;
+ }
+ }
+#endif
+
+ /* If OK so far, then do the command */
+ if (!rc) {
+ if (ticks)
+ *ticks = get_timer(0);
+ rc = cmd_call(cmdtp, flag, argc, argv);
+ if (ticks)
+ *ticks = get_timer(*ticks);
+ *repeatable &= cmdtp->repeatable;
+ }
+ if (rc == CMD_RET_USAGE)
+ rc = cmd_usage(cmdtp);
+ return rc;
+}
diff --git a/common/console.c b/common/console.c
index 7e018863bd..cc55068c7c 100644
--- a/common/console.c
+++ b/common/console.c
@@ -2,33 +2,84 @@
* (C) Copyright 2000
* Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <stdarg.h>
#include <malloc.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
@@ -212,7 +263,7 @@ int serial_printf(const char *fmt, ...)
/* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
- i = vsprintf(printbuffer, fmt, args);
+ i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
va_end(args);
serial_puts(printbuffer);
@@ -281,7 +332,7 @@ int fprintf(int file, const char *fmt, ...)
/* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
- i = vsprintf(printbuffer, fmt, args);
+ i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
va_end(args);
/* Send to desired file */
@@ -298,6 +349,9 @@ int getc(void)
return 0;
#endif
+ if (!gd->have_console)
+ return 0;
+
if (gd->flags & GD_FLG_DEVINIT) {
/* Get from the standard input */
return fgetc(stdin);
@@ -314,6 +368,9 @@ int tstc(void)
return 0;
#endif
+ if (!gd->have_console)
+ return 0;
+
if (gd->flags & GD_FLG_DEVINIT) {
/* Test the standard input */
return ftstc(stdin);
@@ -323,6 +380,39 @@ int tstc(void)
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_SILENT_CONSOLE
@@ -335,6 +425,9 @@ void putc(const char c)
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);
@@ -356,6 +449,9 @@ void puts(const char *s)
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);
@@ -371,12 +467,17 @@ int printf(const char *fmt, ...)
uint i;
char printbuffer[CONFIG_SYS_PBSIZE];
+#ifndef 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 = vsprintf(printbuffer, fmt, args);
+ i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
va_end(args);
/* Print the string */
@@ -389,10 +490,15 @@ 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 = vsprintf(printbuffer, fmt, args);
+ i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
/* Print the string */
puts(printbuffer);
@@ -459,7 +565,7 @@ inline void dbg(const char *fmt, ...)
/* For this to work, printbuffer must be larger than
* anything we ever want to print.
*/
- i = vsprintf(printbuffer, fmt, args);
+ i = vsnprintf(printbuffer, sizeof(printbuffer), fmt, args);
va_end(args);
if ((screen + sizeof(screen) - 1 - cursor)
@@ -479,7 +585,7 @@ inline void dbg(const char *fmt, ...)
/** U-Boot INIT FUNCTIONS *************************************************/
-struct stdio_dev *search_device(int flags, char *name)
+struct stdio_dev *search_device(int flags, const char *name)
{
struct stdio_dev *dev;
@@ -491,7 +597,7 @@ struct stdio_dev *search_device(int flags, char *name)
return NULL;
}
-int console_assign(int file, char *devname)
+int console_assign(int file, const char *devname)
{
int flag;
struct stdio_dev *dev;
@@ -529,12 +635,13 @@ int console_init_f(void)
gd->flags |= GD_FLG_SILENT;
#endif
+ print_pre_console_buffer();
+
return 0;
}
void stdio_print_current_devices(void)
{
-#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET
/* Print information */
puts("In: ");
if (stdio_devices[stdin] == NULL) {
@@ -556,7 +663,6 @@ void stdio_print_current_devices(void)
} else {
printf ("%s\n", stdio_devices[stderr]->name);
}
-#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */
}
#ifdef CONFIG_SYS_CONSOLE_IS_IN_ENV
@@ -626,9 +732,9 @@ int console_init_r(void)
done:
#endif
- gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
-
+#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) */
@@ -637,6 +743,8 @@ done:
}
#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))
@@ -701,15 +809,17 @@ int console_init_r(void)
#endif
}
- gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
-
+#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))
diff --git a/common/env_attr.c b/common/env_attr.c
new file mode 100644
index 0000000000..64baca5a10
--- /dev/null
+++ b/common/env_attr.c
@@ -0,0 +1,213 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include <linux/linux_string.h>
+#else
+#include <common.h>
+#endif
+
+#include <env_attr.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <malloc.h>
+
+/*
+ * Iterate through the whole list calling the callback for each found element.
+ * "attr_list" takes the form:
+ * attributes = [^,:\s]*
+ * entry = name[:attributes]
+ * list = entry[,list]
+ */
+int env_attr_walk(const char *attr_list,
+ int (*callback)(const char *name, const char *attributes))
+{
+ const char *entry, *entry_end;
+ char *name, *attributes;
+
+ if (!attr_list)
+ /* list not found */
+ return 1;
+
+ entry = attr_list;
+ do {
+ char *entry_cpy = NULL;
+
+ entry_end = strchr(entry, ENV_ATTR_LIST_DELIM);
+ /* check if this is the last entry in the list */
+ if (entry_end == NULL) {
+ int entry_len = strlen(entry);
+
+ if (entry_len) {
+ /*
+ * allocate memory to copy the entry into since
+ * we will need to inject '\0' chars and squash
+ * white-space before calling the callback
+ */
+ entry_cpy = malloc(entry_len + 1);
+ if (entry_cpy)
+ /* copy the rest of the list */
+ strcpy(entry_cpy, entry);
+ else
+ return -ENOMEM;
+ }
+ } else {
+ int entry_len = entry_end - entry;
+
+ if (entry_len) {
+ /*
+ * allocate memory to copy the entry into since
+ * we will need to inject '\0' chars and squash
+ * white-space before calling the callback
+ */
+ entry_cpy = malloc(entry_len + 1);
+ if (entry_cpy) {
+ /* copy just this entry and null term */
+ strncpy(entry_cpy, entry, entry_len);
+ entry_cpy[entry_len] = '\0';
+ } else
+ return -ENOMEM;
+ }
+ }
+
+ /* check if there is anything to process (e.g. not ",,,") */
+ if (entry_cpy != NULL) {
+ attributes = strchr(entry_cpy, ENV_ATTR_SEP);
+ /* check if there is a ':' */
+ if (attributes != NULL) {
+ /* replace the ':' with '\0' to term name */
+ *attributes++ = '\0';
+ /* remove white-space from attributes */
+ attributes = strim(attributes);
+ }
+ /* remove white-space from name */
+ name = strim(entry_cpy);
+
+ /* only call the callback if there is a name */
+ if (strlen(name) != 0) {
+ int retval = 0;
+
+ retval = callback(name, attributes);
+ if (retval) {
+ free(entry_cpy);
+ return retval;
+ }
+ }
+ }
+
+ free(entry_cpy);
+ entry = entry_end + 1;
+ } while (entry_end != NULL);
+
+ return 0;
+}
+
+/*
+ * Search for the last matching string in another string with the option to
+ * start looking at a certain point (i.e. ignore anything beyond that point).
+ */
+static char *reverse_strstr(const char *searched, const char *search_for,
+ const char *searched_start)
+{
+ char *result = NULL;
+
+ if (*search_for == '\0')
+ return (char *)searched;
+
+ for (;;) {
+ char *match = strstr(searched, search_for);
+
+ /*
+ * Stop looking if no new match is found or looking past the
+ * searched_start pointer
+ */
+ if (match == NULL || (searched_start != NULL &&
+ match + strlen(search_for) > searched_start))
+ break;
+
+ result = match;
+ searched = match + 1;
+ }
+
+ return result;
+}
+
+/*
+ * Retrieve the attributes string associated with a single name in the list
+ * There is no protection on attributes being too small for the value
+ */
+int env_attr_lookup(const char *attr_list, const char *name, char *attributes)
+{
+ const char *entry = NULL;
+
+ if (!attributes)
+ /* bad parameter */
+ return -1;
+ if (!attr_list)
+ /* list not found */
+ return 1;
+
+ entry = reverse_strstr(attr_list, name, NULL);
+ while (entry != NULL) {
+ const char *prevch = entry - 1;
+ const char *nextch = entry + strlen(name);
+
+ /* Skip spaces */
+ while (*prevch == ' ')
+ prevch--;
+ while (*nextch == ' ')
+ nextch++;
+
+ /* check for an exact match */
+ if ((entry == attr_list ||
+ *prevch == ENV_ATTR_LIST_DELIM) &&
+ (*nextch == ENV_ATTR_SEP ||
+ *nextch == ENV_ATTR_LIST_DELIM ||
+ *nextch == '\0'))
+ break;
+
+ entry = reverse_strstr(attr_list, name, entry);
+ }
+ if (entry != NULL) {
+ int len;
+
+ /* skip the name */
+ entry += strlen(name);
+ /* skip spaces */
+ while (*entry == ' ')
+ entry++;
+ if (*entry != ENV_ATTR_SEP)
+ len = 0;
+ else {
+ const char *delim;
+ static const char delims[] = {
+ ENV_ATTR_LIST_DELIM, ' ', '\0'};
+
+ /* skip the attr sep */
+ entry += 1;
+ /* skip spaces */
+ while (*entry == ' ')
+ entry++;
+
+ delim = strpbrk(entry, delims);
+ if (delim == NULL)
+ len = strlen(entry);
+ else
+ len = delim - entry;
+ memcpy(attributes, entry, len);
+ }
+ attributes[len] = '\0';
+
+ /* success */
+ return 0;
+ }
+
+ /* not found in list */
+ return 2;
+}
diff --git a/common/env_auto.c b/common/env_auto.c
index c03f668ab1..8b5a822300 100644
--- a/common/env_auto.c
+++ b/common/env_auto.c
@@ -59,7 +59,7 @@ extern nand_info_t nand_info[];
//extern flash_info_t flash_info[];
/* references to names in env_common.c */
-extern uchar default_environment[];
+extern const unsigned char default_environment[];
extern int default_environment_size;
extern unsigned int OmPin;
@@ -280,7 +280,7 @@ int saveenv_movinand(void)
char *res;
res = (char *)&env_ptr->data;
- len = hexport('\0', &res, ENV_SIZE);
+ len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
if (len < 0) {
printf("Cannot export environment");
return 1;
@@ -307,7 +307,7 @@ int saveenv_onenand(void)
char *res;
res = (char *)&env_ptr->data;
- len = hexport('\0', &res, ENV_SIZE);
+ len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
if (len < 0) {
printf("Cannot export environment");
return 1;
diff --git a/common/env_callback.c b/common/env_callback.c
new file mode 100644
index 0000000000..34bb58e4a9
--- /dev/null
+++ b/common/env_callback.c
@@ -0,0 +1,128 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <environment.h>
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+DECLARE_GLOBAL_DATA_PTR;
+#endif
+
+/*
+ * Look up a callback function pointer by name
+ */
+static struct env_clbk_tbl *find_env_callback(const char *name)
+{
+ struct env_clbk_tbl *clbkp;
+ int i;
+ int num_callbacks = ll_entry_count(struct env_clbk_tbl, env_clbk);
+
+ if (name == NULL)
+ return NULL;
+
+ /* look up the callback in the linker-list */
+ for (i = 0, clbkp = ll_entry_start(struct env_clbk_tbl, env_clbk);
+ i < num_callbacks;
+ i++, clbkp++) {
+ if (strcmp(name, clbkp->name) == 0)
+ return clbkp;
+ }
+
+ return NULL;
+}
+
+/*
+ * Look for a possible callback for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+void env_callback_init(ENTRY *var_entry)
+{
+ const char *var_name = var_entry->key;
+ const char *callback_list = getenv(ENV_CALLBACK_VAR);
+ char callback_name[256] = "";
+ struct env_clbk_tbl *clbkp;
+ int ret = 1;
+
+ /* look in the ".callbacks" var for a reference to this variable */
+ if (callback_list != NULL)
+ ret = env_attr_lookup(callback_list, var_name, callback_name);
+
+ /* only if not found there, look in the static list */
+ if (ret)
+ ret = env_attr_lookup(ENV_CALLBACK_LIST_STATIC, var_name,
+ callback_name);
+
+ /* if an association was found, set the callback pointer */
+ if (!ret && strlen(callback_name)) {
+ clbkp = find_env_callback(callback_name);
+ if (clbkp != NULL)
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ var_entry->callback = clbkp->callback + gd->reloc_off;
+#else
+ var_entry->callback = clbkp->callback;
+#endif
+ }
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a callback association should remove its callback.
+ */
+static int clear_callback(ENTRY *entry)
+{
+ entry->callback = NULL;
+
+ return 0;
+}
+
+/*
+ * Call for each element in the list that associates variables to callbacks
+ */
+static int set_callback(const char *name, const char *value)
+{
+ ENTRY e, *ep;
+ struct env_clbk_tbl *clbkp;
+
+ e.key = name;
+ e.data = NULL;
+ hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+ /* does the env variable actually exist? */
+ if (ep != NULL) {
+ /* the assocaition delares no callback, so remove the pointer */
+ if (value == NULL || strlen(value) == 0)
+ ep->callback = NULL;
+ else {
+ /* assign the requested callback */
+ clbkp = find_env_callback(value);
+ if (clbkp != NULL)
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+ ep->callback = clbkp->callback + gd->reloc_off;
+#else
+ ep->callback = clbkp->callback;
+#endif
+ }
+ }
+
+ return 0;
+}
+
+static int on_callbacks(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ /* remove all callbacks */
+ hwalk_r(&env_htab, clear_callback);
+
+ /* configure any static callback bindings */
+ env_attr_walk(ENV_CALLBACK_LIST_STATIC, set_callback);
+ /* configure any dynamic callback bindings */
+ env_attr_walk(value, set_callback);
+
+ return 0;
+}
+U_BOOT_ENV_CALLBACK(callbacks, on_callbacks);
diff --git a/common/env_common.c b/common/env_common.c
index a365fcb8d3..1ac337730c 100644
--- a/common/env_common.c
+++ b/common/env_common.c
@@ -5,23 +5,7 @@
* (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Andreas Heppel <aheppel@sysgo.de>
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
@@ -34,142 +18,46 @@
DECLARE_GLOBAL_DATA_PTR;
-extern env_t *env_ptr;
-
-extern void env_relocate_spec (void);
-extern uchar env_get_char_spec(int);
-
-static uchar env_get_char_init (int index);
-
/************************************************************************
* Default settings to be used when no valid environment is found
*/
-#define XMK_STR(x) #x
-#define MK_STR(x) XMK_STR(x)
-
-uchar default_environment[] = {
-#if defined(CONFIG_HKDK4412) && defined(CONFIG_EXYNOS_PRIME)
- "bootscript=source 40008000\0"
- "default_bootcmd=echo >>> Run Default Bootcmd <<<;movi read kernel 0 40008000;movi read rootfs 0 41000000 100000;bootm 40008000 41000000\0"
- "loadbootscript_1=echo >>> Load Boot Script from mmc 0:1 <<<;fatload mmc 0:1 40008000 boot.scr\0"
- "loadbootscript_2=echo >>> Load Boot Script from mmc 0:2 <<<;fatload mmc 0:2 40008000 boot.scr\0"
-#endif
-
-#ifdef CONFIG_BOOTARGS
- "bootargs=" CONFIG_BOOTARGS "\0"
-#endif
-#ifdef CONFIG_BOOTCOMMAND
- "bootcmd=" CONFIG_BOOTCOMMAND "\0"
-#endif
-#ifdef CONFIG_RAMBOOTCOMMAND
- "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
-#endif
-#ifdef CONFIG_NFSBOOTCOMMAND
- "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
-#endif
-#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
- "bootdelay=" MK_STR(CONFIG_BOOTDELAY) "\0"
-#endif
-#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
- "baudrate=" MK_STR(CONFIG_BAUDRATE) "\0"
-#endif
-#ifdef CONFIG_LOADS_ECHO
- "loads_echo=" MK_STR(CONFIG_LOADS_ECHO) "\0"
-#endif
-#ifdef CONFIG_ETHADDR
- "ethaddr=" MK_STR(CONFIG_ETHADDR) "\0"
-#endif
-#ifdef CONFIG_ETH1ADDR
- "eth1addr=" MK_STR(CONFIG_ETH1ADDR) "\0"
-#endif
-#ifdef CONFIG_ETH2ADDR
- "eth2addr=" MK_STR(CONFIG_ETH2ADDR) "\0"
-#endif
-#ifdef CONFIG_ETH3ADDR
- "eth3addr=" MK_STR(CONFIG_ETH3ADDR) "\0"
-#endif
-#ifdef CONFIG_ETH4ADDR
- "eth4addr=" MK_STR(CONFIG_ETH4ADDR) "\0"
-#endif
-#ifdef CONFIG_ETH5ADDR
- "eth5addr=" MK_STR(CONFIG_ETH5ADDR) "\0"
-#endif
-#ifdef CONFIG_IPADDR
- "ipaddr=" MK_STR(CONFIG_IPADDR) "\0"
-#endif
-#ifdef CONFIG_SERVERIP
- "serverip=" MK_STR(CONFIG_SERVERIP) "\0"
-#endif
-#ifdef CONFIG_SYS_AUTOLOAD
- "autoload=" CONFIG_SYS_AUTOLOAD "\0"
-#endif
-#ifdef CONFIG_PREBOOT
- "preboot=" CONFIG_PREBOOT "\0"
-#endif
-#ifdef CONFIG_ROOTPATH
- "rootpath=" MK_STR(CONFIG_ROOTPATH) "\0"
-#endif
-#ifdef CONFIG_GATEWAYIP
- "gatewayip=" MK_STR(CONFIG_GATEWAYIP) "\0"
-#endif
-#ifdef CONFIG_NETMASK
- "netmask=" MK_STR(CONFIG_NETMASK) "\0"
-#endif
-#ifdef CONFIG_HOSTNAME
- "hostname=" MK_STR(CONFIG_HOSTNAME) "\0"
-#endif
-#ifdef CONFIG_BOOTFILE
- "bootfile=" MK_STR(CONFIG_BOOTFILE) "\0"
-#endif
-#ifdef CONFIG_LOADADDR
- "loadaddr=" MK_STR(CONFIG_LOADADDR) "\0"
-#endif
-#ifdef CONFIG_CLOCKS_IN_MHZ
- "clocks_in_mhz=1\0"
-#endif
-#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
- "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
-#endif
-#ifdef CONFIG_EXTRA_ENV_SETTINGS
- CONFIG_EXTRA_ENV_SETTINGS
-#endif
- "\0"
-};
+#include <env_default.h>
-int default_environment_size = sizeof(default_environment);
+struct hsearch_data env_htab = {
+ .change_ok = env_flags_validate,
+};
-static uchar env_get_char_init (int index)
+static uchar __env_get_char_spec(int index)
{
- uchar c;
+ return *((uchar *)(gd->env_addr + index));
+}
+uchar env_get_char_spec(int)
+ __attribute__((weak, alias("__env_get_char_spec")));
+static uchar env_get_char_init(int index)
+{
/* if crc was bad, use the default environment */
if (gd->env_valid)
- c = env_get_char_spec(index);
+ return env_get_char_spec(index);
else
- c = default_environment[index];
-
- return (c);
+ return default_environment[index];
}
-uchar env_get_char_memory (int index)
+uchar env_get_char_memory(int index)
{
return *env_get_addr(index);
}
-uchar env_get_char (int index)
+uchar env_get_char(int index)
{
- uchar c;
-
/* if relocated to RAM */
if (gd->flags & GD_FLG_RELOC)
- c = env_get_char_memory(index);
+ return env_get_char_memory(index);
else
- c = env_get_char_init(index);
-
- return (c);
+ return env_get_char_init(index);
}
-uchar *env_get_addr (int index)
+const uchar *env_get_addr(int index)
{
if (gd->env_valid)
return (uchar *)(gd->env_addr + index);
@@ -177,8 +65,42 @@ uchar *env_get_addr (int index)
return &default_environment[index];
}
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var)
+{
+ char *s = getenv(var);
+
+ if (s == NULL)
+ return -1;
+ return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
+ 1 : 0;
+}
+
+/*
+ * Look up the variable from the default environment
+ */
+char *getenv_default(const char *name)
+{
+ char *ret_val;
+ unsigned long really_valid = gd->env_valid;
+ unsigned long real_gd_flags = gd->flags;
+
+ /* Pretend that the image is bad. */
+ gd->flags &= ~GD_FLG_ENV_READY;
+ gd->env_valid = 0;
+ ret_val = getenv(name);
+ gd->env_valid = really_valid;
+ gd->flags = real_gd_flags;
+ return ret_val;
+}
+
void set_default_env(const char *s)
{
+ int flags = 0;
+
if (sizeof(default_environment) > ENV_SIZE) {
puts("*** Error - default environment is too large\n\n");
return;
@@ -188,21 +110,36 @@ void set_default_env(const char *s)
if (*s == '!') {
printf("*** Warning - %s, "
"using default environment\n\n",
- s+1);
+ s + 1);
} else {
+ flags = H_INTERACTIVE;
puts(s);
}
} else {
puts("Using default environment\n\n");
}
- if (himport((char *)default_environment,
- sizeof(default_environment), '\0', 0) == 0) {
+ if (himport_r(&env_htab, (char *)default_environment,
+ sizeof(default_environment), '\0', flags,
+ 0, NULL) == 0)
error("Environment import failed: errno = %d\n", errno);
- }
+
gd->flags |= GD_FLG_ENV_READY;
}
+
+/* [re]set individual variables to their value in the default environment */
+int set_default_vars(int nvars, char * const vars[])
+{
+ /*
+ * Special use-case: import from default environment
+ * (and use \0 as a separator)
+ */
+ return himport_r(&env_htab, (const char *)default_environment,
+ sizeof(default_environment), '\0',
+ H_NOCLEAR | H_INTERACTIVE, nvars, vars);
+}
+
/*
* Check if CRC is valid and (if yes) import the environment.
* Note that "buf" may or may not be aligned.
@@ -222,7 +159,8 @@ int env_import(const char *buf, int check)
}
}
- if (himport((char *)ep->data, ENV_SIZE, '\0', 0)) {
+ if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0,
+ 0, NULL)) {
gd->flags |= GD_FLG_ENV_READY;
return 1;
}
@@ -234,61 +172,52 @@ int env_import(const char *buf, int check)
return 0;
}
-void env_relocate (void)
+void env_relocate(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
- extern void env_reloc(void);
-
env_reloc();
+ env_htab.change_ok += gd->reloc_off;
#endif
if (gd->env_valid == 0) {
-#if defined(CONFIG_ENV_IS_NOWHERE) /* Environment not changable */
+#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
+ /* Environment not changable */
set_default_env(NULL);
#else
- show_boot_progress (-60);
+ bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
set_default_env("!bad CRC");
#endif
} else {
- env_relocate_spec ();
+ env_relocate_spec();
}
}
-#if 0 /* need to reimplement - def CONFIG_AUTO_COMPLETE */
+#if defined(CONFIG_AUTO_COMPLETE) && !defined(CONFIG_SPL_BUILD)
int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
{
- int i, nxt, len, vallen, found;
- const char *lval, *rval;
+ ENTRY *match;
+ int found, idx;
+ idx = 0;
found = 0;
cmdv[0] = NULL;
- len = strlen(var);
- /* now iterate over the variables and select those that match */
- for (i=0; env_get_char(i) != '\0'; i=nxt+1) {
-
- for (nxt=i; env_get_char(nxt) != '\0'; ++nxt)
- ;
-
- lval = (char *)env_get_addr(i);
- rval = strchr(lval, '=');
- if (rval != NULL) {
- vallen = rval - lval;
- rval++;
- } else
- vallen = strlen(lval);
-
- if (len > 0 && (vallen < len || memcmp(lval, var, len) != 0))
- continue;
+ while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
+ int vallen = strlen(match->key) + 1;
- if (found >= maxv - 2 || bufsz < vallen + 1) {
- cmdv[found++] = "...";
+ if (found >= maxv - 2 || bufsz < vallen)
break;
- }
+
cmdv[found++] = buf;
- memcpy(buf, lval, vallen); buf += vallen; bufsz -= vallen;
- *buf++ = '\0'; bufsz--;
+ memcpy(buf, match->key, vallen);
+ buf += vallen;
+ bufsz -= vallen;
}
+ qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
+
+ if (idx)
+ cmdv[found++] = "...";
+
cmdv[found] = NULL;
return found;
}
diff --git a/common/env_flags.c b/common/env_flags.c
new file mode 100644
index 0000000000..e9b72e60a9
--- /dev/null
+++ b/common/env_flags.c
@@ -0,0 +1,544 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#ifdef USE_HOSTCC /* Eliminate "ANSI does not permit..." warnings */
+#include <stdint.h>
+#include <stdio.h>
+#include "fw_env.h"
+#include <env_attr.h>
+#include <env_flags.h>
+#define getenv fw_getenv
+#else
+#include <common.h>
+#include <environment.h>
+#endif
+
+#ifdef CONFIG_CMD_NET
+#define ENV_FLAGS_NET_VARTYPE_REPS "im"
+#else
+#define ENV_FLAGS_NET_VARTYPE_REPS ""
+#endif
+
+static const char env_flags_vartype_rep[] = "sdxb" ENV_FLAGS_NET_VARTYPE_REPS;
+static const char env_flags_varaccess_rep[] = "aroc";
+static const int env_flags_varaccess_mask[] = {
+ 0,
+ ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+ ENV_FLAGS_VARACCESS_PREVENT_CREATE |
+ ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
+ ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+ ENV_FLAGS_VARACCESS_PREVENT_OVERWR,
+ ENV_FLAGS_VARACCESS_PREVENT_DELETE |
+ ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR};
+
+#ifdef CONFIG_CMD_ENV_FLAGS
+static const char * const env_flags_vartype_names[] = {
+ "string",
+ "decimal",
+ "hexadecimal",
+ "boolean",
+#ifdef CONFIG_CMD_NET
+ "IP address",
+ "MAC address",
+#endif
+};
+static const char * const env_flags_varaccess_names[] = {
+ "any",
+ "read-only",
+ "write-once",
+ "change-default",
+};
+
+/*
+ * Print the whole list of available type flags.
+ */
+void env_flags_print_vartypes(void)
+{
+ enum env_flags_vartype curtype = (enum env_flags_vartype)0;
+
+ while (curtype != env_flags_vartype_end) {
+ printf("\t%c -\t%s\n", env_flags_vartype_rep[curtype],
+ env_flags_vartype_names[curtype]);
+ curtype++;
+ }
+}
+
+/*
+ * Print the whole list of available access flags.
+ */
+void env_flags_print_varaccess(void)
+{
+ enum env_flags_varaccess curaccess = (enum env_flags_varaccess)0;
+
+ while (curaccess != env_flags_varaccess_end) {
+ printf("\t%c -\t%s\n", env_flags_varaccess_rep[curaccess],
+ env_flags_varaccess_names[curaccess]);
+ curaccess++;
+ }
+}
+
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type)
+{
+ return env_flags_vartype_names[type];
+}
+
+/*
+ * Return the name of the access.
+ */
+const char *env_flags_get_varaccess_name(enum env_flags_varaccess access)
+{
+ return env_flags_varaccess_names[access];
+}
+#endif /* CONFIG_CMD_ENV_FLAGS */
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags)
+{
+ char *type;
+
+ if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
+ return env_flags_vartype_string;
+
+ type = strchr(env_flags_vartype_rep,
+ flags[ENV_FLAGS_VARTYPE_LOC]);
+
+ if (type != NULL)
+ return (enum env_flags_vartype)
+ (type - &env_flags_vartype_rep[0]);
+
+ printf("## Warning: Unknown environment variable type '%c'\n",
+ flags[ENV_FLAGS_VARTYPE_LOC]);
+ return env_flags_vartype_string;
+}
+
+/*
+ * Parse the flags string from a .flags attribute list into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess(const char *flags)
+{
+ char *access;
+
+ if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
+ return env_flags_varaccess_any;
+
+ access = strchr(env_flags_varaccess_rep,
+ flags[ENV_FLAGS_VARACCESS_LOC]);
+
+ if (access != NULL)
+ return (enum env_flags_varaccess)
+ (access - &env_flags_varaccess_rep[0]);
+
+ printf("## Warning: Unknown environment variable access method '%c'\n",
+ flags[ENV_FLAGS_VARACCESS_LOC]);
+ return env_flags_varaccess_any;
+}
+
+/*
+ * Parse the binary flags from a hash table entry into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags)
+{
+ int i;
+
+ for (i = 0; i < sizeof(env_flags_varaccess_mask); i++)
+ if (env_flags_varaccess_mask[i] ==
+ (binflags & ENV_FLAGS_VARACCESS_BIN_MASK))
+ return (enum env_flags_varaccess)i;
+
+ printf("Warning: Non-standard access flags. (0x%x)\n",
+ binflags & ENV_FLAGS_VARACCESS_BIN_MASK);
+
+ return env_flags_varaccess_any;
+}
+
+static inline int is_hex_prefix(const char *value)
+{
+ return value[0] == '0' && (value[1] == 'x' || value[1] == 'X');
+}
+
+static void skip_num(int hex, const char *value, const char **end,
+ int max_digits)
+{
+ int i;
+
+ if (hex && is_hex_prefix(value))
+ value += 2;
+
+ for (i = max_digits; i != 0; i--) {
+ if (hex && !isxdigit(*value))
+ break;
+ if (!hex && !isdigit(*value))
+ break;
+ value++;
+ }
+ if (end != NULL)
+ *end = value;
+}
+
+/*
+ * Based on the declared type enum, validate that the value string complies
+ * with that format
+ */
+static int _env_flags_validate_type(const char *value,
+ enum env_flags_vartype type)
+{
+ const char *end;
+#ifdef CONFIG_CMD_NET
+ const char *cur;
+ int i;
+#endif
+
+ switch (type) {
+ case env_flags_vartype_string:
+ break;
+ case env_flags_vartype_decimal:
+ skip_num(0, value, &end, -1);
+ if (*end != '\0')
+ return -1;
+ break;
+ case env_flags_vartype_hex:
+ skip_num(1, value, &end, -1);
+ if (*end != '\0')
+ return -1;
+ if (value + 2 == end && is_hex_prefix(value))
+ return -1;
+ break;
+ case env_flags_vartype_bool:
+ if (value[0] != '1' && value[0] != 'y' && value[0] != 't' &&
+ value[0] != 'Y' && value[0] != 'T' &&
+ value[0] != '0' && value[0] != 'n' && value[0] != 'f' &&
+ value[0] != 'N' && value[0] != 'F')
+ return -1;
+ if (value[1] != '\0')
+ return -1;
+ break;
+#ifdef CONFIG_CMD_NET
+ case env_flags_vartype_ipaddr:
+ cur = value;
+ for (i = 0; i < 4; i++) {
+ skip_num(0, cur, &end, 3);
+ if (cur == end)
+ return -1;
+ if (i != 3 && *end != '.')
+ return -1;
+ if (i == 3 && *end != '\0')
+ return -1;
+ cur = end + 1;
+ }
+ break;
+ case env_flags_vartype_macaddr:
+ cur = value;
+ for (i = 0; i < 6; i++) {
+ skip_num(1, cur, &end, 2);
+ if (cur == end)
+ return -1;
+ if (cur + 2 == end && is_hex_prefix(cur))
+ return -1;
+ if (i != 5 && *end != ':')
+ return -1;
+ if (i == 5 && *end != '\0')
+ return -1;
+ cur = end + 1;
+ }
+ break;
+#endif
+ case env_flags_vartype_end:
+ return -1;
+ }
+
+ /* OK */
+ return 0;
+}
+
+/*
+ * Look for flags in a provided list and failing that the static list
+ */
+static inline int env_flags_lookup(const char *flags_list, const char *name,
+ char *flags)
+{
+ int ret = 1;
+
+ if (!flags)
+ /* bad parameter */
+ return -1;
+
+ /* try the env first */
+ if (flags_list)
+ ret = env_attr_lookup(flags_list, name, flags);
+
+ if (ret != 0)
+ /* if not found in the env, look in the static list */
+ ret = env_attr_lookup(ENV_FLAGS_LIST_STATIC, name, flags);
+
+ return ret;
+}
+
+#ifdef USE_HOSTCC /* Functions only used from tools/env */
+/*
+ * Look up any flags directly from the .flags variable and the static list
+ * and convert them to the vartype enum.
+ */
+enum env_flags_vartype env_flags_get_type(const char *name)
+{
+ const char *flags_list = getenv(ENV_FLAGS_VAR);
+ char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
+
+ if (env_flags_lookup(flags_list, name, flags))
+ return env_flags_vartype_string;
+
+ if (strlen(flags) <= ENV_FLAGS_VARTYPE_LOC)
+ return env_flags_vartype_string;
+
+ return env_flags_parse_vartype(flags);
+}
+
+/*
+ * Look up the access of a variable directly from the .flags var.
+ */
+enum env_flags_varaccess env_flags_get_varaccess(const char *name)
+{
+ const char *flags_list = getenv(ENV_FLAGS_VAR);
+ char flags[ENV_FLAGS_ATTR_MAX_LEN + 1];
+
+ if (env_flags_lookup(flags_list, name, flags))
+ return env_flags_varaccess_any;
+
+ if (strlen(flags) <= ENV_FLAGS_VARACCESS_LOC)
+ return env_flags_varaccess_any;
+
+ return env_flags_parse_varaccess(flags);
+}
+
+/*
+ * Validate that the proposed new value for "name" is valid according to the
+ * defined flags for that variable, if any.
+ */
+int env_flags_validate_type(const char *name, const char *value)
+{
+ enum env_flags_vartype type;
+
+ if (value == NULL)
+ return 0;
+ type = env_flags_get_type(name);
+ if (_env_flags_validate_type(value, type) < 0) {
+ printf("## Error: flags type check failure for "
+ "\"%s\" <= \"%s\" (type: %c)\n",
+ name, value, env_flags_vartype_rep[type]);
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Validate that the proposed access to variable "name" is valid according to
+ * the defined flags for that variable, if any.
+ */
+int env_flags_validate_varaccess(const char *name, int check_mask)
+{
+ enum env_flags_varaccess access;
+ int access_mask;
+
+ access = env_flags_get_varaccess(name);
+ access_mask = env_flags_varaccess_mask[access];
+
+ return (check_mask & access_mask) != 0;
+}
+
+/*
+ * Validate the parameters to "env set" directly
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[])
+{
+ if ((argc >= 3) && argv[2] != NULL) {
+ enum env_flags_vartype type = env_flags_get_type(argv[1]);
+
+ /*
+ * we don't currently check types that need more than
+ * one argument
+ */
+ if (type != env_flags_vartype_string && argc > 3) {
+ printf("## Error: too many parameters for setting "
+ "\"%s\"\n", argv[1]);
+ return -1;
+ }
+ return env_flags_validate_type(argv[1], argv[2]);
+ }
+ /* ok */
+ return 0;
+}
+
+#else /* !USE_HOSTCC - Functions only used from lib/hashtable.c */
+
+/*
+ * Parse the flag charachters from the .flags attribute list into the binary
+ * form to be stored in the environment entry->flags field.
+ */
+static int env_parse_flags_to_bin(const char *flags)
+{
+ int binflags;
+
+ binflags = env_flags_parse_vartype(flags) & ENV_FLAGS_VARTYPE_BIN_MASK;
+ binflags |= env_flags_varaccess_mask[env_flags_parse_varaccess(flags)];
+
+ return binflags;
+}
+
+/*
+ * Look for possible flags for a newly added variable
+ * This is called specifically when the variable did not exist in the hash
+ * previously, so the blanket update did not find this variable.
+ */
+void env_flags_init(ENTRY *var_entry)
+{
+ const char *var_name = var_entry->key;
+ const char *flags_list = getenv(ENV_FLAGS_VAR);
+ char flags[ENV_FLAGS_ATTR_MAX_LEN + 1] = "";
+ int ret = 1;
+
+ /* look in the ".flags" and static for a reference to this variable */
+ ret = env_flags_lookup(flags_list, var_name, flags);
+
+ /* if any flags were found, set the binary form to the entry */
+ if (!ret && strlen(flags))
+ var_entry->flags = env_parse_flags_to_bin(flags);
+}
+
+/*
+ * Called on each existing env var prior to the blanket update since removing
+ * a flag in the flag list should remove its flags.
+ */
+static int clear_flags(ENTRY *entry)
+{
+ entry->flags = 0;
+
+ return 0;
+}
+
+/*
+ * Call for each element in the list that defines flags for a variable
+ */
+static int set_flags(const char *name, const char *value)
+{
+ ENTRY e, *ep;
+
+ e.key = name;
+ e.data = NULL;
+ hsearch_r(e, FIND, &ep, &env_htab, 0);
+
+ /* does the env variable actually exist? */
+ if (ep != NULL) {
+ /* the flag list is empty, so clear the flags */
+ if (value == NULL || strlen(value) == 0)
+ ep->flags = 0;
+ else
+ /* assign the requested flags */
+ ep->flags = env_parse_flags_to_bin(value);
+ }
+
+ return 0;
+}
+
+static int on_flags(const char *name, const char *value, enum env_op op,
+ int flags)
+{
+ /* remove all flags */
+ hwalk_r(&env_htab, clear_flags);
+
+ /* configure any static flags */
+ env_attr_walk(ENV_FLAGS_LIST_STATIC, set_flags);
+ /* configure any dynamic flags */
+ env_attr_walk(value, set_flags);
+
+ return 0;
+}
+U_BOOT_ENV_CALLBACK(flags, on_flags);
+
+/*
+ * Perform consistency checking before creating, overwriting, or deleting an
+ * environment variable. Called as a callback function by hsearch_r() and
+ * hdelete_r(). Returns 0 in case of success, 1 in case of failure.
+ * When (flag & H_FORCE) is set, do not print out any error message and force
+ * overwriting of write-once variables.
+ */
+
+int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
+ int flag)
+{
+ const char *name;
+ const char *oldval = NULL;
+
+ if (op != env_op_create)
+ oldval = item->data;
+
+ name = item->key;
+
+ /* Default value for NULL to protect string-manipulating functions */
+ newval = newval ? : "";
+
+ /* validate the value to match the variable type */
+ if (op != env_op_delete) {
+ enum env_flags_vartype type = (enum env_flags_vartype)
+ (ENV_FLAGS_VARTYPE_BIN_MASK & item->flags);
+
+ if (_env_flags_validate_type(newval, type) < 0) {
+ printf("## Error: flags type check failure for "
+ "\"%s\" <= \"%s\" (type: %c)\n",
+ name, newval, env_flags_vartype_rep[type]);
+ return -1;
+ }
+ }
+
+ /* check for access permission */
+#ifndef CONFIG_ENV_ACCESS_IGNORE_FORCE
+ if (flag & H_FORCE)
+ return 0;
+#endif
+ switch (op) {
+ case env_op_delete:
+ if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_DELETE) {
+ printf("## Error: Can't delete \"%s\"\n", name);
+ return 1;
+ }
+ break;
+ case env_op_overwrite:
+ if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_OVERWR) {
+ printf("## Error: Can't overwrite \"%s\"\n", name);
+ return 1;
+ } else if (item->flags &
+ ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR) {
+ const char *defval = getenv_default(name);
+
+ if (defval == NULL)
+ defval = "";
+ printf("oldval: %s defval: %s\n", oldval, defval);
+ if (strcmp(oldval, defval) != 0) {
+ printf("## Error: Can't overwrite \"%s\"\n",
+ name);
+ return 1;
+ }
+ }
+ break;
+ case env_op_create:
+ if (item->flags & ENV_FLAGS_VARACCESS_PREVENT_CREATE) {
+ printf("## Error: Can't create \"%s\"\n", name);
+ return 1;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/common/hush.c b/common/hush.c
index 2188fd4ac8..3f3a79c508 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -17,7 +17,6 @@
* Erik W. Troan, which they placed in the public domain. I don't know
* how much of the Johnson/Troan code has survived the repeated rewrites.
* Other credits:
- * simple_itoa() was lifted from boa-0.93.15
* b_addchr() derived from similar w_addchar function in glibc-2.2
* setup_redirect(), redirect_opt_num(), and big chunks of main()
* and many builtins derived from contributions by Erik Andersen
@@ -72,20 +71,9 @@
* maybe change map[] to use 2-bit entries
* (eventually) remove all the printf's
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
+
#define __U_BOOT__
#ifdef __U_BOOT__
#include <malloc.h> /* malloc, free, realloc*/
@@ -93,8 +81,9 @@
#include <common.h> /* readline */
#include <hush.h>
#include <command.h> /* find_cmd */
-/*cmd_boot.c*/
-extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); /* do_bootd */
+#ifndef CONFIG_SYS_PROMPT_HUSH_PS2
+#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
+#endif
#endif
#ifndef __U_BOOT__
#include <ctype.h> /* isalpha, isdigit */
@@ -127,6 +116,7 @@ extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
#endif
#endif
#define SPECIAL_VAR_SYMBOL 03
+#define SUBSTED_VAR_SYMBOL 04
#ifndef __U_BOOT__
#define FLAG_EXIT_FROM_LOOP 1
#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
@@ -288,8 +278,7 @@ struct variables {
char **global_argv;
unsigned int global_argc;
#endif
-unsigned int last_return_code;
-int nesting_level;
+static unsigned int last_return_code;
#ifndef __U_BOOT__
extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
#endif
@@ -499,7 +488,7 @@ static void remove_bg_job(struct pipe *pi);
/* local variable support */
static char **make_list_in(char **inp, char *name);
static char *insert_var_value(char *inp);
-static char *get_local_var(const char *var);
+static char *insert_var_value_sub(char *inp, int tag_subst);
#ifndef __U_BOOT__
/* Table of built-in functions. They can be forked or not, depending on
@@ -925,20 +914,6 @@ static int b_addqchr(o_string *o, int ch, int quote)
return b_addchr(o, ch);
}
-/* belongs in utility.c */
-char *simple_itoa(unsigned int i)
-{
- /* 21 digits plus null terminator, good for 64-bit or smaller ints */
- static char local[22];
- char *p = &local[21];
- *p-- = '\0';
- do {
- *p-- = '0' + i % 10;
- i /= 10;
- } while (i > 0);
- return p + 1;
-}
-
#ifndef __U_BOOT__
static int b_adduint(o_string *o, unsigned int i)
{
@@ -1018,14 +993,11 @@ static void get_user_input(struct in_str *i)
fflush(stdout);
i->p = the_command;
#else
- extern char console_buffer[];
int n;
static char the_command[CONFIG_SYS_CBSIZE];
#ifdef CONFIG_BOOT_RETRY_TIME
-# ifdef CONFIG_RESET_TO_RETRY
- extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
-# else
+# ifndef CONFIG_RESET_TO_RETRY
# error "This currently only works with CONFIG_RESET_TO_RETRY enabled"
# endif
reset_cmd_timeout();
@@ -1559,7 +1531,6 @@ static int run_pipe_real(struct pipe *pi)
int nextin;
int flag = do_repeat ? CMD_FLAG_REPEAT : 0;
struct child_prog *child;
- cmd_tbl_t *cmdtp;
char *p;
# if __GNUC__
/* Avoid longjmp clobbering */
@@ -1663,64 +1634,30 @@ static int run_pipe_real(struct pipe *pi)
* Is it really safe for inline use? Experimentally,
* things seem to work with glibc. */
setup_redirects(child, squirrel);
-#else
- /* check ";", because ,example , argv consist from
- * "help;flinfo" must not execute
- */
- if (strchr(child->argv[i], ';')) {
- printf ("Unknown command '%s' - try 'help' or use 'run' command\n",
- child->argv[i]);
- return -1;
- }
- /* Look up command in command table */
-
- if ((cmdtp = find_cmd(child->argv[i])) == NULL) {
- printf ("Unknown command '%s' - try 'help'\n", child->argv[i]);
- return -1; /* give up after bad command */
- } else {
- int rcode;
-#if defined(CONFIG_CMD_BOOTD)
- extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
-
- /* avoid "bootd" recursion */
- if (cmdtp->cmd == do_bootd) {
- if (flag & CMD_FLAG_BOOTD) {
- printf ("'bootd' recursion detected\n");
- return -1;
- }
- else
- flag |= CMD_FLAG_BOOTD;
- }
-#endif
- /* found - check max args */
- if ((child->argc - i) > cmdtp->maxargs)
- return cmd_usage(cmdtp);
-#endif
- child->argv+=i; /* XXX horrible hack */
-#ifndef __U_BOOT__
+ child->argv += i; /* XXX horrible hack */
rcode = x->function(child);
-#else
- /* OK - call function to do the command */
-
- rcode = (cmdtp->cmd)
-(cmdtp, flag,child->argc-i,&child->argv[i]);
- if ( !cmdtp->repeatable )
- flag_repeat = 0;
-
-
-#endif
- child->argv-=i; /* XXX restore hack so free() can work right */
-#ifndef __U_BOOT__
-
+ /* XXX restore hack so free() can work right */
+ child->argv -= i;
restore_redirects(squirrel);
-#endif
-
- return rcode;
}
+ return rcode;
}
-#ifndef __U_BOOT__
+#else
+ /* check ";", because ,example , argv consist from
+ * "help;flinfo" must not execute
+ */
+ if (strchr(child->argv[i], ';')) {
+ printf("Unknown command '%s' - try 'help' or use "
+ "'run' command\n", child->argv[i]);
+ return -1;
+ }
+ /* Process the command */
+ return cmd_process(flag, child->argc, child->argv,
+ &flag_repeat, NULL);
+#endif
}
+#ifndef __U_BOOT__
for (i = 0; i < pi->num_progs; i++) {
child = & (pi->progs[i]);
@@ -2175,7 +2112,7 @@ static char *get_dollar_var(char ch);
#endif
/* This is used to get/check local shell variables */
-static char *get_local_var(const char *s)
+char *get_local_var(const char *s)
{
struct variables *cur;
@@ -2223,7 +2160,7 @@ int set_local_var(const char *s, int flg_export)
* NAME=VALUE format. So the first order of business is to
* split 's' on the '=' into 'name' and 'value' */
value = strchr(name, '=');
- if (value==0 && ++value==0) {
+ if (value == NULL && ++value == NULL) {
free(name);
return -1;
}
@@ -2258,13 +2195,13 @@ int set_local_var(const char *s, int flg_export)
result = -1;
} else {
cur->name = strdup(name);
- if(cur->name == 0) {
+ if (cur->name == NULL) {
free(cur);
result = -1;
} else {
struct variables *bottom = top_vars;
cur->value = strdup(value);
- cur->next = 0;
+ cur->next = NULL;
cur->flg_export = flg_export;
cur->flg_read_only = 0;
while(bottom->next) bottom=bottom->next;
@@ -2297,7 +2234,7 @@ void unset_local_var(const char *name)
if(strcmp(cur->name, name)==0)
break;
}
- if(cur!=0) {
+ if (cur != NULL) {
struct variables *next = top_vars;
if(cur->flg_read_only) {
error_msg("%s: readonly variable", name);
@@ -2380,7 +2317,8 @@ static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
}
#endif
-struct pipe *new_pipe(void) {
+static struct pipe *new_pipe(void)
+{
struct pipe *pi;
pi = xmalloc(sizeof(struct pipe));
pi->num_progs = 0;
@@ -2438,7 +2376,7 @@ static struct reserved_combo reserved_list[] = {
};
#define NRES (sizeof(reserved_list)/sizeof(struct reserved_combo))
-int reserved_word(o_string *dest, struct p_context *ctx)
+static int reserved_word(o_string *dest, struct p_context *ctx)
{
struct reserved_combo *r;
for (r=reserved_list;
@@ -2796,13 +2734,50 @@ static int parse_group(o_string *dest, struct p_context *ctx,
static char *lookup_param(char *src)
{
char *p;
+ char *sep;
+ char *default_val = NULL;
+ int assign = 0;
+ int expand_empty = 0;
if (!src)
return NULL;
- p = getenv(src);
- if (!p)
- p = get_local_var(src);
+ sep = strchr(src, ':');
+
+ if (sep) {
+ *sep = '\0';
+ if (*(sep + 1) == '-')
+ default_val = sep+2;
+ if (*(sep + 1) == '=') {
+ default_val = sep+2;
+ assign = 1;
+ }
+ if (*(sep + 1) == '+') {
+ default_val = sep+2;
+ expand_empty = 1;
+ }
+ }
+
+ p = getenv(src);
+ if (!p)
+ p = get_local_var(src);
+
+ if (!p || strlen(p) == 0) {
+ p = default_val;
+ if (assign) {
+ char *var = malloc(strlen(src)+strlen(default_val)+2);
+ if (var) {
+ sprintf(var, "%s=%s", src, default_val);
+ set_local_var(var, 0);
+ }
+ free(var);
+ }
+ } else if (expand_empty) {
+ p += strlen(p);
+ }
+
+ if (sep)
+ *sep = ':';
return p;
}
@@ -2938,8 +2913,8 @@ int parse_string(o_string *dest, struct p_context *ctx, const char *src)
#endif
/* return code is 0 for normal exit, 1 for syntax error */
-int parse_stream(o_string *dest, struct p_context *ctx,
- struct in_str *input, int end_trigger)
+static int parse_stream(o_string *dest, struct p_context *ctx,
+ struct in_str *input, int end_trigger)
{
unsigned int ch, m;
#ifndef __U_BOOT__
@@ -3104,6 +3079,21 @@ int parse_stream(o_string *dest, struct p_context *ctx,
return 1;
break;
#endif
+ case SUBSTED_VAR_SYMBOL:
+ dest->nonnull = 1;
+ while (ch = b_getch(input), ch != EOF &&
+ ch != SUBSTED_VAR_SYMBOL) {
+ debug_printf("subst, pass=%d\n", ch);
+ if (input->__promptme == 0)
+ return 1;
+ b_addchr(dest, ch);
+ }
+ debug_printf("subst, term=%d\n", ch);
+ if (ch == EOF) {
+ syntax();
+ return 1;
+ }
+ break;
default:
syntax(); /* this is really an internal logic error */
return 1;
@@ -3123,13 +3113,13 @@ int parse_stream(o_string *dest, struct p_context *ctx,
return 0;
}
-void mapset(const unsigned char *set, int code)
+static void mapset(const unsigned char *set, int code)
{
const unsigned char *s;
for (s=set; *s; s++) map[*s] = code;
}
-void update_ifs_map(void)
+static void update_ifs_map(void)
{
/* char *ifs and char map[256] are both globals. */
ifs = (uchar *)getenv("IFS");
@@ -3145,6 +3135,10 @@ void update_ifs_map(void)
mapset((uchar *)"\\$'\"`", 3); /* never flow through */
mapset((uchar *)"<>;&|(){}#", 1); /* flow through if quoted */
#else
+ {
+ uchar subst[2] = {SUBSTED_VAR_SYMBOL, 0};
+ mapset(subst, 3); /* never flow through */
+ }
mapset((uchar *)"\\$'\"", 3); /* never flow through */
mapset((uchar *)";&|#", 1); /* flow through if quoted */
#endif
@@ -3153,7 +3147,7 @@ void update_ifs_map(void)
/* most recursion does not come through here, the exeception is
* from builtin_source() */
-int parse_stream_outer(struct in_str *inp, int flag)
+static int parse_stream_outer(struct in_str *inp, int flag)
{
struct p_context ctx;
@@ -3224,7 +3218,7 @@ int parse_stream_outer(struct in_str *inp, int flag)
#ifndef __U_BOOT__
static int parse_string_outer(const char *s, int flag)
#else
-int parse_string_outer(char *s, int flag)
+int parse_string_outer(const char *s, int flag)
#endif /* __U_BOOT__ */
{
struct in_str input;
@@ -3287,7 +3281,7 @@ int u_boot_hush_start(void)
top_vars = malloc(sizeof(struct variables));
top_vars->name = "HUSH_VERSION";
top_vars->value = "0.01";
- top_vars->next = 0;
+ top_vars->next = NULL;
top_vars->flg_export = 0;
top_vars->flg_read_only = 1;
#ifdef CONFIG_NEEDS_MANUAL_RELOC
@@ -3484,25 +3478,57 @@ final_return:
static char *insert_var_value(char *inp)
{
+ return insert_var_value_sub(inp, 0);
+}
+
+static char *insert_var_value_sub(char *inp, int tag_subst)
+{
int res_str_len = 0;
int len;
int done = 0;
char *p, *p1, *res_str = NULL;
while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
+ /* check the beginning of the string for normal charachters */
if (p != inp) {
+ /* copy any charachters to the result string */
len = p - inp;
res_str = xrealloc(res_str, (res_str_len + len));
strncpy((res_str + res_str_len), inp, len);
res_str_len += len;
}
inp = ++p;
+ /* find the ending marker */
p = strchr(inp, SPECIAL_VAR_SYMBOL);
*p = '\0';
+ /* look up the value to substitute */
if ((p1 = lookup_param(inp))) {
- len = res_str_len + strlen(p1);
+ if (tag_subst)
+ len = res_str_len + strlen(p1) + 2;
+ else
+ len = res_str_len + strlen(p1);
res_str = xrealloc(res_str, (1 + len));
- strcpy((res_str + res_str_len), p1);
+ if (tag_subst) {
+ /*
+ * copy the variable value to the result
+ * string
+ */
+ strcpy((res_str + res_str_len + 1), p1);
+
+ /*
+ * mark the replaced text to be accepted as
+ * is
+ */
+ res_str[res_str_len] = SUBSTED_VAR_SYMBOL;
+ res_str[res_str_len + 1 + strlen(p1)] =
+ SUBSTED_VAR_SYMBOL;
+ } else
+ /*
+ * copy the variable value to the result
+ * string
+ */
+ strcpy((res_str + res_str_len), p1);
+
res_str_len = len;
}
*p = SPECIAL_VAR_SYMBOL;
@@ -3566,9 +3592,14 @@ static char * make_string(char ** inp)
char *str = NULL;
int n;
int len = 2;
+ char *noeval_str;
+ int noeval = 0;
+ noeval_str = get_local_var("HUSH_NO_EVAL");
+ if (noeval_str != NULL && *noeval_str != '0' && *noeval_str != '\0')
+ noeval = 1;
for (n = 0; inp[n]; n++) {
- p = insert_var_value(inp[n]);
+ p = insert_var_value_sub(inp[n], noeval);
str = xrealloc(str, (len + strlen(p)));
if (n) {
strcat(str, " ");
@@ -3586,7 +3617,8 @@ static char * make_string(char ** inp)
}
#ifdef __U_BOOT__
-int do_showvar (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int do_showvar(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
{
int i, k;
int rcode = 0;
diff --git a/common/image.c b/common/image.c
index 68a4a9e2f3..d5d30b7b0d 100644
--- a/common/image.c
+++ b/common/image.c
@@ -409,11 +409,11 @@ static const image_header_t *image_get_ramdisk (ulong rd_addr, uint8_t arch,
/* Shared dual-format routines */
/*****************************************************************************/
#ifndef USE_HOSTCC
-int getenv_yesno (char *var)
-{
- char *s = getenv (var);
- return (s && (*s == 'n')) ? 0 : 1;
-}
+//int getenv_yesno (char *var)
+//{
+// char *s = getenv (var);
+// return (s && (*s == 'n')) ? 0 : 1;
+//}
ulong getenv_bootm_low(void)
{
diff --git a/common/iomux.c b/common/iomux.c
index 91d98e9835..cf4da45707 100644
--- a/common/iomux.c
+++ b/common/iomux.c
@@ -2,23 +2,7 @@
* (C) Copyright 2008
* Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
@@ -135,18 +119,6 @@ int iomux_doenv(const int console, const char *arg)
*/
if (console_assign(console, start[j]) < 0)
continue;
-#ifdef CONFIG_SERIAL_MULTI
- /*
- * This was taken from common/cmd_nvedit.c.
- * This will never work because serial_assign() returns
- * 1 upon error, not -1.
- * This would almost always return an error anyway because
- * serial_assign() expects the name of a serial device, like
- * serial_smc, but the user generally only wants to set serial.
- */
- if (serial_assign(start[j]) < 0)
- continue;
-#endif
cons_set[cs_idx++] = dev;
}
free(console_args);
diff --git a/common/main.c b/common/main.c
index d97ccd7dd8..ae37fee46d 100644
--- a/common/main.c
+++ b/common/main.c
@@ -6,43 +6,23 @@
* (C) Copyright 2005
* JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
/* #define DEBUG */
#include <common.h>
-#include <watchdog.h>
#include <command.h>
-#ifdef CONFIG_MODEM_SUPPORT
-#include <malloc.h> /* for free() prototype */
-#endif
-
-#ifdef CONFIG_SYS_HUSH_PARSER
+#include <fdtdec.h>
#include <hush.h>
-#endif
-
+#include <malloc.h>
+#include <menu.h>
#include <post.h>
+#include <version.h>
+#include <watchdog.h>
+#include <linux/ctype.h>
-#if defined(CONFIG_SILENT_CONSOLE) || defined(CONFIG_POST) || defined(CONFIG_CMDLINE_EDITING)
DECLARE_GLOBAL_DATA_PTR;
-#endif
/*
* Board-specific Platform code can reimplement show_boot_progress () if needed
@@ -50,29 +30,24 @@ DECLARE_GLOBAL_DATA_PTR;
void inline __show_boot_progress (int val) {}
void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
-#if defined(CONFIG_BOOT_RETRY_TIME) && defined(CONFIG_RESET_TO_RETRY)
-extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); /* for do_reset() prototype */
-#endif
+#define MAX_DELAY_STOP_STR 32
-extern int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#define DEBUG_PARSER 0 /* set to 1 to debug */
-#if defined(CONFIG_UPDATE_TFTP)
-void update_tftp (void);
-#endif /* CONFIG_UPDATE_TFTP */
+#define debug_parser(fmt, args...) \
+ debug_cond(DEBUG_PARSER, fmt, ##args)
-#define MAX_DELAY_STOP_STR 32
-
-#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
-static int abortboot(int);
+#ifndef DEBUG_BOOTKEYS
+#define DEBUG_BOOTKEYS 0
#endif
-
-#undef DEBUG_PARSER
+#define debug_bootkeys(fmt, args...) \
+ debug_cond(DEBUG_BOOTKEYS, fmt, ##args)
char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */
static char * delete_char (char *buffer, char *p, int *colp, int *np, int plen);
-static char erase_seq[] = "\b \b"; /* erase sequence */
-static char tab_seq[] = " "; /* used to expand TABs */
+static const char erase_seq[] = "\b \b"; /* erase sequence */
+static const char tab_seq[] = " "; /* used to expand TABs */
#ifdef CONFIG_BOOT_RETRY_TIME
static uint64_t endtime = 0; /* must be set, default is instant timeout */
@@ -92,12 +67,11 @@ extern void mdm_init(void); /* defined in board.c */
/***************************************************************************
* Watch for 'delay' seconds for autoboot stop or autoboot delay string.
- * returns: 0 - no key string, allow autoboot
- * 1 - got key string, abort
+ * returns: 0 - no key string, allow autoboot 1 - got key string, abort
*/
-#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+#if defined(CONFIG_BOOTDELAY)
# if defined(CONFIG_AUTOBOOT_KEYED)
-static __inline__ int abortboot(int bootdelay)
+static int abortboot_keyed(int bootdelay)
{
int abort = 0;
uint64_t etime = endtick(bootdelay);
@@ -118,6 +92,11 @@ static __inline__ int abortboot(int bootdelay)
u_int presskey_max = 0;
u_int i;
+#ifndef CONFIG_ZERO_BOOTDELAY_CHECK
+ if (bootdelay == 0)
+ return 0;
+#endif
+
# ifdef CONFIG_AUTOBOOT_PROMPT
printf(CONFIG_AUTOBOOT_PROMPT);
# endif
@@ -148,11 +127,9 @@ static __inline__ int abortboot(int bootdelay)
presskey_max = presskey_max > delaykey[i].len ?
presskey_max : delaykey[i].len;
-# if DEBUG_BOOTKEYS
- printf("%s key:<%s>\n",
- delaykey[i].retry ? "delay" : "stop",
- delaykey[i].str ? delaykey[i].str : "NULL");
-# endif
+ debug_bootkeys("%s key:<%s>\n",
+ delaykey[i].retry ? "delay" : "stop",
+ delaykey[i].str ? delaykey[i].str : "NULL");
}
/* In order to keep up with incoming data, check timeout only
@@ -177,10 +154,9 @@ static __inline__ int abortboot(int bootdelay)
memcmp (presskey + presskey_len - delaykey[i].len,
delaykey[i].str,
delaykey[i].len) == 0) {
-# if DEBUG_BOOTKEYS
- printf("got %skey\n",
- delaykey[i].retry ? "delay" : "stop");
-# endif
+ debug_bootkeys("got %skey\n",
+ delaykey[i].retry ? "delay" :
+ "stop");
# ifdef CONFIG_BOOT_RETRY_TIME
/* don't retry auto boot */
@@ -192,10 +168,8 @@ static __inline__ int abortboot(int bootdelay)
}
} while (!abort && get_ticks() <= etime);
-# if DEBUG_BOOTKEYS
if (!abort)
- puts("key timeout\n");
-# endif
+ debug_bootkeys("key timeout\n");
#ifdef CONFIG_SILENT_CONSOLE
if (abort)
@@ -211,14 +185,16 @@ static __inline__ int abortboot(int bootdelay)
static int menukey = 0;
#endif
-static __inline__ int abortboot(int bootdelay)
+static int abortboot_normal(int bootdelay)
{
int abort = 0;
+ unsigned long ts;
#ifdef CONFIG_MENUPROMPT
printf(CONFIG_MENUPROMPT);
#else
- printf("Hit any key to stop autoboot: %2d ", bootdelay);
+ if (bootdelay >= 0)
+ printf("Hit any key to stop autoboot: %2d ", bootdelay);
#endif
#if defined CONFIG_ZERO_BOOTDELAY_CHECK
@@ -236,11 +212,10 @@ static __inline__ int abortboot(int bootdelay)
#endif
while ((bootdelay > 0) && (!abort)) {
- int i;
-
--bootdelay;
- /* delay 100 * 10ms */
- for (i=0; !abort && i<100; ++i) {
+ /* delay 1000 ms */
+ ts = get_timer(0);
+ do {
if (tstc()) { /* we got a key press */
abort = 1; /* don't auto boot */
bootdelay = 0; /* no more delay */
@@ -252,7 +227,7 @@ static __inline__ int abortboot(int bootdelay)
break;
}
udelay(10000);
- }
+ } while (!abort && get_timer(ts) < 1000);
printf("\b\b\b%2d ", bootdelay);
}
@@ -267,114 +242,116 @@ static __inline__ int abortboot(int bootdelay)
return abort;
}
# endif /* CONFIG_AUTOBOOT_KEYED */
-#endif /* CONFIG_BOOTDELAY >= 0 */
-
-/****************************************************************************/
-void main_loop (void)
+static int abortboot(int bootdelay)
{
-#ifndef CONFIG_SYS_HUSH_PARSER
- static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
- int len;
- int rc = 1;
- int flag;
-#endif
-
-#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
- char *s;
- int bootdelay;
-#endif
-#ifdef CONFIG_PREBOOT
- char *p;
+#ifdef CONFIG_AUTOBOOT_KEYED
+ return abortboot_keyed(bootdelay);
+#else
+ return abortboot_normal(bootdelay);
#endif
-#ifdef CONFIG_BOOTCOUNT_LIMIT
- unsigned long bootcount = 0;
- unsigned long bootlimit = 0;
- char *bcs;
- char bcs_set[16];
-#endif /* CONFIG_BOOTCOUNT_LIMIT */
-
-#if defined(CONFIG_VFD) && defined(VFD_TEST_LOGO)
- ulong bmp = 0; /* default bitmap */
- extern int trab_vfd (ulong bitmap);
+}
+#endif /* CONFIG_BOOTDELAY */
-#ifdef CONFIG_MODEM_SUPPORT
- if (do_mdm_init)
- bmp = 1; /* alternate bitmap */
-#endif
- trab_vfd (bmp);
-#endif /* CONFIG_VFD && VFD_TEST_LOGO */
+/*
+ * Runs the given boot command securely. Specifically:
+ * - Doesn't run the command with the shell (run_command or parse_string_outer),
+ * since that's a lot of code surface that an attacker might exploit.
+ * Because of this, we don't do any argument parsing--the secure boot command
+ * has to be a full-fledged u-boot command.
+ * - Doesn't check for keypresses before booting, since that could be a
+ * security hole; also disables Ctrl-C.
+ * - Doesn't allow the command to return.
+ *
+ * Upon any failures, this function will drop into an infinite loop after
+ * printing the error message to console.
+ */
-#ifdef CONFIG_BOOTCOUNT_LIMIT
- bootcount = bootcount_load();
- bootcount++;
- bootcount_store (bootcount);
- sprintf (bcs_set, "%lu", bootcount);
- setenv ("bootcount", bcs_set);
- bcs = getenv ("bootlimit");
- bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
-#endif /* CONFIG_BOOTCOUNT_LIMIT */
+#if defined(CONFIG_BOOTDELAY) && defined(CONFIG_OF_CONTROL)
+static void secure_boot_cmd(char *cmd)
+{
+ cmd_tbl_t *cmdtp;
+ int rc;
-#ifdef CONFIG_MODEM_SUPPORT
- debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
- if (do_mdm_init) {
- char *str = strdup(getenv("mdm_cmd"));
- setenv ("preboot", str); /* set or delete definition */
- if (str != NULL)
- free (str);
- mdm_init(); /* wait for modem connection */
+ if (!cmd) {
+ printf("## Error: Secure boot command not specified\n");
+ goto err;
}
-#endif /* CONFIG_MODEM_SUPPORT */
-#ifdef CONFIG_VERSION_VARIABLE
- {
- extern char version_string[];
+ /* Disable Ctrl-C just in case some command is used that checks it. */
+ disable_ctrlc(1);
- setenv ("ver", version_string); /* set version variable */
+ /* Find the command directly. */
+ cmdtp = find_cmd(cmd);
+ if (!cmdtp) {
+ printf("## Error: \"%s\" not defined\n", cmd);
+ goto err;
}
-#endif /* CONFIG_VERSION_VARIABLE */
-#ifdef CONFIG_SYS_HUSH_PARSER
- u_boot_hush_start ();
-#endif
+ /* Run the command, forcing no flags and faking argc and argv. */
+ rc = (cmdtp->cmd)(cmdtp, 0, 1, &cmd);
-#if defined(CONFIG_HUSH_INIT_VAR)
- hush_init_var ();
-#endif
+ /* Shouldn't ever return from boot command. */
+ printf("## Error: \"%s\" returned (code %d)\n", cmd, rc);
-#ifdef CONFIG_AUTO_COMPLETE
- install_auto_complete();
-#endif
+err:
+ /*
+ * Not a whole lot to do here. Rebooting won't help much, since we'll
+ * just end up right back here. Just loop.
+ */
+ hang();
+}
-#ifdef CONFIG_PREBOOT
- if ((p = getenv ("preboot")) != NULL) {
-# ifdef CONFIG_AUTOBOOT_KEYED
- int prev = disable_ctrlc(1); /* disable Control C checking */
-# endif
+static void process_fdt_options(const void *blob)
+{
+ ulong addr;
-# ifndef CONFIG_SYS_HUSH_PARSER
- run_command (p, 0);
-# else
- parse_string_outer(p, FLAG_PARSE_SEMICOLON |
- FLAG_EXIT_FROM_LOOP);
-# endif
+ /* Add an env variable to point to a kernel payload, if available */
+ addr = fdtdec_get_config_int(gd->fdt_blob, "kernel-offset", 0);
+ if (addr)
+ setenv_addr("kernaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
-# ifdef CONFIG_AUTOBOOT_KEYED
- disable_ctrlc(prev); /* restore Control C checking */
-# endif
- }
-#endif /* CONFIG_PREBOOT */
+ /* Add an env variable to point to a root disk, if available */
+ addr = fdtdec_get_config_int(gd->fdt_blob, "rootdisk-offset", 0);
+ if (addr)
+ setenv_addr("rootaddr", (void *)(CONFIG_SYS_TEXT_BASE + addr));
+}
+#endif /* CONFIG_OF_CONTROL */
-#if defined(CONFIG_UPDATE_TFTP)
- update_tftp ();
-#endif /* CONFIG_UPDATE_TFTP */
+#ifdef CONFIG_BOOTDELAY
+static void process_boot_delay(void)
+{
+#ifdef CONFIG_OF_CONTROL
+ char *env;
+#endif
+ char *s;
+ int bootdelay;
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+ unsigned long bootcount = 0;
+ unsigned long bootlimit = 0;
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
+
+#ifdef CONFIG_BOOTCOUNT_LIMIT
+ bootcount = bootcount_load();
+ bootcount++;
+ bootcount_store (bootcount);
+ setenv_ulong("bootcount", bootcount);
+ bootlimit = getenv_ulong("bootlimit", 10, 0);
+#endif /* CONFIG_BOOTCOUNT_LIMIT */
-#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
+#ifdef CONFIG_OF_CONTROL
+ bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay",
+ bootdelay);
+#endif
+
debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
+#if defined(CONFIG_MENU_SHOW)
+ bootdelay = menu_show(bootdelay);
+#endif
# ifdef CONFIG_BOOT_RETRY_TIME
init_cmd_timeout ();
# endif /* CONFIG_BOOT_RETRY_TIME */
@@ -394,41 +371,109 @@ void main_loop (void)
else
#endif /* CONFIG_BOOTCOUNT_LIMIT */
s = getenv ("bootcmd");
+#ifdef CONFIG_OF_CONTROL
+ /* Allow the fdt to override the boot command */
+ env = fdtdec_get_config_string(gd->fdt_blob, "bootcmd");
+ if (env)
+ s = env;
+
+ process_fdt_options(gd->fdt_blob);
+
+ /*
+ * If the bootsecure option was chosen, use secure_boot_cmd().
+ * Always use 'env' in this case, since bootsecure requres that the
+ * bootcmd was specified in the FDT too.
+ */
+ if (fdtdec_get_config_int(gd->fdt_blob, "bootsecure", 0))
+ secure_boot_cmd(env);
+
+#endif /* CONFIG_OF_CONTROL */
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
- if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
-# ifdef CONFIG_AUTOBOOT_KEYED
+ if (bootdelay != -1 && s && !abortboot(bootdelay)) {
+#ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1); /* disable Control C checking */
-# endif
+#endif
-# ifndef CONFIG_SYS_HUSH_PARSER
- run_command (s, 0);
-# else
- parse_string_outer(s, FLAG_PARSE_SEMICOLON |
- FLAG_EXIT_FROM_LOOP);
-# endif
+ run_command_list(s, -1, 0);
-# ifdef CONFIG_AUTOBOOT_KEYED
+#ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev); /* restore Control C checking */
-# endif
+#endif
}
-# ifdef CONFIG_MENUKEY
+#ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) {
- s = getenv("menucmd");
- if (s) {
-# ifndef CONFIG_SYS_HUSH_PARSER
- run_command (s, 0);
-# else
- parse_string_outer(s, FLAG_PARSE_SEMICOLON |
- FLAG_EXIT_FROM_LOOP);
-# endif
- }
+ s = getenv("menucmd");
+ if (s)
+ run_command_list(s, -1, 0);
}
#endif /* CONFIG_MENUKEY */
+}
#endif /* CONFIG_BOOTDELAY */
+void main_loop(void)
+{
+#ifndef CONFIG_SYS_HUSH_PARSER
+ static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
+ int len;
+ int rc = 1;
+ int flag;
+#endif
+#ifdef CONFIG_PREBOOT
+ char *p;
+#endif
+
+ bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");
+
+#ifdef CONFIG_MODEM_SUPPORT
+ debug("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init);
+ if (do_mdm_init) {
+ char *str = strdup(getenv("mdm_cmd"));
+ setenv("preboot", str); /* set or delete definition */
+ if (str != NULL)
+ free(str);
+ mdm_init(); /* wait for modem connection */
+ }
+#endif /* CONFIG_MODEM_SUPPORT */
+
+#ifdef CONFIG_VERSION_VARIABLE
+ {
+ setenv("ver", version_string); /* set version variable */
+ }
+#endif /* CONFIG_VERSION_VARIABLE */
+
+#ifdef CONFIG_SYS_HUSH_PARSER
+ u_boot_hush_start();
+#endif
+
+#if defined(CONFIG_HUSH_INIT_VAR)
+ hush_init_var();
+#endif
+
+#ifdef CONFIG_PREBOOT
+ p = getenv("preboot");
+ if (p != NULL) {
+# ifdef CONFIG_AUTOBOOT_KEYED
+ int prev = disable_ctrlc(1); /* disable Control C checking */
+# endif
+
+ run_command_list(p, -1, 0);
+
+# ifdef CONFIG_AUTOBOOT_KEYED
+ disable_ctrlc(prev); /* restore Control C checking */
+# endif
+ }
+#endif /* CONFIG_PREBOOT */
+
+#if defined(CONFIG_UPDATE_TFTP)
+ update_tftp(0UL);
+#endif /* CONFIG_UPDATE_TFTP */
+
+#ifdef CONFIG_BOOTDELAY
+ process_boot_delay();
+#endif
/*
* Main Loop for Monitor Command Processing
*/
@@ -470,7 +515,7 @@ void main_loop (void)
if (len == -1)
puts ("<INTERRUPT>\n");
else
- rc = run_command (lastcommand, flag);
+ rc = run_command(lastcommand, flag);
if (rc <= 0) {
/* invalid command or not repeatable, forget it */
@@ -530,13 +575,13 @@ void reset_cmd_timeout(void)
#define HIST_MAX 20
#define HIST_SIZE CONFIG_SYS_CBSIZE
-static int hist_max = 0;
-static int hist_add_idx = 0;
+static int hist_max;
+static int hist_add_idx;
static int hist_cur = -1;
-unsigned hist_num = 0;
+static unsigned hist_num;
-char* hist_list[HIST_MAX];
-char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
+static char *hist_list[HIST_MAX];
+static char hist_lines[HIST_MAX][HIST_SIZE + 1]; /* Save room for NULL */
#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
@@ -699,7 +744,8 @@ static void cread_add_str(char *str, int strsize, int insert, unsigned long *num
}
}
-static int cread_line(const char *const prompt, char *buf, unsigned int *len)
+static int cread_line(const char *const prompt, char *buf, unsigned int *len,
+ int timeout)
{
unsigned long num = 0;
unsigned long eol_num = 0;
@@ -709,6 +755,7 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len)
int esc_len = 0;
char esc_save[8];
int init_len = strlen(buf);
+ int first = 1;
if (init_len)
cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
@@ -721,6 +768,16 @@ static int cread_line(const char *const prompt, char *buf, unsigned int *len)
WATCHDOG_RESET();
}
#endif
+ if (first && timeout) {
+ uint64_t etime = endtick(timeout);
+
+ while (!tstc()) { /* while no incoming data */
+ if (get_ticks() >= etime)
+ return -2; /* timed out */
+ WATCHDOG_RESET();
+ }
+ first = 0;
+ }
ichar = getcmd_getch();
@@ -936,11 +993,11 @@ int readline (const char *const prompt)
*/
console_buffer[0] = '\0';
- return readline_into_buffer(prompt, console_buffer);
+ return readline_into_buffer(prompt, console_buffer, 0);
}
-int readline_into_buffer (const char *const prompt, char * buffer)
+int readline_into_buffer(const char *const prompt, char *buffer, int timeout)
{
char *p = buffer;
#ifdef CONFIG_CMDLINE_EDITING
@@ -963,7 +1020,7 @@ int readline_into_buffer (const char *const prompt, char * buffer)
if (prompt)
puts (prompt);
- rc = cread_line(prompt, p, &len);
+ rc = cread_line(prompt, p, &len, timeout);
return rc < 0 ? rc : len;
} else {
@@ -993,7 +1050,6 @@ int readline_into_buffer (const char *const prompt, char * buffer)
#ifdef CONFIG_SHOW_ACTIVITY
while (!tstc()) {
- extern void show_activity(int arg);
show_activity(0);
WATCHDOG_RESET();
}
@@ -1004,20 +1060,20 @@ int readline_into_buffer (const char *const prompt, char * buffer)
* Special character handling
*/
switch (c) {
- case '\r': /* Enter */
+ case '\r': /* Enter */
case '\n':
*p = '\0';
puts ("\r\n");
- return (p - p_buf);
+ return p - p_buf;
- case '\0': /* nul */
+ case '\0': /* nul */
continue;
- case 0x03: /* ^C - break */
+ case 0x03: /* ^C - break */
p_buf[0] = '\0'; /* discard input */
- return (-1);
+ return -1;
- case 0x15: /* ^U - erase line */
+ case 0x15: /* ^U - erase line */
while (col > plen) {
puts (erase_seq);
--col;
@@ -1026,15 +1082,15 @@ int readline_into_buffer (const char *const prompt, char * buffer)
n = 0;
continue;
- case 0x17: /* ^W - erase word */
+ case 0x17: /* ^W - erase word */
p=delete_char(p_buf, p, &col, &n, plen);
while ((n > 0) && (*p != ' ')) {
p=delete_char(p_buf, p, &col, &n, plen);
}
continue;
- case 0x08: /* ^H - backspace */
- case 0x7F: /* DEL - backspace */
+ case 0x08: /* ^H - backspace */
+ case 0x7F: /* DEL - backspace */
p=delete_char(p_buf, p, &col, &n, plen);
continue;
@@ -1043,7 +1099,7 @@ int readline_into_buffer (const char *const prompt, char * buffer)
* Must be a normal character then
*/
if (n < CONFIG_SYS_CBSIZE-2) {
- if (c == '\t') { /* expand TABs */
+ if (c == '\t') { /* expand TABs */
#ifdef CONFIG_AUTO_COMPLETE
/* if auto completion triggered just continue */
*p = '\0';
@@ -1055,8 +1111,16 @@ int readline_into_buffer (const char *const prompt, char * buffer)
puts (tab_seq+(col&07));
col += 8 - (col&07);
} else {
- ++col; /* echo input */
- putc (c);
+ char buf[2];
+
+ /*
+ * Echo input using puts() to force an
+ * LCD flush if we are using an LCD
+ */
+ ++col;
+ buf[0] = c;
+ buf[1] = '\0';
+ puts(buf);
}
*p++ = c;
++n;
@@ -1108,37 +1172,29 @@ int parse_line (char *line, char *argv[])
{
int nargs = 0;
-#ifdef DEBUG_PARSER
- printf ("parse_line: \"%s\"\n", line);
-#endif
+ debug_parser("parse_line: \"%s\"\n", line);
while (nargs < CONFIG_SYS_MAXARGS) {
/* skip any white space */
- while ((*line == ' ') || (*line == '\t')) {
+ while (isblank(*line))
++line;
- }
if (*line == '\0') { /* end of line, no more args */
argv[nargs] = NULL;
-#ifdef DEBUG_PARSER
- printf ("parse_line: nargs=%d\n", nargs);
-#endif
- return (nargs);
+ debug_parser("parse_line: nargs=%d\n", nargs);
+ return nargs;
}
argv[nargs++] = line; /* begin of argument string */
/* find end of string */
- while (*line && (*line != ' ') && (*line != '\t')) {
+ while (*line && !isblank(*line))
++line;
- }
if (*line == '\0') { /* end of line, no more args */
argv[nargs] = NULL;
-#ifdef DEBUG_PARSER
- printf ("parse_line: nargs=%d\n", nargs);
-#endif
- return (nargs);
+ debug_parser("parse_line: nargs=%d\n", nargs);
+ return nargs;
}
*line++ = '\0'; /* terminate current arg */
@@ -1146,14 +1202,13 @@ int parse_line (char *line, char *argv[])
printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS);
-#ifdef DEBUG_PARSER
- printf ("parse_line: nargs=%d\n", nargs);
-#endif
+ debug_parser("parse_line: nargs=%d\n", nargs);
return (nargs);
}
/****************************************************************************/
+#ifndef CONFIG_SYS_HUSH_PARSER
static void process_macros (const char *input, char *output)
{
char c, prev;
@@ -1165,12 +1220,10 @@ static void process_macros (const char *input, char *output)
/* 1 = waiting for '(' or '{' */
/* 2 = waiting for ')' or '}' */
/* 3 = waiting for ''' */
-#ifdef DEBUG_PARSER
char *output_start = output;
- printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input),
- input);
-#endif
+ debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input),
+ input);
prev = '\0'; /* previous character */
@@ -1258,10 +1311,8 @@ static void process_macros (const char *input, char *output)
else
*(output - 1) = 0;
-#ifdef DEBUG_PARSER
- printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
- strlen (output_start), output_start);
-#endif
+ debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n",
+ strlen(output_start), output_start);
}
/****************************************************************************
@@ -1280,10 +1331,8 @@ static void process_macros (const char *input, char *output)
* the environment data, which may change magicly when the command we run
* creates or modifies environment variables (like "bootp" does).
*/
-
-int run_command (const char *cmd, int flag)
+static int builtin_run_command(const char *cmd, int flag)
{
- cmd_tbl_t *cmdtp;
char cmdbuf[CONFIG_SYS_CBSIZE]; /* working copy of cmd */
char *token; /* start of token in cmdbuf */
char *sep; /* end of token (separator) in cmdbuf */
@@ -1294,12 +1343,12 @@ int run_command (const char *cmd, int flag)
int repeatable = 1;
int rc = 0;
-#ifdef DEBUG_PARSER
- printf ("[RUN_COMMAND] cmd[%p]=\"", cmd);
- puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */
- puts ("\"\n");
-#endif
-
+ debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd);
+ if (DEBUG_PARSER) {
+ /* use puts - string may be loooong */
+ puts(cmd ? cmd : "NULL");
+ puts("\"\n");
+ }
clear_ctrlc(); /* forget any previous Control C */
if (!cmd || !*cmd) {
@@ -1317,9 +1366,7 @@ int run_command (const char *cmd, int flag)
* repeatable commands
*/
-#ifdef DEBUG_PARSER
- printf ("[PROCESS_SEPARATORS] %s\n", cmd);
-#endif
+ debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
while (*str) {
/*
@@ -1348,9 +1395,7 @@ int run_command (const char *cmd, int flag)
}
else
str = sep; /* no more commands for next pass */
-#ifdef DEBUG_PARSER
- printf ("token: \"%s\"\n", token);
-#endif
+ debug_parser("token: \"%s\"\n", token);
/* find macros in this token and replace them */
process_macros (token, finaltoken);
@@ -1361,49 +1406,124 @@ int run_command (const char *cmd, int flag)
continue;
}
- /* Look up command in command table */
- if ((cmdtp = find_cmd(argv[0])) == NULL) {
- printf ("Unknown command '%s' - try 'help'\n", argv[0]);
- rc = -1; /* give up after bad command */
- continue;
- }
-
- /* found - check max args */
- if (argc > cmdtp->maxargs) {
- cmd_usage(cmdtp);
+ if (cmd_process(flag, argc, argv, &repeatable, NULL))
rc = -1;
- continue;
- }
-#if defined(CONFIG_CMD_BOOTD)
- /* avoid "bootd" recursion */
- if (cmdtp->cmd == do_bootd) {
-#ifdef DEBUG_PARSER
- printf ("[%s]\n", finaltoken);
+ /* Did the user stop this? */
+ if (had_ctrlc ())
+ return -1; /* if stopped then not repeatable */
+ }
+
+ return rc ? rc : repeatable;
+}
#endif
- if (flag & CMD_FLAG_BOOTD) {
- puts ("'bootd' recursion detected\n");
- rc = -1;
- continue;
- } else {
- flag |= CMD_FLAG_BOOTD;
- }
- }
+
+/*
+ * Run a command using the selected parser.
+ *
+ * @param cmd Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command(const char *cmd, int flag)
+{
+#ifndef CONFIG_SYS_HUSH_PARSER
+ /*
+ * builtin_run_command can return 0 or 1 for success, so clean up
+ * its result.
+ */
+ if (builtin_run_command(cmd, flag) == -1)
+ return 1;
+
+ return 0;
+#else
+ return parse_string_outer(cmd,
+ FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP);
#endif
+}
- /* OK - call function to do the command */
- if ((cmdtp->cmd) (cmdtp, flag, argc, argv) != 0) {
- rc = -1;
+#ifndef CONFIG_SYS_HUSH_PARSER
+/**
+ * Execute a list of command separated by ; or \n using the built-in parser.
+ *
+ * This function cannot take a const char * for the command, since if it
+ * finds newlines in the string, it replaces them with \0.
+ *
+ * @param cmd String containing list of commands
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+static int builtin_run_command_list(char *cmd, int flag)
+{
+ char *line, *next;
+ int rcode = 0;
+
+ /*
+ * Break into individual lines, and execute each line; terminate on
+ * error.
+ */
+ line = next = cmd;
+ while (*next) {
+ if (*next == '\n') {
+ *next = '\0';
+ /* run only non-empty commands */
+ if (*line) {
+ debug("** exec: \"%s\"\n", line);
+ if (builtin_run_command(line, 0) < 0) {
+ rcode = 1;
+ break;
+ }
+ }
+ line = next + 1;
}
+ ++next;
+ }
+ if (rcode == 0 && *line)
+ rcode = (builtin_run_command(line, 0) >= 0);
- repeatable &= cmdtp->repeatable;
+ return rcode;
+}
+#endif
- /* Did the user stop this? */
- if (had_ctrlc ())
- return -1; /* if stopped then not repeatable */
+int run_command_list(const char *cmd, int len, int flag)
+{
+ int need_buff = 1;
+ char *buff = (char *)cmd; /* cast away const */
+ int rcode = 0;
+
+ if (len == -1) {
+ len = strlen(cmd);
+#ifdef CONFIG_SYS_HUSH_PARSER
+ /* hush will never change our string */
+ need_buff = 0;
+#else
+ /* the built-in parser will change our string if it sees \n */
+ need_buff = strchr(cmd, '\n') != NULL;
+#endif
+ }
+ if (need_buff) {
+ buff = malloc(len + 1);
+ if (!buff)
+ return 1;
+ memcpy(buff, cmd, len);
+ buff[len] = '\0';
}
+#ifdef CONFIG_SYS_HUSH_PARSER
+ rcode = parse_string_outer(buff, FLAG_PARSE_SEMICOLON);
+#else
+ /*
+ * This function will overwrite any \n it sees with a \0, which
+ * is why it can't work with a const char *. Here we are making
+ * using of internal knowledge of this function, to avoid always
+ * doing a malloc() which is actually required only in a case that
+ * is pretty rare.
+ */
+ rcode = builtin_run_command_list(buff, flag);
+ if (need_buff)
+ free(buff);
+#endif
- return rc ? rc : repeatable;
+ return rcode;
}
/****************************************************************************/
@@ -1414,7 +1534,7 @@ int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
int i;
if (argc < 2)
- return cmd_usage(cmdtp);
+ return CMD_RET_USAGE;
for (i=1; i<argc; ++i) {
char *arg;
@@ -1423,14 +1543,9 @@ int do_run (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
printf ("## Error: \"%s\" not defined\n", argv[i]);
return 1;
}
-#ifndef CONFIG_SYS_HUSH_PARSER
- if (run_command (arg, flag) == -1)
- return 1;
-#else
- if (parse_string_outer(arg,
- FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
+
+ if (run_command(arg, flag) != 0)
return 1;
-#endif
}
return 0;
}
diff --git a/common/stdio.c b/common/stdio.c
index ab7c5abde1..844f98c184 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -1,24 +1,12 @@
/*
- * (C) Copyright 2000
- * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
- *
- * See file CREDITS for list of people who contributed to this
- * project.
+ * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
+ * Changes for multibus/multiadapter I2C support.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * (C) Copyright 2000
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
@@ -30,7 +18,8 @@
#ifdef CONFIG_LOGBUFFER
#include <logbuff.h>
#endif
-#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
#include <i2c.h>
#endif
@@ -105,7 +94,7 @@ struct list_head* stdio_get_list(void)
return &(devs.list);
}
-struct stdio_dev* stdio_get_by_name(char* name)
+struct stdio_dev* stdio_get_by_name(const char *name)
{
struct list_head *pos;
struct stdio_dev *dev;
@@ -135,7 +124,6 @@ struct stdio_dev* stdio_clone(struct stdio_dev *dev)
return NULL;
memcpy(_dev, dev, sizeof(struct stdio_dev));
- strncpy(_dev->name, dev->name, 16);
return _dev;
}
@@ -155,12 +143,12 @@ int stdio_register (struct stdio_dev * dev)
* returns 0 if success, -1 if device is assigned and 1 if devname not found
*/
#ifdef CONFIG_SYS_STDIO_DEREGISTER
-int stdio_deregister(char *devname)
+int stdio_deregister(const char *devname)
{
int l;
struct list_head *pos;
struct stdio_dev *dev;
- char temp_names[3][8];
+ char temp_names[3][16];
dev = stdio_get_by_name(devname);
@@ -174,7 +162,7 @@ int stdio_deregister(char *devname)
}
memcpy (&temp_names[l][0],
stdio_devices[l]->name,
- sizeof(stdio_devices[l]->name));
+ sizeof(temp_names[l]));
}
list_del(&(dev->list));
@@ -208,12 +196,13 @@ int stdio_init (void)
/* Initialize the list */
INIT_LIST_HEAD(&(devs.list));
-#ifdef CONFIG_ARM_DCC_MULTI
- drv_arm_dcc_init ();
-#endif
-#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+#ifdef CONFIG_SYS_I2C
+ i2c_init_all();
+#else
+#if defined(CONFIG_HARD_I2C)
i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
+#endif
#ifdef CONFIG_LCD
drv_lcd_init ();
#endif
@@ -227,9 +216,7 @@ int stdio_init (void)
drv_logbuff_init ();
#endif
drv_system_init ();
-#ifdef CONFIG_SERIAL_MULTI
serial_stdio_init ();
-#endif
#ifdef CONFIG_USB_TTY
drv_usbtty_init ();
#endif
@@ -239,6 +226,8 @@ int stdio_init (void)
#ifdef CONFIG_JTAG_CONSOLE
drv_jtag_console_init ();
#endif
-
+#ifdef CONFIG_CBMEM_CONSOLE
+ cbmemc_init();
+#endif
return (0);
}
diff --git a/common/usb_kbd.c b/common/usb_kbd.c
index 9957dcc323..1ad67caf13 100644
--- a/common/usb_kbd.c
+++ b/common/usb_kbd.c
@@ -5,752 +5,549 @@
* Part of this source has been derived from the Linux USB
* project.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
+#include <malloc.h>
#include <stdio_dev.h>
#include <asm/byteorder.h>
#include <usb.h>
-#undef USB_KBD_DEBUG
/*
- * if overwrite_console returns 1, the stdin, stderr and stdout
+ * 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);
+extern int overwrite_console(void);
#else
-int overwrite_console (void)
+int overwrite_console(void)
{
- return (0);
+ return 0;
}
#endif
-#ifdef USB_KBD_DEBUG
-#define USB_KBD_PRINTF(fmt,args...) printf (fmt ,##args)
-#else
-#define USB_KBD_PRINTF(fmt,args...)
-#endif
-
-
-#define REPEAT_RATE 40/4 /* 40msec -> 25cps */
-#define REPEAT_DELAY 10 /* 10 x REAPEAT_RATE = 400msec */
+/* Keyboard sampling rate */
+#define REPEAT_RATE (40 / 4) /* 40msec -> 25cps */
+#define REPEAT_DELAY 10 /* 10 x REPEAT_RATE = 400msec */
#define NUM_LOCK 0x53
-#define CAPS_LOCK 0x39
-#define SCROLL_LOCK 0x47
-
+#define CAPS_LOCK 0x39
+#define SCROLL_LOCK 0x47
/* Modifier bits */
-#define LEFT_CNTR 0
-#define LEFT_SHIFT 1
-#define LEFT_ALT 2
-#define LEFT_GUI 3
-#define RIGHT_CNTR 4
-#define RIGHT_SHIFT 5
-#define RIGHT_ALT 6
-#define RIGHT_GUI 7
-
-#define USB_KBD_BUFFER_LEN 0x20 /* size of the keyboardbuffer */
-
-static volatile char usb_kbd_buffer[USB_KBD_BUFFER_LEN];
-static volatile int usb_in_pointer = 0;
-static volatile int usb_out_pointer = 0;
-
-unsigned char new[8];
-unsigned char old[8];
-int repeat_delay;
-#define DEVNAME "usbkbd"
-static unsigned char num_lock = 0;
-static unsigned char caps_lock = 0;
-static unsigned char scroll_lock = 0;
-static unsigned char ctrl = 0;
-
-static unsigned char leds __attribute__ ((aligned (0x4)));
-
-static unsigned char usb_kbd_numkey[] = {
- '1', '2', '3', '4', '5', '6', '7', '8', '9', '0','\r',0x1b,'\b','\t',' ', '-',
- '=', '[', ']','\\', '#', ';', '\'', '`', ',', '.', '/'
+#define LEFT_CNTR (1 << 0)
+#define LEFT_SHIFT (1 << 1)
+#define LEFT_ALT (1 << 2)
+#define LEFT_GUI (1 << 3)
+#define RIGHT_CNTR (1 << 4)
+#define RIGHT_SHIFT (1 << 5)
+#define RIGHT_ALT (1 << 6)
+#define RIGHT_GUI (1 << 7)
+
+/* Size of the keyboard buffer */
+#define USB_KBD_BUFFER_LEN 0x20
+
+/* Device name */
+#define DEVNAME "usbkbd"
+
+/* Keyboard maps */
+static const unsigned char usb_kbd_numkey[] = {
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+ '\r', 0x1b, '\b', '\t', ' ', '-', '=', '[', ']',
+ '\\', '#', ';', '\'', '`', ',', '.', '/'
};
-static unsigned char usb_kbd_numkey_shifted[] = {
- '!', '@', '#', '$', '%', '^', '&', '*', '(', ')','\r',0x1b,'\b','\t',' ', '_',
- '+', '{', '}', '|', '~', ':', '"', '~', '<', '>', '?'
+static const unsigned char usb_kbd_numkey_shifted[] = {
+ '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
+ '\r', 0x1b, '\b', '\t', ' ', '_', '+', '{', '}',
+ '|', '~', ':', '"', '~', '<', '>', '?'
};
-/******************************************************************
- * Queue handling
- ******************************************************************/
-/* puts character in the queue and sets up the in and out pointer */
-static void usb_kbd_put_queue(char data)
-{
- if((usb_in_pointer+1)==USB_KBD_BUFFER_LEN) {
- if(usb_out_pointer==0) {
- return; /* buffer full */
- } else{
- usb_in_pointer=0;
- }
- } else {
- if((usb_in_pointer+1)==usb_out_pointer)
- return; /* buffer full */
- usb_in_pointer++;
- }
- usb_kbd_buffer[usb_in_pointer]=data;
- return;
-}
+static const unsigned char usb_kbd_num_keypad[] = {
+ '/', '*', '-', '+', '\r',
+ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+ '.', 0, 0, 0, '='
+};
-/* test if a character is in the queue */
-static int usb_kbd_testc(void)
-{
-#ifdef CONFIG_SYS_USB_EVENT_POLL
- usb_event_poll();
-#endif
- if(usb_in_pointer==usb_out_pointer)
- return(0); /* no data */
- else
- return(1);
-}
-/* gets the character from the queue */
-static int usb_kbd_getc(void)
-{
- char c;
- while(usb_in_pointer==usb_out_pointer) {
-#ifdef CONFIG_SYS_USB_EVENT_POLL
- usb_event_poll();
-#endif
- }
- if((usb_out_pointer+1)==USB_KBD_BUFFER_LEN)
- usb_out_pointer=0;
- else
- usb_out_pointer++;
- c=usb_kbd_buffer[usb_out_pointer];
- return (int)c;
+/*
+ * map arrow keys to ^F/^B ^N/^P, can't really use the proper
+ * ANSI sequence for arrow keys because the queuing code breaks
+ * when a single keypress expands to 3 queue elements
+ */
+static const unsigned char usb_kbd_arrow[] = {
+ 0x6, 0x2, 0xe, 0x10
+};
-}
+/*
+ * NOTE: It's important for the NUM, CAPS, SCROLL-lock bits to be in this
+ * order. See usb_kbd_setled() function!
+ */
+#define USB_KBD_NUMLOCK (1 << 0)
+#define USB_KBD_CAPSLOCK (1 << 1)
+#define USB_KBD_SCROLLLOCK (1 << 2)
+#define USB_KBD_CTRL (1 << 3)
-/* forward decleration */
-static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum);
+#define USB_KBD_LEDMASK \
+ (USB_KBD_NUMLOCK | USB_KBD_CAPSLOCK | USB_KBD_SCROLLLOCK)
-/* search for keyboard and register it if found */
-int drv_usb_kbd_init(void)
-{
- int error,i;
- struct stdio_dev usb_kbd_dev,*old_dev;
- struct usb_device *dev;
- char *stdinname = getenv ("stdin");
-
- usb_in_pointer=0;
- usb_out_pointer=0;
- /* scan all USB Devices */
- for(i=0;i<USB_MAX_DEVICE;i++) {
- dev=usb_get_dev_index(i); /* get device */
- if(dev == NULL)
- return -1;
- if(dev->devnum!=-1) {
- if(usb_kbd_probe(dev,0)==1) { /* Ok, we found a keyboard */
- /* check, if it is already registered */
- USB_KBD_PRINTF("USB KBD found set up device.\n");
- old_dev = stdio_get_by_name(DEVNAME);
- if(old_dev) {
- /* ok, already registered, just return ok */
- USB_KBD_PRINTF("USB KBD is already registered.\n");
- return 1;
- }
- /* register the keyboard */
- USB_KBD_PRINTF("USB KBD register.\n");
- memset (&usb_kbd_dev, 0, sizeof(struct stdio_dev));
- strcpy(usb_kbd_dev.name, DEVNAME);
- usb_kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
- usb_kbd_dev.putc = NULL;
- usb_kbd_dev.puts = NULL;
- usb_kbd_dev.getc = usb_kbd_getc;
- usb_kbd_dev.tstc = usb_kbd_testc;
- usb_kbd_dev.priv = (void *)dev;
- error = stdio_register (&usb_kbd_dev);
- if(error==0) {
- /* check if this is the standard input device */
- if(strcmp(stdinname,DEVNAME)==0) {
- /* reassign the console */
- if(overwrite_console()) {
- return 1;
- }
- error=console_assign(stdin,DEVNAME);
- if(error==0)
- return 1;
- else
- return error;
- }
- return 1;
- }
- return error;
- }
- }
- }
- /* no USB Keyboard found */
- return -1;
-}
+struct usb_kbd_pdata {
+ uint32_t repeat_delay;
+ uint32_t usb_in_pointer;
+ uint32_t usb_out_pointer;
+ uint8_t usb_kbd_buffer[USB_KBD_BUFFER_LEN];
-/* deregistering the keyboard */
-int usb_kbd_deregister(void)
+ uint8_t *new;
+ uint8_t old[8];
+
+ uint8_t flags;
+};
+
+extern int __maybe_unused net_busy_flag;
+
+/* The period of time between two calls of usb_kbd_testc(). */
+static unsigned long __maybe_unused kbd_testc_tms;
+
+/* Generic keyboard event polling. */
+void usb_kbd_generic_poll(void)
{
-#ifdef CONFIG_SYS_STDIO_DEREGISTER
- return stdio_deregister(DEVNAME);
-#else
- return 1;
-#endif
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_kbd_pdata *data;
+ struct usb_interface *iface;
+ struct usb_endpoint_descriptor *ep;
+ int pipe;
+ int maxp;
+
+ /* Get the pointer to USB Keyboard device pointer */
+ dev = stdio_get_by_name(DEVNAME);
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ data = usb_kbd_dev->privptr;
+ iface = &usb_kbd_dev->config.if_desc[0];
+ ep = &iface->ep_desc[0];
+ pipe = usb_rcvintpipe(usb_kbd_dev, ep->bEndpointAddress);
+
+ /* Submit a interrupt transfer request */
+ maxp = usb_maxpacket(usb_kbd_dev, pipe);
+ usb_submit_int_msg(usb_kbd_dev, pipe, data->new,
+ maxp > 8 ? 8 : maxp, ep->bInterval);
}
-/**************************************************************************
- * Low Level drivers
- */
+/* Puts character in the queue and sets up the in and out pointer. */
+static void usb_kbd_put_queue(struct usb_kbd_pdata *data, char c)
+{
+ if (data->usb_in_pointer == USB_KBD_BUFFER_LEN - 1) {
+ /* Check for buffer full. */
+ if (data->usb_out_pointer == 0)
+ return;
+
+ data->usb_in_pointer = 0;
+ } else {
+ /* Check for buffer full. */
+ if (data->usb_in_pointer == data->usb_out_pointer - 1)
+ return;
+
+ data->usb_in_pointer++;
+ }
-/* set the LEDs. Since this is used in the irq routine, the control job
- is issued with a timeout of 0. This means, that the job is queued without
- waiting for job completion */
+ data->usb_kbd_buffer[data->usb_in_pointer] = c;
+}
+/*
+ * Set the LEDs. Since this is used in the irq routine, the control job is
+ * issued with a timeout of 0. This means, that the job is queued without
+ * waiting for job completion.
+ */
static void usb_kbd_setled(struct usb_device *dev)
{
- struct usb_interface *iface;
- iface = &dev->config.if_desc[0];
- leds=0;
- if(scroll_lock!=0)
- leds|=1;
- leds<<=1;
- if(caps_lock!=0)
- leds|=1;
- leds<<=1;
- if(num_lock!=0)
- leds|=1;
+ struct usb_interface *iface = &dev->config.if_desc[0];
+ struct usb_kbd_pdata *data = dev->privptr;
+ uint32_t leds = data->flags & USB_KBD_LEDMASK;
+
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x200, iface->desc.bInterfaceNumber, (void *)&leds, 1, 0);
-
}
-
-#define CAPITAL_MASK 0x20
+#define CAPITAL_MASK 0x20
/* Translate the scancode in ASCII */
-static int usb_kbd_translate(unsigned char scancode,unsigned char modifier,int pressed)
+static int usb_kbd_translate(struct usb_kbd_pdata *data, unsigned char scancode,
+ unsigned char modifier, int pressed)
{
- unsigned char keycode;
+ uint8_t keycode = 0;
- if(pressed==0) {
- /* key released */
- repeat_delay=0;
+ /* Key released */
+ if (pressed == 0) {
+ data->repeat_delay = 0;
return 0;
}
- if(pressed==2) {
- repeat_delay++;
- if(repeat_delay<REPEAT_DELAY)
+
+ if (pressed == 2) {
+ data->repeat_delay++;
+ if (data->repeat_delay < REPEAT_DELAY)
return 0;
- repeat_delay=REPEAT_DELAY;
+
+ data->repeat_delay = REPEAT_DELAY;
}
- keycode=0;
- if((scancode>3) && (scancode<=0x1d)) { /* alpha numeric values */
- keycode=scancode-4 + 0x61;
- if(caps_lock)
- keycode&=~CAPITAL_MASK; /* switch to capital Letters */
- if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) {
- if(keycode & CAPITAL_MASK)
- keycode&=~CAPITAL_MASK; /* switch to capital Letters */
+
+ /* Alphanumeric values */
+ if ((scancode > 3) && (scancode <= 0x1d)) {
+ keycode = scancode - 4 + 'a';
+
+ if (data->flags & USB_KBD_CAPSLOCK)
+ keycode &= ~CAPITAL_MASK;
+
+ if (modifier & (LEFT_SHIFT | RIGHT_SHIFT)) {
+ /* Handle CAPSLock + Shift pressed simultaneously */
+ if (keycode & CAPITAL_MASK)
+ keycode &= ~CAPITAL_MASK;
else
- keycode|=CAPITAL_MASK; /* switch to non capital Letters */
+ keycode |= CAPITAL_MASK;
}
}
- if((scancode>0x1d) && (scancode<0x3A)) {
- if(((modifier&(1<<LEFT_SHIFT))!=0)||((modifier&(1<<RIGHT_SHIFT))!=0)) /* shifted */
- keycode=usb_kbd_numkey_shifted[scancode-0x1e];
- else /* non shifted */
- keycode=usb_kbd_numkey[scancode-0x1e];
+
+ if ((scancode > 0x1d) && (scancode < 0x3a)) {
+ /* Shift pressed */
+ if (modifier & (LEFT_SHIFT | RIGHT_SHIFT))
+ keycode = usb_kbd_numkey_shifted[scancode - 0x1e];
+ else
+ keycode = usb_kbd_numkey[scancode - 0x1e];
}
- if (ctrl)
+ /* Arrow keys */
+ if ((scancode >= 0x4f) && (scancode <= 0x52))
+ keycode = usb_kbd_arrow[scancode - 0x4f];
+
+ /* Numeric keypad */
+ if ((scancode >= 0x54) && (scancode <= 0x67))
+ keycode = usb_kbd_num_keypad[scancode - 0x54];
+
+ if (data->flags & USB_KBD_CTRL)
keycode = scancode - 0x3;
- if(pressed==1) {
- if(scancode==NUM_LOCK) {
- num_lock=~num_lock;
+ if (pressed == 1) {
+ if (scancode == NUM_LOCK) {
+ data->flags ^= USB_KBD_NUMLOCK;
return 1;
}
- if(scancode==CAPS_LOCK) {
- caps_lock=~caps_lock;
+
+ if (scancode == CAPS_LOCK) {
+ data->flags ^= USB_KBD_CAPSLOCK;
return 1;
}
- if(scancode==SCROLL_LOCK) {
- scroll_lock=~scroll_lock;
+ if (scancode == SCROLL_LOCK) {
+ data->flags ^= USB_KBD_SCROLLLOCK;
return 1;
}
}
- if(keycode!=0) {
- USB_KBD_PRINTF("%c",keycode);
- usb_kbd_put_queue(keycode);
+
+ /* Report keycode if any */
+ if (keycode) {
+ debug("%c", keycode);
+ usb_kbd_put_queue(data, keycode);
}
+
return 0;
}
+static uint32_t usb_kbd_service_key(struct usb_device *dev, int i, int up)
+{
+ uint32_t res = 0;
+ struct usb_kbd_pdata *data = dev->privptr;
+ uint8_t *new;
+ uint8_t *old;
+
+ if (up) {
+ new = data->old;
+ old = data->new;
+ } else {
+ new = data->new;
+ old = data->old;
+ }
+
+ if ((old[i] > 3) && (memscan(new + 2, old[i], 6) == new + 8))
+ res |= usb_kbd_translate(data, old[i], data->new[0], up);
+
+ return res;
+}
+
/* Interrupt service routine */
-static int usb_kbd_irq(struct usb_device *dev)
+static int usb_kbd_irq_worker(struct usb_device *dev)
{
- int i,res;
+ struct usb_kbd_pdata *data = dev->privptr;
+ int i, res = 0;
- if((dev->irq_status!=0)||(dev->irq_act_len!=8))
- {
- USB_KBD_PRINTF("usb_keyboard Error %lX, len %d\n",dev->irq_status,dev->irq_act_len);
- return 1;
- }
- res=0;
-
- switch (new[0]) {
- case 0x0: /* No combo key pressed */
- ctrl = 0;
- break;
- case 0x01: /* Left Ctrl pressed */
- case 0x10: /* Right Ctrl pressed */
- ctrl = 1;
- break;
- }
+ /* No combo key pressed */
+ if (data->new[0] == 0x00)
+ data->flags &= ~USB_KBD_CTRL;
+ /* Left or Right Ctrl pressed */
+ else if ((data->new[0] == LEFT_CNTR) || (data->new[0] == RIGHT_CNTR))
+ data->flags |= USB_KBD_CTRL;
for (i = 2; i < 8; i++) {
- if (old[i] > 3 && memscan(&new[2], old[i], 6) == &new[8]) {
- res|=usb_kbd_translate(old[i],new[0],0);
- }
- if (new[i] > 3 && memscan(&old[2], new[i], 6) == &old[8]) {
- res|=usb_kbd_translate(new[i],new[0],1);
- }
+ res |= usb_kbd_service_key(dev, i, 0);
+ res |= usb_kbd_service_key(dev, i, 1);
}
- if((new[2]>3) && (old[2]==new[2])) /* still pressed */
- res|=usb_kbd_translate(new[2],new[0],2);
- if(res==1)
+
+ /* Key is still pressed */
+ if ((data->new[2] > 3) && (data->old[2] == data->new[2]))
+ res |= usb_kbd_translate(data, data->new[2], data->new[0], 2);
+
+ if (res == 1)
usb_kbd_setled(dev);
- memcpy(&old[0],&new[0], 8);
- return 1; /* install IRQ Handler again */
+
+ memcpy(data->old, data->new, 8);
+
+ return 1;
}
-/* probes the USB device dev for keyboard type */
-static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
+/* Keyboard interrupt handler */
+static int usb_kbd_irq(struct usb_device *dev)
+{
+ if ((dev->irq_status != 0) || (dev->irq_act_len != 8)) {
+ debug("USB KBD: Error %lX, len %d\n",
+ dev->irq_status, dev->irq_act_len);
+ return 1;
+ }
+
+ return usb_kbd_irq_worker(dev);
+}
+
+/* Interrupt polling */
+static inline void usb_kbd_poll_for_event(struct usb_device *dev)
{
+#if defined(CONFIG_SYS_USB_EVENT_POLL)
struct usb_interface *iface;
struct usb_endpoint_descriptor *ep;
- int pipe,maxp;
+ struct usb_kbd_pdata *data;
+ int pipe;
+ int maxp;
- if (dev->descriptor.bNumConfigurations != 1) return 0;
- iface = &dev->config.if_desc[ifnum];
+ /* Get the pointer to USB Keyboard device pointer */
+ data = dev->privptr;
+ iface = &dev->config.if_desc[0];
+ ep = &iface->ep_desc[0];
+ pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
- if (iface->desc.bInterfaceClass != 3)
- return 0;
- if (iface->desc.bInterfaceSubClass != 1)
- return 0;
- if (iface->desc.bInterfaceProtocol != 1)
- return 0;
- if (iface->desc.bNumEndpoints != 1)
+ /* Submit a interrupt transfer request */
+ maxp = usb_maxpacket(dev, pipe);
+ usb_submit_int_msg(dev, pipe, &data->new[0],
+ maxp > 8 ? 8 : maxp, ep->bInterval);
+
+ usb_kbd_irq_worker(dev);
+#elif defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP)
+ struct usb_interface *iface;
+ struct usb_kbd_pdata *data = dev->privptr;
+ iface = &dev->config.if_desc[0];
+ usb_get_report(dev, iface->desc.bInterfaceNumber,
+ 1, 0, data->new, sizeof(data->new));
+ if (memcmp(data->old, data->new, sizeof(data->new)))
+ usb_kbd_irq_worker(dev);
+#endif
+}
+
+/* test if a character is in the queue */
+static int usb_kbd_testc(void)
+{
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_kbd_pdata *data;
+
+#ifdef CONFIG_CMD_NET
+ /*
+ * If net_busy_flag is 1, NET transfer is running,
+ * then we check key-pressed every second (first check may be
+ * less than 1 second) to improve TFTP booting performance.
+ */
+ if (net_busy_flag && (get_timer(kbd_testc_tms) < CONFIG_SYS_HZ))
return 0;
+ kbd_testc_tms = get_timer(0);
+#endif
+ dev = stdio_get_by_name(DEVNAME);
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ data = usb_kbd_dev->privptr;
- ep = &iface->ep_desc[0];
+ usb_kbd_poll_for_event(usb_kbd_dev);
- if (!(ep->bEndpointAddress & 0x80)) return 0;
- if ((ep->bmAttributes & 3) != 3) return 0;
- USB_KBD_PRINTF("USB KBD found set protocol...\n");
- /* ok, we found a USB Keyboard, install it */
- /* usb_kbd_get_hid_desc(dev); */
- usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
- USB_KBD_PRINTF("USB KBD found set idle...\n");
- usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0);
- memset(&new[0], 0, 8);
- memset(&old[0], 0, 8);
- repeat_delay=0;
- pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
- maxp = usb_maxpacket(dev, pipe);
- dev->irq_handle=usb_kbd_irq;
- USB_KBD_PRINTF("USB KBD enable interrupt pipe...\n");
- usb_submit_int_msg(dev,pipe,&new[0], maxp > 8 ? 8 : maxp,ep->bInterval);
- return 1;
+ return !(data->usb_in_pointer == data->usb_out_pointer);
}
+/* gets the character from the queue */
+static int usb_kbd_getc(void)
+{
+ struct stdio_dev *dev;
+ struct usb_device *usb_kbd_dev;
+ struct usb_kbd_pdata *data;
-#if 0
-struct usb_hid_descriptor {
- unsigned char bLength;
- unsigned char bDescriptorType; /* 0x21 for HID */
- unsigned short bcdHID; /* release number */
- unsigned char bCountryCode;
- unsigned char bNumDescriptors;
- unsigned char bReportDescriptorType;
- unsigned short wDescriptorLength;
-} __attribute__ ((packed));
+ dev = stdio_get_by_name(DEVNAME);
+ usb_kbd_dev = (struct usb_device *)dev->priv;
+ data = usb_kbd_dev->privptr;
-/*
- * We parse each description item into this structure. Short items data
- * values are expanded to 32-bit signed int, long items contain a pointer
- * into the data area.
- */
+ while (data->usb_in_pointer == data->usb_out_pointer)
+ usb_kbd_poll_for_event(usb_kbd_dev);
-struct hid_item {
- unsigned char format;
- unsigned char size;
- unsigned char type;
- unsigned char tag;
- union {
- unsigned char u8;
- char s8;
- unsigned short u16;
- short s16;
- unsigned long u32;
- long s32;
- unsigned char *longdata;
- } data;
-};
+ if (data->usb_out_pointer == USB_KBD_BUFFER_LEN - 1)
+ data->usb_out_pointer = 0;
+ else
+ data->usb_out_pointer++;
-/*
- * HID report item format
- */
+ return data->usb_kbd_buffer[data->usb_out_pointer];
+}
-#define HID_ITEM_FORMAT_SHORT 0
-#define HID_ITEM_FORMAT_LONG 1
+/* probes the USB device dev for keyboard type. */
+static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum)
+{
+ struct usb_interface *iface;
+ struct usb_endpoint_descriptor *ep;
+ struct usb_kbd_pdata *data;
+ int pipe, maxp;
-/*
- * Special tag indicating long items
- */
+ if (dev->descriptor.bNumConfigurations != 1)
+ return 0;
-#define HID_ITEM_TAG_LONG 15
+ iface = &dev->config.if_desc[ifnum];
+ if (iface->desc.bInterfaceClass != 3)
+ return 0;
-static struct usb_hid_descriptor usb_kbd_hid_desc;
+ if (iface->desc.bInterfaceSubClass != 1)
+ return 0;
-void usb_kbd_display_hid(struct usb_hid_descriptor *hid)
-{
- printf("USB_HID_DESC:\n");
- printf(" bLenght 0x%x\n",hid->bLength);
- printf(" bcdHID 0x%x\n",hid->bcdHID);
- printf(" bCountryCode %d\n",hid->bCountryCode);
- printf(" bNumDescriptors 0x%x\n",hid->bNumDescriptors);
- printf(" bReportDescriptorType 0x%x\n",hid->bReportDescriptorType);
- printf(" wDescriptorLength 0x%x\n",hid->wDescriptorLength);
-}
+ if (iface->desc.bInterfaceProtocol != 1)
+ return 0;
+ if (iface->desc.bNumEndpoints != 1)
+ return 0;
-/*
- * Fetch a report description item from the data stream. We support long
- * items, though they are not used yet.
- */
+ ep = &iface->ep_desc[0];
-static int fetch_item(unsigned char *start,unsigned char *end, struct hid_item *item)
-{
- if((end - start) > 0) {
- unsigned char b = *start++;
- item->type = (b >> 2) & 3;
- item->tag = (b >> 4) & 15;
- if (item->tag == HID_ITEM_TAG_LONG) {
- item->format = HID_ITEM_FORMAT_LONG;
- if ((end - start) >= 2) {
- item->size = *start++;
- item->tag = *start++;
- if ((end - start) >= item->size) {
- item->data.longdata = start;
- start += item->size;
- return item->size;
- }
- }
- } else {
- item->format = HID_ITEM_FORMAT_SHORT;
- item->size = b & 3;
- switch (item->size) {
- case 0:
- return item->size;
- case 1:
- if ((end - start) >= 1) {
- item->data.u8 = *start++;
- return item->size;
- }
- break;
- case 2:
- if ((end - start) >= 2) {
- item->data.u16 = le16_to_cpu((unsigned short *)start);
- start+=2;
- return item->size;
- }
- case 3:
- item->size++;
- if ((end - start) >= 4) {
- item->data.u32 = le32_to_cpu((unsigned long *)start);
- start+=4;
- return item->size;
- }
- }
- }
- }
- return -1;
-}
+ /* Check if endpoint 1 is interrupt endpoint */
+ if (!(ep->bEndpointAddress & 0x80))
+ return 0;
-/*
- * HID report descriptor item type (prefix bit 2,3)
- */
+ if ((ep->bmAttributes & 3) != 3)
+ return 0;
-#define HID_ITEM_TYPE_MAIN 0
-#define HID_ITEM_TYPE_GLOBAL 1
-#define HID_ITEM_TYPE_LOCAL 2
-#define HID_ITEM_TYPE_RESERVED 3
-/*
- * HID report descriptor main item tags
- */
+ debug("USB KBD: found set protocol...\n");
-#define HID_MAIN_ITEM_TAG_INPUT 8
-#define HID_MAIN_ITEM_TAG_OUTPUT 9
-#define HID_MAIN_ITEM_TAG_FEATURE 11
-#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10
-#define HID_MAIN_ITEM_TAG_END_COLLECTION 12
-/*
- * HID report descriptor main item contents
- */
+ data = malloc(sizeof(struct usb_kbd_pdata));
+ if (!data) {
+ printf("USB KBD: Error allocating private data\n");
+ return 0;
+ }
-#define HID_MAIN_ITEM_CONSTANT 0x001
-#define HID_MAIN_ITEM_VARIABLE 0x002
-#define HID_MAIN_ITEM_RELATIVE 0x004
-#define HID_MAIN_ITEM_WRAP 0x008
-#define HID_MAIN_ITEM_NONLINEAR 0x010
-#define HID_MAIN_ITEM_NO_PREFERRED 0x020
-#define HID_MAIN_ITEM_NULL_STATE 0x040
-#define HID_MAIN_ITEM_VOLATILE 0x080
-#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100
+ /* Clear private data */
+ memset(data, 0, sizeof(struct usb_kbd_pdata));
-/*
- * HID report descriptor collection item types
- */
+ /* allocate input buffer aligned and sized to USB DMA alignment */
+ data->new = memalign(USB_DMA_MINALIGN, roundup(8, USB_DMA_MINALIGN));
-#define HID_COLLECTION_PHYSICAL 0
-#define HID_COLLECTION_APPLICATION 1
-#define HID_COLLECTION_LOGICAL 2
-/*
- * HID report descriptor global item tags
- */
+ /* Insert private data into USB device structure */
+ dev->privptr = data;
-#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0
-#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1
-#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2
-#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3
-#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4
-#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5
-#define HID_GLOBAL_ITEM_TAG_UNIT 6
-#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7
-#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8
-#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9
-#define HID_GLOBAL_ITEM_TAG_PUSH 10
-#define HID_GLOBAL_ITEM_TAG_POP 11
+ /* Set IRQ handler */
+ dev->irq_handle = usb_kbd_irq;
-/*
- * HID report descriptor local item tags
- */
+ pipe = usb_rcvintpipe(dev, ep->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe);
-#define HID_LOCAL_ITEM_TAG_USAGE 0
-#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1
-#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4
-#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5
-#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7
-#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8
-#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9
-#define HID_LOCAL_ITEM_TAG_DELIMITER 10
+ /* We found a USB Keyboard, install it. */
+ usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
+ debug("USB KBD: found set idle...\n");
+ usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0);
-static void usb_kbd_show_item(struct hid_item *item)
-{
- switch(item->type) {
- case HID_ITEM_TYPE_MAIN:
- switch(item->tag) {
- case HID_MAIN_ITEM_TAG_INPUT:
- printf("Main Input");
- break;
- case HID_MAIN_ITEM_TAG_OUTPUT:
- printf("Main Output");
- break;
- case HID_MAIN_ITEM_TAG_FEATURE:
- printf("Main Feature");
- break;
- case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
- printf("Main Begin Collection");
- break;
- case HID_MAIN_ITEM_TAG_END_COLLECTION:
- printf("Main End Collection");
- break;
- default:
- printf("Main reserved %d",item->tag);
- break;
- }
- break;
- case HID_ITEM_TYPE_GLOBAL:
- switch(item->tag) {
- case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
- printf("- Global Usage Page");
- break;
- case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
- printf("- Global Logical Minimum");
- break;
- case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
- printf("- Global Logical Maximum");
- break;
- case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
- printf("- Global physical Minimum");
- break;
- case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
- printf("- Global physical Maximum");
- break;
- case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
- printf("- Global Unit Exponent");
- break;
- case HID_GLOBAL_ITEM_TAG_UNIT:
- printf("- Global Unit");
- break;
- case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
- printf("- Global Report Size");
- break;
- case HID_GLOBAL_ITEM_TAG_REPORT_ID:
- printf("- Global Report ID");
- break;
- case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
- printf("- Global Report Count");
- break;
- case HID_GLOBAL_ITEM_TAG_PUSH:
- printf("- Global Push");
- break;
- case HID_GLOBAL_ITEM_TAG_POP:
- printf("- Global Pop");
- break;
- default:
- printf("- Global reserved %d",item->tag);
- break;
- }
- break;
- case HID_ITEM_TYPE_LOCAL:
- switch(item->tag) {
- case HID_LOCAL_ITEM_TAG_USAGE:
- printf("-- Local Usage");
- break;
- case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
- printf("-- Local Usage Minimum");
- break;
- case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
- printf("-- Local Usage Maximum");
- break;
- case HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX:
- printf("-- Local Designator Index");
- break;
- case HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM:
- printf("-- Local Designator Minimum");
- break;
- case HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM:
- printf("-- Local Designator Maximum");
- break;
- case HID_LOCAL_ITEM_TAG_STRING_INDEX:
- printf("-- Local String Index");
- break;
- case HID_LOCAL_ITEM_TAG_STRING_MINIMUM:
- printf("-- Local String Minimum");
- break;
- case HID_LOCAL_ITEM_TAG_STRING_MAXIMUM:
- printf("-- Local String Maximum");
- break;
- case HID_LOCAL_ITEM_TAG_DELIMITER:
- printf("-- Local Delimiter");
- break;
- default:
- printf("-- Local reserved %d",item->tag);
- break;
- }
- break;
- default:
- printf("--- reserved %d",item->type);
- break;
- }
- switch(item->size) {
- case 1:
- printf(" %d",item->data.u8);
- break;
- case 2:
- printf(" %d",item->data.u16);
- break;
- case 4:
- printf(" %ld",item->data.u32);
- break;
+ debug("USB KBD: enable interrupt pipe...\n");
+ if (usb_submit_int_msg(dev, pipe, data->new, maxp > 8 ? 8 : maxp,
+ ep->bInterval) < 0) {
+ printf("Failed to get keyboard state from device %04x:%04x\n",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ /* Abort, we don't want to use that non-functional keyboard. */
+ return 0;
}
- printf("\n");
-}
+ /* Success. */
+ return 1;
+}
-static int usb_kbd_get_hid_desc(struct usb_device *dev)
+/* Search for keyboard and register it if found. */
+int drv_usb_kbd_init(void)
{
- unsigned char buffer[256];
- struct usb_descriptor_header *head;
- struct usb_config_descriptor *config;
- int index,len,i;
- unsigned char *start, *end;
- struct hid_item item;
-
- if(usb_get_configuration_no(dev,&buffer[0],0)==-1)
- return -1;
- head =(struct usb_descriptor_header *)&buffer[0];
- if(head->bDescriptorType!=USB_DT_CONFIG) {
- printf(" ERROR: NOT USB_CONFIG_DESC %x\n",head->bDescriptorType);
- return -1;
- }
- index=head->bLength;
- config=(struct usb_config_descriptor *)&buffer[0];
- len=le16_to_cpu(config->wTotalLength);
- /* Ok the first entry must be a configuration entry, now process the others */
- head=(struct usb_descriptor_header *)&buffer[index];
- while(index+1 < len) {
- if(head->bDescriptorType==USB_DT_HID) {
- printf("HID desc found\n");
- memcpy(&usb_kbd_hid_desc,&buffer[index],buffer[index]);
- le16_to_cpus(&usb_kbd_hid_desc.bcdHID);
- le16_to_cpus(&usb_kbd_hid_desc.wDescriptorLength);
- usb_kbd_display_hid(&usb_kbd_hid_desc);
- len=0;
- break;
+ struct stdio_dev usb_kbd_dev, *old_dev;
+ struct usb_device *dev;
+ char *stdinname = getenv("stdin");
+ int error, i;
+
+ /* Scan all USB Devices */
+ for (i = 0; i < USB_MAX_DEVICE; i++) {
+ /* Get USB device. */
+ dev = usb_get_dev_index(i);
+ if (!dev)
+ return -1;
+
+ if (dev->devnum == -1)
+ continue;
+
+ /* Try probing the keyboard */
+ if (usb_kbd_probe(dev, 0) != 1)
+ continue;
+
+ /* We found a keyboard, check if it is already registered. */
+ debug("USB KBD: found set up device.\n");
+ old_dev = stdio_get_by_name(DEVNAME);
+ if (old_dev) {
+ /* Already registered, just return ok. */
+ debug("USB KBD: is already registered.\n");
+ usb_kbd_deregister();
+ return 1;
}
- index+=head->bLength;
- head=(struct usb_descriptor_header *)&buffer[index];
- }
- if(len>0)
- return -1;
- len=usb_kbd_hid_desc.wDescriptorLength;
- if((index = usb_get_class_descriptor(dev, 0, USB_DT_REPORT, 0, &buffer[0], len)) < 0) {
- printf("reading report descriptor failed\n");
- return -1;
+
+ /* Register the keyboard */
+ debug("USB KBD: register.\n");
+ memset(&usb_kbd_dev, 0, sizeof(struct stdio_dev));
+ strcpy(usb_kbd_dev.name, DEVNAME);
+ usb_kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ usb_kbd_dev.putc = NULL;
+ usb_kbd_dev.puts = NULL;
+ usb_kbd_dev.getc = usb_kbd_getc;
+ usb_kbd_dev.tstc = usb_kbd_testc;
+ usb_kbd_dev.priv = (void *)dev;
+ error = stdio_register(&usb_kbd_dev);
+ if (error)
+ return error;
+
+#ifdef CONFIG_CONSOLE_MUX
+ error = iomux_doenv(stdin, stdinname);
+ if (error)
+ return error;
+#else
+ /* Check if this is the standard input device. */
+ if (strcmp(stdinname, DEVNAME))
+ return 1;
+
+ /* Reassign the console */
+ if (overwrite_console())
+ return 1;
+
+ error = console_assign(stdin, DEVNAME);
+ if (error)
+ return error;
+#endif
+
+ return 1;
}
- printf(" report descriptor (size %u, read %d)\n", len, index);
- start = &buffer[0];
- end = &buffer[len];
- i=0;
- do {
- index=fetch_item(start,end,&item);
- i+=index;
- i++;
- if(index>=0)
- usb_kbd_show_item(&item);
-
- start+=index;
- start++;
- } while(index>=0);
+ /* No USB Keyboard found */
+ return -1;
}
+/* Deregister the keyboard. */
+int usb_kbd_deregister(void)
+{
+#ifdef CONFIG_SYS_STDIO_DEREGISTER
+ return stdio_deregister(DEVNAME);
+#else
+ return 1;
#endif
+}
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index e27bb3e71d..df8ab07b94 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -2,23 +2,7 @@
* (C) Copyright 2004
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
@@ -28,81 +12,160 @@
DECLARE_GLOBAL_DATA_PTR;
-static char input_buffer[512];
-static int input_size = 0; /* char count in input buffer */
-static int input_offset = 0; /* offset to valid chars in input buffer */
-static int input_recursion = 0;
-static int output_recursion = 0;
+#ifndef CONFIG_NETCONSOLE_BUFFER_SIZE
+#define CONFIG_NETCONSOLE_BUFFER_SIZE 512
+#endif
+
+static char input_buffer[CONFIG_NETCONSOLE_BUFFER_SIZE];
+static int input_size; /* char count in input buffer */
+static int input_offset; /* offset to valid chars in input buffer */
+static int input_recursion;
+static int output_recursion;
static int net_timeout;
-static uchar nc_ether[6]; /* server enet address */
-static IPaddr_t nc_ip; /* server ip */
-static short nc_port; /* source/target port */
-static const char *output_packet; /* used by first send udp */
-static int output_packet_len = 0;
+static uchar nc_ether[6]; /* server enet address */
+static IPaddr_t nc_ip; /* server ip */
+static short nc_out_port; /* target output port */
+static short nc_in_port; /* source input port */
+static const char *output_packet; /* used by first send udp */
+static int output_packet_len;
+/*
+ * Start with a default last protocol.
+ * We are only interested in NETCONS or not.
+ */
+enum proto_t net_loop_last_protocol = BOOTP;
-static void nc_wait_arp_handler (uchar * pkt, unsigned dest, unsigned src,
+static void nc_wait_arp_handler(uchar *pkt, unsigned dest,
+ IPaddr_t sip, unsigned src,
unsigned len)
{
- NetState = NETLOOP_SUCCESS; /* got arp reply - quit net loop */
+ net_set_state(NETLOOP_SUCCESS); /* got arp reply - quit net loop */
}
-static void nc_handler (uchar * pkt, unsigned dest, unsigned src,
+static void nc_handler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
unsigned len)
{
if (input_size)
- NetState = NETLOOP_SUCCESS; /* got input - quit net loop */
+ net_set_state(NETLOOP_SUCCESS); /* got input - quit net loop */
}
-static void nc_timeout (void)
+static void nc_timeout(void)
{
- NetState = NETLOOP_SUCCESS;
+ net_set_state(NETLOOP_SUCCESS);
}
-void NcStart (void)
+static int is_broadcast(IPaddr_t ip)
{
- if (!output_packet_len || memcmp (nc_ether, NetEtherNullAddr, 6)) {
+ static IPaddr_t netmask;
+ static IPaddr_t our_ip;
+ static int env_changed_id;
+ int env_id = get_env_id();
+
+ /* update only when the environment has changed */
+ if (env_changed_id != env_id) {
+ netmask = getenv_IPaddr("netmask");
+ our_ip = getenv_IPaddr("ipaddr");
+
+ env_changed_id = env_id;
+ }
+
+ return (ip == ~0 || /* 255.255.255.255 */
+ ((netmask & our_ip) == (netmask & ip) && /* on the same net */
+ (netmask | ip) == ~0)); /* broadcast to our net */
+}
+
+static int refresh_settings_from_env(void)
+{
+ const char *p;
+ static int env_changed_id;
+ int env_id = get_env_id();
+
+ /* update only when the environment has changed */
+ if (env_changed_id != env_id) {
+ if (getenv("ncip")) {
+ nc_ip = getenv_IPaddr("ncip");
+ if (!nc_ip)
+ return -1; /* ncip is 0.0.0.0 */
+ p = strchr(getenv("ncip"), ':');
+ if (p != NULL) {
+ nc_out_port = simple_strtoul(p + 1, NULL, 10);
+ nc_in_port = nc_out_port;
+ }
+ } else
+ nc_ip = ~0; /* ncip is not set, so broadcast */
+
+ p = getenv("ncoutport");
+ if (p != NULL)
+ nc_out_port = simple_strtoul(p, NULL, 10);
+ p = getenv("ncinport");
+ if (p != NULL)
+ nc_in_port = simple_strtoul(p, NULL, 10);
+
+ if (is_broadcast(nc_ip))
+ /* broadcast MAC address */
+ memset(nc_ether, 0xff, sizeof(nc_ether));
+ else
+ /* force arp request */
+ memset(nc_ether, 0, sizeof(nc_ether));
+ }
+ return 0;
+}
+
+/**
+ * Called from NetLoop in net/net.c before each packet
+ */
+void NcStart(void)
+{
+ refresh_settings_from_env();
+ if (!output_packet_len || memcmp(nc_ether, NetEtherNullAddr, 6)) {
/* going to check for input packet */
- NetSetHandler (nc_handler);
- NetSetTimeout (net_timeout, nc_timeout);
+ net_set_udp_handler(nc_handler);
+ NetSetTimeout(net_timeout, nc_timeout);
} else {
/* send arp request */
uchar *pkt;
- NetSetHandler (nc_wait_arp_handler);
- pkt = (uchar *) NetTxPacket + NetEthHdrSize () + IP_HDR_SIZE;
- memcpy (pkt, output_packet, output_packet_len);
- NetSendUDPPacket (nc_ether, nc_ip, nc_port, nc_port, output_packet_len);
+ net_set_arp_handler(nc_wait_arp_handler);
+ pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
+ memcpy(pkt, output_packet, output_packet_len);
+ NetSendUDPPacket(nc_ether, nc_ip, nc_out_port, nc_in_port,
+ output_packet_len);
}
}
-int nc_input_packet (uchar * pkt, unsigned dest, unsigned src, unsigned len)
+int nc_input_packet(uchar *pkt, IPaddr_t src_ip, unsigned dest_port,
+ unsigned src_port, unsigned len)
{
int end, chunk;
- if (dest != nc_port || !len)
- return 0; /* not for us */
+ if (dest_port != nc_in_port || !len)
+ return 0; /* not for us */
- if (input_size == sizeof input_buffer)
- return 1; /* no space */
- if (len > sizeof input_buffer - input_size)
- len = sizeof input_buffer - input_size;
+ if (src_ip != nc_ip && !is_broadcast(nc_ip))
+ return 0; /* not from our client */
+
+ debug_cond(DEBUG_DEV_PKT, "input: \"%*.*s\"\n", len, len, pkt);
+
+ if (input_size == sizeof(input_buffer))
+ return 1; /* no space */
+ if (len > sizeof(input_buffer) - input_size)
+ len = sizeof(input_buffer) - input_size;
end = input_offset + input_size;
- if (end > sizeof input_buffer)
- end -= sizeof input_buffer;
+ if (end > sizeof(input_buffer))
+ end -= sizeof(input_buffer);
chunk = len;
- if (end + len > sizeof input_buffer) {
- chunk = sizeof input_buffer - end;
+ if (end + len > sizeof(input_buffer)) {
+ chunk = sizeof(input_buffer) - end;
memcpy(input_buffer, pkt + chunk, len - chunk);
}
- memcpy (input_buffer + end, pkt, chunk);
+ memcpy(input_buffer + end, pkt, chunk);
input_size += len;
return 1;
}
-static void nc_send_packet (const char *buf, int len)
+static void nc_send_packet(const char *buf, int len)
{
struct eth_device *eth;
int inited = 0;
@@ -110,61 +173,62 @@ static void nc_send_packet (const char *buf, int len)
uchar *ether;
IPaddr_t ip;
- if ((eth = eth_get_dev ()) == NULL) {
+ debug_cond(DEBUG_DEV_PKT, "output: \"%*.*s\"\n", len, len, buf);
+
+ eth = eth_get_dev();
+ if (eth == NULL)
return;
- }
- if (!memcmp (nc_ether, NetEtherNullAddr, 6)) {
+ if (!memcmp(nc_ether, NetEtherNullAddr, 6)) {
if (eth->state == ETH_STATE_ACTIVE)
return; /* inside net loop */
output_packet = buf;
output_packet_len = len;
- NetLoop (NETCONS); /* wait for arp reply and send packet */
+ NetLoop(NETCONS); /* wait for arp reply and send packet */
output_packet_len = 0;
return;
}
if (eth->state != ETH_STATE_ACTIVE) {
- if (eth_init (gd->bd) < 0)
- return;
+ if (eth_is_on_demand_init()) {
+ if (eth_init(gd->bd) < 0)
+ return;
+ eth_set_last_protocol(NETCONS);
+ } else
+ eth_init_state_only(gd->bd);
+
inited = 1;
}
- pkt = (uchar *) NetTxPacket + NetEthHdrSize () + IP_HDR_SIZE;
- memcpy (pkt, buf, len);
+ pkt = (uchar *)NetTxPacket + NetEthHdrSize() + IP_UDP_HDR_SIZE;
+ memcpy(pkt, buf, len);
ether = nc_ether;
ip = nc_ip;
- NetSendUDPPacket (ether, ip, nc_port, nc_port, len);
+ NetSendUDPPacket(ether, ip, nc_out_port, nc_in_port, len);
- if (inited)
- eth_halt ();
+ if (inited) {
+ if (eth_is_on_demand_init())
+ eth_halt();
+ else
+ eth_halt_state_only();
+ }
}
static int nc_start(void)
{
- int netmask, our_ip;
-
- nc_port = 6666; /* default port */
+ int retval;
- if (getenv ("ncip")) {
- char *p;
+ nc_out_port = 6666; /* default port */
+ nc_in_port = nc_out_port;
- nc_ip = getenv_IPaddr ("ncip");
- if (!nc_ip)
- return -1; /* ncip is 0.0.0.0 */
- if ((p = strchr (getenv ("ncip"), ':')) != NULL)
- nc_port = simple_strtoul (p + 1, NULL, 10);
- } else
- nc_ip = ~0; /* ncip is not set */
+ retval = refresh_settings_from_env();
+ if (retval != 0)
+ return retval;
- our_ip = getenv_IPaddr ("ipaddr");
- netmask = getenv_IPaddr ("netmask");
-
- if (nc_ip == ~0 || /* 255.255.255.255 */
- ((netmask & our_ip) == (netmask & nc_ip) && /* on the same net */
- (netmask | nc_ip) == ~0)) /* broadcast to our net */
- memset (nc_ether, 0xff, sizeof nc_ether);
- else
- memset (nc_ether, 0, sizeof nc_ether); /* force arp request */
+ /*
+ * Initialize the static IP settings and buffer pointers
+ * incase we call NetSendUDPPacket before NetLoop
+ */
+ net_init();
return 0;
}
@@ -175,7 +239,7 @@ static void nc_putc(char c)
return;
output_recursion = 1;
- nc_send_packet (&c, 1);
+ nc_send_packet(&c, 1);
output_recursion = 0;
}
@@ -188,10 +252,13 @@ static void nc_puts(const char *s)
return;
output_recursion = 1;
- if ((len = strlen (s)) > 512)
- len = 512;
-
- nc_send_packet (s, len);
+ len = strlen(s);
+ while (len) {
+ int send_len = min(len, sizeof(input_buffer));
+ nc_send_packet(s, send_len);
+ len -= send_len;
+ s += send_len;
+ }
output_recursion = 0;
}
@@ -204,14 +271,14 @@ static int nc_getc(void)
net_timeout = 0; /* no timeout */
while (!input_size)
- NetLoop (NETCONS);
+ NetLoop(NETCONS);
input_recursion = 0;
c = input_buffer[input_offset++];
- if (input_offset >= sizeof input_buffer)
- input_offset -= sizeof input_buffer;
+ if (input_offset >= sizeof(input_buffer))
+ input_offset -= sizeof(input_buffer);
input_size--;
return c;
@@ -227,28 +294,28 @@ static int nc_tstc(void)
if (input_size)
return 1;
- eth = eth_get_dev ();
+ eth = eth_get_dev();
if (eth && eth->state == ETH_STATE_ACTIVE)
return 0; /* inside net loop */
input_recursion = 1;
net_timeout = 1;
- NetLoop (NETCONS); /* kind of poll */
+ NetLoop(NETCONS); /* kind of poll */
input_recursion = 0;
return input_size != 0;
}
-int drv_nc_init (void)
+int drv_nc_init(void)
{
struct stdio_dev dev;
int rc;
- memset (&dev, 0, sizeof (dev));
+ memset(&dev, 0, sizeof(dev));
- strcpy (dev.name, "nc");
+ strcpy(dev.name, "nc");
dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
dev.start = nc_start;
dev.putc = nc_putc;
@@ -256,7 +323,7 @@ int drv_nc_init (void)
dev.getc = nc_getc;
dev.tstc = nc_tstc;
- rc = stdio_register (&dev);
+ rc = stdio_register(&dev);
return (rc == 0) ? 1 : rc;
}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index fdad739724..3ae04c0253 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -36,6 +36,12 @@
#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
#endif
+/*
+ * EHCI spec page 20 says that the HC may take up to 16 uFrames (= 4ms) to halt.
+ * Let's time out after 8 to have a little safety margin on top of that.
+ */
+#define HCHALT_TIMEOUT (8 * 1000)
+
static struct ehci_ctrl ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT];
#define ALIGN_END_ADDR(type, ptr, size) \
@@ -190,6 +196,36 @@ out:
return ret;
}
+static int ehci_shutdown(struct ehci_ctrl *ctrl)
+{
+ int i, ret = 0;
+ uint32_t cmd, reg;
+
+ cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
+ cmd &= ~(CMD_PSE | CMD_ASE);
+ ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+ ret = handshake(&ctrl->hcor->or_usbsts, STS_ASS | STS_PSS, 0,
+ 100 * 1000);
+
+ if (!ret) {
+ for (i = 0; i < CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS; i++) {
+ reg = ehci_readl(&ctrl->hcor->or_portsc[i]);
+ reg |= EHCI_PS_SUSP;
+ ehci_writel(&ctrl->hcor->or_portsc[i], reg);
+ }
+
+ cmd &= ~CMD_RUN;
+ ehci_writel(&ctrl->hcor->or_usbcmd, cmd);
+ ret = handshake(&ctrl->hcor->or_usbsts, STS_HALT, STS_HALT,
+ HCHALT_TIMEOUT);
+ }
+
+ if (ret)
+ puts("EHCI failed to shut down host controller.\n");
+
+ return ret;
+}
+
static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz)
{
uint32_t delta, next;
@@ -808,6 +844,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
}
break;
case USB_PORT_FEAT_TEST:
+ ehci_shutdown(ctrl);
reg &= ~(0xf << 16);
reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16;
ehci_writel(status_reg, reg);
@@ -878,6 +915,7 @@ unknown:
int usb_lowlevel_stop(int index)
{
+ ehci_shutdown(&ehcic[index]);
return ehci_hcd_stop(index);
}
diff --git a/include/command.h b/include/command.h
index 2aabd65f75..f782779d8b 100644
--- a/include/command.h
+++ b/include/command.h
@@ -2,23 +2,7 @@
* (C) Copyright 2000-2009
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
/*
@@ -28,6 +12,7 @@
#define __COMMAND_H
#include <config.h>
+#include <linker_lists.h>
#ifndef NULL
#define NULL 0
@@ -61,14 +46,10 @@ struct cmd_tbl_s {
typedef struct cmd_tbl_s cmd_tbl_t;
-extern cmd_tbl_t __u_boot_cmd_start;
-extern cmd_tbl_t __u_boot_cmd_end;
-enum command_ret_t {
- CMD_RET_SUCCESS, /* 0 = Success */
- CMD_RET_FAILURE, /* 1 = Failure */
- CMD_RET_USAGE = -1, /* Failure, please report 'usage' error */
-};
+#if defined(CONFIG_CMD_RUN)
+extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
/* common/command.c */
int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int
@@ -76,10 +57,10 @@ int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int
cmd_tbl_t *find_cmd(const char *cmd);
cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len);
-extern int cmd_usage(cmd_tbl_t *cmdtp);
+extern int cmd_usage(const cmd_tbl_t *cmdtp);
#ifdef CONFIG_AUTO_COMPLETE
-extern void install_auto_complete(void);
+extern int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
extern int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp);
#endif
@@ -91,17 +72,66 @@ extern int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *
* void function (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
*/
-typedef void command_t (cmd_tbl_t *, int, int, char *[]);
-
#if defined(CONFIG_CMD_MEMORY) \
- || defined(CONFIG_CMD_I2C) \
- || defined(CONFIG_CMD_ITEST) \
- || defined(CONFIG_CMD_PCI) \
- || defined(CONFIG_CMD_PORTIO)
+ || defined(CONFIG_CMD_I2C) \
+ || defined(CONFIG_CMD_ITEST) \
+ || defined(CONFIG_CMD_PCI) \
+ || defined(CONFIG_CMD_PORTIO)
#define CMD_DATA_SIZE
extern int cmd_get_data_size(char* arg, int default_size);
#endif
+#ifdef CONFIG_CMD_BOOTD
+extern int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
+#ifdef CONFIG_CMD_BOOTM
+extern int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+extern int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd);
+#else
+static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
+{
+ return 0;
+}
+#endif
+
+extern int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
+ char *const argv[]);
+
+extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+/*
+ * Error codes that commands return to cmd_process(). We use the standard 0
+ * and 1 for success and failure, but add one more case - failure with a
+ * request to call cmd_usage(). But the cmd_process() function handles
+ * CMD_RET_USAGE itself and after calling cmd_usage() it will return 1.
+ * This is just a convenience for commands to avoid them having to call
+ * cmd_usage() all over the place.
+ */
+enum command_ret_t {
+ CMD_RET_SUCCESS, /* 0 = Success */
+ CMD_RET_FAILURE, /* 1 = Failure */
+ CMD_RET_USAGE = -1, /* Failure, please report 'usage' error */
+};
+
+/**
+ * Process a command with arguments. We look up the command and execute it
+ * if valid. Otherwise we print a usage message.
+ *
+ * @param flag Some flags normally 0 (see CMD_FLAG_.. above)
+ * @param argc Number of arguments (arg 0 must be the command text)
+ * @param argv Arguments
+ * @param repeatable This function sets this to 0 if the command is not
+ * repeatable. If the command is repeatable, the value
+ * is left unchanged.
+ * @param ticks If ticks is not null, this function set it to the
+ * number of ticks the command took to complete.
+ * @return 0 if the command succeeded, 1 if it failed
+ */
+int cmd_process(int flag, int argc, char * const argv[],
+ int *repeatable, unsigned long *ticks);
+
#endif /* __ASSEMBLY__ */
/*
@@ -110,27 +140,36 @@ extern int cmd_get_data_size(char* arg, int default_size);
#define CMD_FLAG_REPEAT 0x0001 /* repeat last command */
#define CMD_FLAG_BOOTD 0x0002 /* command is from bootd */
-#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
-
-#ifdef CONFIG_SYS_LONGHELP
-
-#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
-cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
-
-#define U_BOOT_CMD_MKENT(name,maxargs,rep,cmd,usage,help) \
-{#name, maxargs, rep, cmd, usage, help}
+#ifdef CONFIG_AUTO_COMPLETE
+# define _CMD_COMPLETE(x) x,
+#else
+# define _CMD_COMPLETE(x)
+#endif
+#ifdef CONFIG_SYS_LONGHELP
+# define _CMD_HELP(x) x,
+#else
+# define _CMD_HELP(x)
+#endif
-#else /* no long help info */
+#define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
+ _usage, _help, _comp) \
+ { #_name, _maxargs, _rep, _cmd, _usage, \
+ _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
-#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
-cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}
+#define U_BOOT_CMD_MKENT(_name, _maxargs, _rep, _cmd, _usage, _help) \
+ U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
+ _usage, _help, NULL)
-#define U_BOOT_CMD_MKENT(name,maxargs,rep,cmd,usage,help) \
-{#name, maxargs, rep, cmd, usage}
+#define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
+ ll_entry_declare(cmd_tbl_t, _name, cmd) = \
+ U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
+ _usage, _help, _comp);
-#endif /* CONFIG_SYS_LONGHELP */
+#define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \
+ U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
void fixup_cmdtable(cmd_tbl_t *cmdtp, int size);
#endif
+
#endif /* __COMMAND_H */
diff --git a/include/common.h b/include/common.h
index 0d9458ec84..84beafb7c7 100644
--- a/include/common.h
+++ b/include/common.h
@@ -39,6 +39,7 @@ typedef volatile unsigned char vu_char;
#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/stringify.h>
#include <asm/ptrace.h>
#include <stdarg.h>
#if defined(CONFIG_PCI) && (defined(CONFIG_4xx) && !defined(CONFIG_AP1000))
@@ -270,13 +271,28 @@ void print_size(unsigned long long, const char *);
int print_buffer (ulong addr, void* data, uint width, uint count, uint linelen);
/* common/main.c */
-void main_loop (void);
-int run_command (const char *cmd, int flag);
-int readline (const char *const prompt);
-int readline_into_buffer (const char *const prompt, char * buffer);
-int parse_line (char *, char *[]);
-void init_cmd_timeout(void);
-void reset_cmd_timeout(void);
+void main_loop (void);
+int run_command(const char *cmd, int flag);
+
+/*
+ * Run a list of commands separated by ; or even \0
+ *
+ * Note that if 'len' is not -1, then the command does not need to be nul
+ * terminated, Memory will be allocated for the command in that case.
+ *
+ * @param cmd List of commands to run, each separated bu semicolon
+ * @param len Length of commands excluding terminator if known (-1 if not)
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command_list(const char *cmd, int len, int flag);
+int readline (const char *const prompt);
+int readline_into_buffer(const char *const prompt, char *buffer,
+ int timeout);
+int parse_line (char *, char *[]);
+void init_cmd_timeout(void);
+void reset_cmd_timeout(void);
+extern char console_buffer[];
/* arch/$(ARCH)/lib/board.c */
void board_init_f (ulong) __attribute__ ((noreturn));
@@ -300,17 +316,46 @@ extern ulong load_addr; /* Default Load Address */
void doc_probe(unsigned long physadr);
/* common/cmd_nvedit.c */
-int env_init (void);
-void env_relocate (void);
-int envmatch (uchar *, int);
-char *getenv (char *);
-int getenv_f (char *name, char *buf, unsigned len);
-int saveenv (void);
-#ifdef CONFIG_PPC /* ARM version to be fixed! */
-int inline setenv (char *, char *);
-#else
-int setenv (char *, char *);
-#endif /* CONFIG_PPC */
+int env_init (void);
+void env_relocate (void);
+int envmatch (uchar *, int);
+char *getenv (const char *);
+int getenv_f (const char *name, char *buf, unsigned len);
+ulong getenv_ulong(const char *name, int base, ulong default_val);
+
+/*
+ * getenv_hex() - Return an environment variable as a hex value
+ *
+ * Decode an environment as a hex number (it may or may not have a 0x
+ * prefix). If the environment variable cannot be found, or does not start
+ * with hex digits, the default value is returned.
+ *
+ * @varname: Variable to decode
+ * @default_val: Value to return on error
+ */
+ulong getenv_hex(const char *varname, ulong default_val);
+
+/*
+ * Read an environment variable as a boolean
+ * Return -1 if variable does not exist (default to true)
+ */
+int getenv_yesno(const char *var);
+int saveenv (void);
+int setenv (const char *, const char *);
+int setenv_ulong(const char *varname, ulong value);
+int setenv_hex(const char *varname, ulong value);
+/*
+ * setenv_addr - Set an environment variable to an address in hex
+ *
+ * @varname: Environment variable to set
+ * @addr: Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+static inline int setenv_addr(const char *varname, const void *addr)
+{
+ return setenv_hex(varname, (ulong)addr);
+}
+
#ifdef CONFIG_ARM
# include <asm/mach-types.h>
# include <asm/setup.h>
@@ -684,14 +729,7 @@ void udelay (unsigned long);
void mdelay (unsigned long msec);
/* lib/vsprintf.c */
-ulong simple_strtoul(const char *cp,char **endp,unsigned int base);
-unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base);
-long simple_strtol(const char *cp,char **endp,unsigned int base);
-void panic(const char *fmt, ...)
- __attribute__ ((format (__printf__, 1, 2)));
-int sprintf(char * buf, const char *fmt, ...)
- __attribute__ ((format (__printf__, 2, 3)));
-int vsprintf(char *buf, const char *fmt, va_list args);
+#include <vsprintf.h>
/* lib/strmhz.c */
char * strmhz(char *buf, long hz);
@@ -702,7 +740,7 @@ char * strmhz(char *buf, long hz);
/* common/console.c */
int console_init_f(void); /* Before relocation; uses the serial stuff */
int console_init_r(void); /* After relocation; uses the console stuff */
-int console_assign (int file, char *devname); /* Assign the console */
+int console_assign(int file, const char *devname); /* Assign the console */
int ctrlc (void);
int had_ctrlc (void); /* have we had a Control-C since last clear? */
void clear_ctrlc (void); /* clear the Control-C condition */
diff --git a/include/configs/smdk4412.h b/include/configs/smdk4412.h
index edd729e565..ecafdba4f6 100644
--- a/include/configs/smdk4412.h
+++ b/include/configs/smdk4412.h
@@ -189,6 +189,19 @@
#define CONFIG_ENV_OVERWRITE
#define CONFIG_BAUDRATE 115200
+/* USB KEYBOARD */
+#define CONFIG_USB_KEYBOARD
+#define CONFIG_SYS_USB_EVENT_POLL
+
+/* NETCONSOLE */
+#define CONFIG_NETCONSOLE
+
+/* CONSOLE MUX */
+#define CONFIG_CONSOLE_MUX
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV
+
+#define CONFIG_CMD_BOOTM
+
/***********************************************************
* Command definition
***********************************************************/
diff --git a/include/env_attr.h b/include/env_attr.h
new file mode 100644
index 0000000000..b82fec91be
--- /dev/null
+++ b/include/env_attr.h
@@ -0,0 +1,39 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ENV_ATTR_H__
+#define __ENV_ATTR_H__
+
+#define ENV_ATTR_LIST_DELIM ','
+#define ENV_ATTR_SEP ':'
+
+/*
+ * env_attr_walk takes as input an "attr_list" that takes the form:
+ * attributes = [^,:\s]*
+ * entry = name[:attributes]
+ * list = entry[,list]
+ * It will call the "callback" function with the "name" and attribute as "value"
+ * The callback may return a non-0 to abort the list walk.
+ * This return value will be passed through to the caller.
+ * 0 is returned on success.
+ */
+extern int env_attr_walk(const char *attr_list,
+ int (*callback)(const char *name, const char *value));
+
+/*
+ * env_attr_lookup takes as input an "attr_list" with the same form as above.
+ * It also takes as input a "name" to look for.
+ * If the name is found in the list, it's value is copied into "attributes".
+ * There is no protection on attributes being too small for the value.
+ * It returns -1 if attributes is NULL, 1 if "name" is not found, 2 if
+ * "attr_list" is NULL.
+ * Returns 0 on success.
+ */
+extern int env_attr_lookup(const char *attr_list, const char *name,
+ char *attributes);
+
+#endif /* __ENV_ATTR_H__ */
diff --git a/include/env_callback.h b/include/env_callback.h
new file mode 100644
index 0000000000..f90a7fa3b6
--- /dev/null
+++ b/include/env_callback.h
@@ -0,0 +1,73 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ENV_CALLBACK_H__
+#define __ENV_CALLBACK_H__
+
+#include <env_flags.h>
+#include <linker_lists.h>
+#include <search.h>
+
+#define ENV_CALLBACK_VAR ".callbacks"
+
+/* Board configs can define additional static callback bindings */
+#ifndef CONFIG_ENV_CALLBACK_LIST_STATIC
+#define CONFIG_ENV_CALLBACK_LIST_STATIC
+#endif
+
+#ifdef CONFIG_SILENT_CONSOLE
+#define SILENT_CALLBACK "silent:silent,"
+#else
+#define SILENT_CALLBACK
+#endif
+
+#ifdef CONFIG_SPLASHIMAGE_GUARD
+#define SPLASHIMAGE_CALLBACK "splashimage:splashimage,"
+#else
+#define SPLASHIMAGE_CALLBACK
+#endif
+
+/*
+ * This list of callback bindings is static, but may be overridden by defining
+ * a new association in the ".callbacks" environment variable.
+ */
+#define ENV_CALLBACK_LIST_STATIC ENV_CALLBACK_VAR ":callbacks," \
+ ENV_FLAGS_VAR ":flags," \
+ "baudrate:baudrate," \
+ "bootfile:bootfile," \
+ "loadaddr:loadaddr," \
+ SILENT_CALLBACK \
+ SPLASHIMAGE_CALLBACK \
+ "stdin:console,stdout:console,stderr:console," \
+ CONFIG_ENV_CALLBACK_LIST_STATIC
+
+struct env_clbk_tbl {
+ const char *name; /* Callback name */
+ int (*callback)(const char *name, const char *value, enum env_op op,
+ int flags);
+};
+
+void env_callback_init(ENTRY *var_entry);
+
+/*
+ * Define a callback that can be associated with variables.
+ * when associated through the ".callbacks" environment variable, the callback
+ * will be executed any time the variable is inserted, overwritten, or deleted.
+ */
+#ifdef CONFIG_SPL_BUILD
+#define U_BOOT_ENV_CALLBACK(name, callback) \
+ static inline void _u_boot_env_noop_##name(void) \
+ { \
+ (void)callback; \
+ }
+#else
+#define U_BOOT_ENV_CALLBACK(name, callback) \
+ ll_entry_declare(struct env_clbk_tbl, name, env_clbk) = \
+ {#name, callback}
+#endif
+
+#endif /* __ENV_CALLBACK_H__ */
diff --git a/include/env_default.h b/include/env_default.h
new file mode 100644
index 0000000000..b2d4e52e58
--- /dev/null
+++ b/include/env_default.h
@@ -0,0 +1,138 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Andreas Heppel <aheppel@sysgo.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <env_callback.h>
+
+#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
+env_t environment __PPCENV__ = {
+ ENV_CRC, /* CRC Sum */
+#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
+ 1, /* Flags: valid */
+#endif
+ {
+#elif defined(DEFAULT_ENV_INSTANCE_STATIC)
+static char default_environment[] = {
+#else
+const unsigned char default_environment[] = {
+#endif
+#if defined(CONFIG_HKDK4412) && defined(CONFIG_EXYNOS_PRIME)
+ "bootscript=source 40008000\0"
+ "default_bootcmd=echo >>> Run Default Bootcmd <<<;movi read kernel 0 40008000;movi read rootfs 0 41000000 100000;bootm 40008000 41000000\0"
+ "loadbootscript_1=echo >>> Load Boot Script from mmc 0:1 <<<;fatload mmc 0:1 40008000 boot.scr\0"
+ "loadbootscript_2=echo >>> Load Boot Script from mmc 0:2 <<<;fatload mmc 0:2 40008000 boot.scr\0"
+#endif
+
+#ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT
+ ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
+#endif
+#ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT
+ ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
+#endif
+#ifdef CONFIG_BOOTARGS
+ "bootargs=" CONFIG_BOOTARGS "\0"
+#endif
+#ifdef CONFIG_BOOTCOMMAND
+ "bootcmd=" CONFIG_BOOTCOMMAND "\0"
+#endif
+#ifdef CONFIG_RAMBOOTCOMMAND
+ "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
+#endif
+#ifdef CONFIG_NFSBOOTCOMMAND
+ "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
+#endif
+#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ "bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0"
+#endif
+#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
+ "baudrate=" __stringify(CONFIG_BAUDRATE) "\0"
+#endif
+#ifdef CONFIG_LOADS_ECHO
+ "loads_echo=" __stringify(CONFIG_LOADS_ECHO) "\0"
+#endif
+#ifdef CONFIG_ETHADDR
+ "ethaddr=" __stringify(CONFIG_ETHADDR) "\0"
+#endif
+#ifdef CONFIG_ETH1ADDR
+ "eth1addr=" __stringify(CONFIG_ETH1ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH2ADDR
+ "eth2addr=" __stringify(CONFIG_ETH2ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH3ADDR
+ "eth3addr=" __stringify(CONFIG_ETH3ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH4ADDR
+ "eth4addr=" __stringify(CONFIG_ETH4ADDR) "\0"
+#endif
+#ifdef CONFIG_ETH5ADDR
+ "eth5addr=" __stringify(CONFIG_ETH5ADDR) "\0"
+#endif
+#ifdef CONFIG_ETHPRIME
+ "ethprime=" CONFIG_ETHPRIME "\0"
+#endif
+#ifdef CONFIG_IPADDR
+ "ipaddr=" __stringify(CONFIG_IPADDR) "\0"
+#endif
+#ifdef CONFIG_SERVERIP
+ "serverip=" __stringify(CONFIG_SERVERIP) "\0"
+#endif
+#ifdef CONFIG_SYS_AUTOLOAD
+ "autoload=" CONFIG_SYS_AUTOLOAD "\0"
+#endif
+#ifdef CONFIG_PREBOOT
+ "preboot=" CONFIG_PREBOOT "\0"
+#endif
+#ifdef CONFIG_ROOTPATH
+ "rootpath=" CONFIG_ROOTPATH "\0"
+#endif
+#ifdef CONFIG_GATEWAYIP
+ "gatewayip=" __stringify(CONFIG_GATEWAYIP) "\0"
+#endif
+#ifdef CONFIG_NETMASK
+ "netmask=" __stringify(CONFIG_NETMASK) "\0"
+#endif
+#ifdef CONFIG_HOSTNAME
+ "hostname=" __stringify(CONFIG_HOSTNAME) "\0"
+#endif
+#ifdef CONFIG_BOOTFILE
+ "bootfile=" CONFIG_BOOTFILE "\0"
+#endif
+#ifdef CONFIG_LOADADDR
+ "loadaddr=" __stringify(CONFIG_LOADADDR) "\0"
+#endif
+#ifdef CONFIG_CLOCKS_IN_MHZ
+ "clocks_in_mhz=1\0"
+#endif
+#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
+ "pcidelay=" __stringify(CONFIG_PCI_BOOTDELAY)"\0"
+#endif
+#ifdef CONFIG_ENV_VARS_UBOOT_CONFIG
+ "arch=" CONFIG_SYS_ARCH "\0"
+ "cpu=" CONFIG_SYS_CPU "\0"
+ "board=" CONFIG_SYS_BOARD "\0"
+ "board_name=" CONFIG_SYS_BOARD "\0"
+#ifdef CONFIG_SYS_VENDOR
+ "vendor=" CONFIG_SYS_VENDOR "\0"
+#endif
+#ifdef CONFIG_SYS_SOC
+ "soc=" CONFIG_SYS_SOC "\0"
+#endif
+#endif
+#ifdef CONFIG_EXTRA_ENV_SETTINGS
+ CONFIG_EXTRA_ENV_SETTINGS
+#endif
+ "\0"
+#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
+ }
+#endif
+};
+
+int default_environment_size = sizeof(default_environment);
+
diff --git a/include/env_flags.h b/include/env_flags.h
new file mode 100644
index 0000000000..3ef631105f
--- /dev/null
+++ b/include/env_flags.h
@@ -0,0 +1,156 @@
+/*
+ * (C) Copyright 2012
+ * Joe Hershberger, National Instruments, joe.hershberger@ni.com
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ENV_FLAGS_H__
+#define __ENV_FLAGS_H__
+
+enum env_flags_vartype {
+ env_flags_vartype_string,
+ env_flags_vartype_decimal,
+ env_flags_vartype_hex,
+ env_flags_vartype_bool,
+#ifdef CONFIG_CMD_NET
+ env_flags_vartype_ipaddr,
+ env_flags_vartype_macaddr,
+#endif
+ env_flags_vartype_end
+};
+
+enum env_flags_varaccess {
+ env_flags_varaccess_any,
+ env_flags_varaccess_readonly,
+ env_flags_varaccess_writeonce,
+ env_flags_varaccess_changedefault,
+ env_flags_varaccess_end
+};
+
+#define ENV_FLAGS_VAR ".flags"
+#define ENV_FLAGS_ATTR_MAX_LEN 2
+#define ENV_FLAGS_VARTYPE_LOC 0
+#define ENV_FLAGS_VARACCESS_LOC 1
+
+#ifndef CONFIG_ENV_FLAGS_LIST_STATIC
+#define CONFIG_ENV_FLAGS_LIST_STATIC ""
+#endif
+
+#ifdef CONFIG_CMD_NET
+#ifdef CONFIG_ENV_OVERWRITE
+#define ETHADDR_FLAGS "ethaddr:ma,"
+#else
+#ifdef CONFIG_OVERWRITE_ETHADDR_ONCE
+#define ETHADDR_FLAGS "ethaddr:mc,"
+#else
+#define ETHADDR_FLAGS "ethaddr:mo,"
+#endif
+#endif
+#else
+#define ETHADDR_FLAGS ""
+#endif
+
+#ifndef CONFIG_ENV_OVERWRITE
+#define SERIAL_FLAGS "serial#:so,"
+#else
+#define SERIAL_FLAGS ""
+#endif
+
+#define ENV_FLAGS_LIST_STATIC \
+ ETHADDR_FLAGS \
+ SERIAL_FLAGS \
+ CONFIG_ENV_FLAGS_LIST_STATIC
+
+#ifdef CONFIG_CMD_ENV_FLAGS
+/*
+ * Print the whole list of available type flags.
+ */
+void env_flags_print_vartypes(void);
+/*
+ * Print the whole list of available access flags.
+ */
+void env_flags_print_varaccess(void);
+/*
+ * Return the name of the type.
+ */
+const char *env_flags_get_vartype_name(enum env_flags_vartype type);
+/*
+ * Return the name of the access.
+ */
+const char *env_flags_get_varaccess_name(enum env_flags_varaccess access);
+#endif
+
+/*
+ * Parse the flags string from a .flags attribute list into the vartype enum.
+ */
+enum env_flags_vartype env_flags_parse_vartype(const char *flags);
+/*
+ * Parse the flags string from a .flags attribute list into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess(const char *flags);
+/*
+ * Parse the binary flags from a hash table entry into the varaccess enum.
+ */
+enum env_flags_varaccess env_flags_parse_varaccess_from_binflags(int binflags);
+
+#ifdef USE_HOSTCC
+/*
+ * Look up the type of a variable directly from the .flags var.
+ */
+enum env_flags_vartype env_flags_get_type(const char *name);
+/*
+ * Look up the access of a variable directly from the .flags var.
+ */
+enum env_flags_varaccess env_flags_get_access(const char *name);
+/*
+ * Validate the newval for its type to conform with the requirements defined by
+ * its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_type(const char *name, const char *newval);
+/*
+ * Validate the newval for its access to conform with the requirements defined
+ * by its flags (directly looked at the .flags var).
+ */
+int env_flags_validate_access(const char *name, int check_mask);
+/*
+ * Validate that the proposed access to variable "name" is valid according to
+ * the defined flags for that variable, if any.
+ */
+int env_flags_validate_varaccess(const char *name, int check_mask);
+/*
+ * Validate the parameters passed to "env set" for type compliance
+ */
+int env_flags_validate_env_set_params(int argc, char * const argv[]);
+
+#else /* !USE_HOSTCC */
+
+#include <search.h>
+
+/*
+ * When adding a variable to the environment, initialize the flags for that
+ * variable.
+ */
+void env_flags_init(ENTRY *var_entry);
+
+/*
+ * Validate the newval for to conform with the requirements defined by its flags
+ */
+int env_flags_validate(const ENTRY *item, const char *newval, enum env_op op,
+ int flag);
+
+#endif /* USE_HOSTCC */
+
+/*
+ * These are the binary flags used in the environment entry->flags variable to
+ * decribe properties of veriables in the table
+ */
+#define ENV_FLAGS_VARTYPE_BIN_MASK 0x00000007
+/* The actual variable type values use the enum value (within the mask) */
+#define ENV_FLAGS_VARACCESS_PREVENT_DELETE 0x00000008
+#define ENV_FLAGS_VARACCESS_PREVENT_CREATE 0x00000010
+#define ENV_FLAGS_VARACCESS_PREVENT_OVERWR 0x00000020
+#define ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR 0x00000040
+#define ENV_FLAGS_VARACCESS_BIN_MASK 0x00000078
+
+#endif /* __ENV_FLAGS_H__ */
diff --git a/include/environment.h b/include/environment.h
index bedbc54242..46a3554ff9 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -2,27 +2,11 @@
* (C) Copyright 2002
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _ENVIRONMENT_H_
-#define _ENVIRONMENT_H_ 1
+#define _ENVIRONMENT_H_
/**************************************************************************
*
@@ -38,21 +22,22 @@
*/
#if defined(CONFIG_ENV_IS_IN_FLASH)
-# ifndef CONFIG_ENV_ADDR
-# define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
+# ifndef CONFIG_ENV_ADDR
+# define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
# endif
-# ifndef CONFIG_ENV_OFFSET
-# define CONFIG_ENV_OFFSET (CONFIG_ENV_ADDR - CONFIG_SYS_FLASH_BASE)
+# ifndef CONFIG_ENV_OFFSET
+# define CONFIG_ENV_OFFSET (CONFIG_ENV_ADDR - CONFIG_SYS_FLASH_BASE)
# endif
# if !defined(CONFIG_ENV_ADDR_REDUND) && defined(CONFIG_ENV_OFFSET_REDUND)
-# define CONFIG_ENV_ADDR_REDUND (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET_REDUND)
+# define CONFIG_ENV_ADDR_REDUND \
+ (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET_REDUND)
# endif
# if defined(CONFIG_ENV_SECT_SIZE) || defined(CONFIG_ENV_SIZE)
-# ifndef CONFIG_ENV_SECT_SIZE
-# define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE
+# ifndef CONFIG_ENV_SECT_SIZE
+# define CONFIG_ENV_SECT_SIZE CONFIG_ENV_SIZE
# endif
-# ifndef CONFIG_ENV_SIZE
-# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
+# ifndef CONFIG_ENV_SIZE
+# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
# endif
# else
# error "Both CONFIG_ENV_SECT_SIZE and CONFIG_ENV_SIZE undefined"
@@ -60,12 +45,13 @@
# if defined(CONFIG_ENV_ADDR_REDUND) && !defined(CONFIG_ENV_SIZE_REDUND)
# define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE
# endif
-# if (CONFIG_ENV_ADDR >= CONFIG_SYS_MONITOR_BASE) && \
- (CONFIG_ENV_ADDR+CONFIG_ENV_SIZE) <= (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN)
-# define ENV_IS_EMBEDDED 1
+# if (CONFIG_ENV_ADDR >= CONFIG_SYS_MONITOR_BASE) && \
+ (CONFIG_ENV_ADDR + CONFIG_ENV_SIZE) <= \
+ (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN)
+# define ENV_IS_EMBEDDED
# endif
# if defined(CONFIG_ENV_ADDR_REDUND) || defined(CONFIG_ENV_OFFSET_REDUND)
-# define CONFIG_SYS_REDUNDAND_ENVIRONMENT 1
+# define CONFIG_SYS_REDUNDAND_ENVIRONMENT
# endif
# ifdef CONFIG_ENV_IS_EMBEDDED
# error "do not define CONFIG_ENV_IS_EMBEDDED in your board config"
@@ -73,6 +59,12 @@
# endif
#endif /* CONFIG_ENV_IS_IN_FLASH */
+#if defined(CONFIG_ENV_IS_IN_MMC)
+# ifdef CONFIG_ENV_OFFSET_REDUND
+# define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+# endif
+#endif
+
#if defined(CONFIG_ENV_IS_IN_NAND)
# if defined(CONFIG_ENV_OFFSET_OOB)
# ifdef CONFIG_ENV_OFFSET_REDUND
@@ -94,20 +86,30 @@ extern unsigned long nand_env_oob_offset;
# endif
#endif /* CONFIG_ENV_IS_IN_NAND */
-#if defined(CONFIG_ENV_IS_IN_MG_DISK)
-# ifndef CONFIG_ENV_ADDR
-# error "Need to define CONFIG_ENV_ADDR when using CONFIG_ENV_IS_IN_MG_DISK"
+#if defined(CONFIG_ENV_IS_IN_UBI)
+# ifndef CONFIG_ENV_UBI_PART
+# error "Need to define CONFIG_ENV_UBI_PART when using CONFIG_ENV_IS_IN_UBI"
+# endif
+# ifndef CONFIG_ENV_UBI_VOLUME
+# error "Need to define CONFIG_ENV_UBI_VOLUME when using CONFIG_ENV_IS_IN_UBI"
+# endif
+# if defined(CONFIG_ENV_UBI_VOLUME_REDUND)
+# define CONFIG_SYS_REDUNDAND_ENVIRONMENT
# endif
# ifndef CONFIG_ENV_SIZE
-# error "Need to define CONFIG_ENV_SIZE when using CONFIG_ENV_IS_IN_MG_DISK"
+# error "Need to define CONFIG_ENV_SIZE when using CONFIG_ENV_IS_IN_UBI"
+# endif
+# ifndef CONFIG_CMD_UBI
+# error "Need to define CONFIG_CMD_UBI when using CONFIG_ENV_IS_IN_UBI"
# endif
-#endif /* CONFIG_ENV_IS_IN_MG_DISK */
+#endif /* CONFIG_ENV_IS_IN_UBI */
/* Embedded env is only supported for some flash types */
#ifdef CONFIG_ENV_IS_EMBEDDED
-# if !defined(CONFIG_ENV_IS_IN_FLASH) && \
- !defined(CONFIG_ENV_IS_IN_NAND) && \
- !defined(CONFIG_ENV_IS_IN_ONENAND)
+# if !defined(CONFIG_ENV_IS_IN_FLASH) && \
+ !defined(CONFIG_ENV_IS_IN_NAND) && \
+ !defined(CONFIG_ENV_IS_IN_ONENAND) && \
+ !defined(CONFIG_ENV_IS_IN_SPI_FLASH)
# error "CONFIG_ENV_IS_EMBEDDED not supported for your flash type"
# endif
#endif
@@ -117,13 +119,15 @@ extern unsigned long nand_env_oob_offset;
* calculated automatically (i.e. NAND), take the board opt-in.
*/
#if defined(CONFIG_ENV_IS_EMBEDDED) && !defined(ENV_IS_EMBEDDED)
-# define ENV_IS_EMBEDDED 1
+# define ENV_IS_EMBEDDED
#endif
/* The build system likes to know if the env is embedded */
#ifdef DO_DEPS_ONLY
# ifdef ENV_IS_EMBEDDED
-# define CONFIG_ENV_IS_EMBEDDED
+# ifndef CONFIG_ENV_IS_EMBEDDED
+# define CONFIG_ENV_IS_EMBEDDED
+# endif
# endif
#endif
@@ -138,10 +142,13 @@ extern unsigned long nand_env_oob_offset;
# define ENV_HEADER_SIZE (sizeof(uint32_t))
#endif
+#if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_ENV_IS_NOWHERE)
+extern char *env_name_spec;
+#endif
#define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)
-typedef struct environment_s {
+typedef struct environment_s {
uint32_t crc; /* CRC32 over data bytes */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
unsigned char flags; /* active/obsolete flags */
@@ -149,20 +156,51 @@ typedef struct environment_s {
unsigned char data[ENV_SIZE]; /* Environment data */
} env_t;
+#ifdef ENV_IS_EMBEDDED
+extern env_t environment;
+#endif /* ENV_IS_EMBEDDED */
+
+extern const unsigned char default_environment[];
+extern env_t *env_ptr;
+
+extern void env_relocate_spec(void);
+extern unsigned char env_get_char_spec(int);
+
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+extern void env_reloc(void);
+#endif
+
+#ifndef DO_DEPS_ONLY
+
+#include <env_attr.h>
+#include <env_callback.h>
+#include <env_flags.h>
+#include <search.h>
+
+extern struct hsearch_data env_htab;
+
/* Function that returns a character from the environment */
-unsigned char env_get_char (int);
+unsigned char env_get_char(int);
/* Function that returns a pointer to a value from the environment */
-unsigned char *env_get_addr(int);
-unsigned char env_get_char_memory (int index);
+const unsigned char *env_get_addr(int);
+unsigned char env_get_char_memory(int index);
/* Function that updates CRC of the enironment */
-void env_crc_update (void);
+void env_crc_update(void);
+
+/* Look up the variable from the default environment */
+char *getenv_default(const char *name);
/* [re]set to the default environment */
void set_default_env(const char *s);
+/* [re]set individual variables to their value in the default environment */
+int set_default_vars(int nvars, char * const vars[]);
+
/* Import from binary representation into hash table */
int env_import(const char *buf, int check);
-#endif /* _ENVIRONMENT_H_ */
+#endif /* DO_DEPS_ONLY */
+
+#endif /* _ENVIRONMENT_H_ */
diff --git a/include/exports.h b/include/exports.h
index 7404a7c843..b8b65e6e31 100644
--- a/include/exports.h
+++ b/include/exports.h
@@ -19,10 +19,10 @@ void free(void*);
void __udelay(unsigned long);
unsigned long get_timer(unsigned long);
int vprintf(const char *, va_list);
-void do_reset (void);
+extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
-char *getenv (char *name);
-int setenv (char *varname, char *varvalue);
+char *getenv (const char *name);
+int setenv (const char *varname, const char *varvalue);
long simple_strtol(const char *cp,char **endp,unsigned int base);
int strcmp(const char * cs,const char * ct);
int ustrtoul(const char *cp, char **endp, unsigned int base);
diff --git a/include/fdtdec.h b/include/fdtdec.h
new file mode 100644
index 0000000000..6bf83bf7c1
--- /dev/null
+++ b/include/fdtdec.h
@@ -0,0 +1,530 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __fdtdec_h
+#define __fdtdec_h
+
+/*
+ * This file contains convenience functions for decoding useful and
+ * enlightening information from FDTs. It is intended to be used by device
+ * drivers and board-specific code within U-Boot. It aims to reduce the
+ * amount of FDT munging required within U-Boot itself, so that driver code
+ * changes to support FDT are minimized.
+ */
+
+#include <libfdt.h>
+
+/*
+ * A typedef for a physical address. Note that fdt data is always big
+ * endian even on a litle endian machine.
+ */
+#ifdef CONFIG_PHYS_64BIT
+typedef u64 fdt_addr_t;
+typedef u64 fdt_size_t;
+#define FDT_ADDR_T_NONE (-1ULL)
+#define fdt_addr_to_cpu(reg) be64_to_cpu(reg)
+#define fdt_size_to_cpu(reg) be64_to_cpu(reg)
+#else
+typedef u32 fdt_addr_t;
+typedef u32 fdt_size_t;
+#define FDT_ADDR_T_NONE (-1U)
+#define fdt_addr_to_cpu(reg) be32_to_cpu(reg)
+#define fdt_size_to_cpu(reg) be32_to_cpu(reg)
+#endif
+
+/* Information obtained about memory from the FDT */
+struct fdt_memory {
+ fdt_addr_t start;
+ fdt_addr_t end;
+};
+
+/**
+ * Compat types that we know about and for which we might have drivers.
+ * Each is named COMPAT_<dir>_<filename> where <dir> is the directory
+ * within drivers.
+ */
+enum fdt_compat_id {
+ COMPAT_UNKNOWN,
+ COMPAT_NVIDIA_TEGRA20_USB, /* Tegra20 USB port */
+ COMPAT_NVIDIA_TEGRA30_USB, /* Tegra30 USB port */
+ COMPAT_NVIDIA_TEGRA114_USB, /* Tegra114 USB port */
+ COMPAT_NVIDIA_TEGRA114_I2C, /* Tegra114 I2C w/single clock source */
+ COMPAT_NVIDIA_TEGRA20_I2C, /* Tegra20 i2c */
+ COMPAT_NVIDIA_TEGRA20_DVC, /* Tegra20 dvc (really just i2c) */
+ COMPAT_NVIDIA_TEGRA20_EMC, /* Tegra20 memory controller */
+ COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */
+ COMPAT_NVIDIA_TEGRA20_KBC, /* Tegra20 Keyboard */
+ COMPAT_NVIDIA_TEGRA20_NAND, /* Tegra2 NAND controller */
+ COMPAT_NVIDIA_TEGRA20_PWM, /* Tegra 2 PWM controller */
+ COMPAT_NVIDIA_TEGRA20_DC, /* Tegra 2 Display controller */
+ COMPAT_NVIDIA_TEGRA30_SDMMC, /* Tegra30 SDMMC controller */
+ COMPAT_NVIDIA_TEGRA20_SDMMC, /* Tegra20 SDMMC controller */
+ COMPAT_NVIDIA_TEGRA20_SFLASH, /* Tegra 2 SPI flash controller */
+ COMPAT_NVIDIA_TEGRA20_SLINK, /* Tegra 2 SPI SLINK controller */
+ COMPAT_NVIDIA_TEGRA114_SPI, /* Tegra 114 SPI controller */
+ COMPAT_SMSC_LAN9215, /* SMSC 10/100 Ethernet LAN9215 */
+ COMPAT_SAMSUNG_EXYNOS5_SROMC, /* Exynos5 SROMC */
+ COMPAT_SAMSUNG_S3C2440_I2C, /* Exynos I2C Controller */
+ COMPAT_SAMSUNG_EXYNOS5_SOUND, /* Exynos Sound */
+ COMPAT_WOLFSON_WM8994_CODEC, /* Wolfson WM8994 Sound Codec */
+ COMPAT_SAMSUNG_EXYNOS_SPI, /* Exynos SPI */
+ COMPAT_GOOGLE_CROS_EC, /* Google CROS_EC Protocol */
+ COMPAT_GOOGLE_CROS_EC_KEYB, /* Google CROS_EC Keyboard */
+ COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */
+ COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */
+ COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */
+ COMPAT_SAMSUNG_EXYNOS_FIMD, /* Exynos Display controller */
+ COMPAT_SAMSUNG_EXYNOS5_DP, /* Exynos Display port controller */
+ COMPAT_SAMSUNG_EXYNOS5_DWMMC, /* Exynos5 DWMMC controller */
+ COMPAT_SAMSUNG_EXYNOS_SERIAL, /* Exynos UART */
+ COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */
+ COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */
+ COMPAT_MAXIM_98095_CODEC, /* MAX98095 Codec */
+ COMPAT_INFINEON_SLB9635_TPM, /* Infineon SLB9635 TPM */
+ COMPAT_INFINEON_SLB9645_TPM, /* Infineon SLB9645 TPM */
+ COMPAT_SAMSUNG_EXYNOS5_I2C, /* Exynos5 High Speed I2C Controller */
+
+ COMPAT_COUNT,
+};
+
+/* GPIOs are numbered from 0 */
+enum {
+ FDT_GPIO_NONE = -1U, /* an invalid GPIO used to end our list */
+
+ FDT_GPIO_ACTIVE_LOW = 1 << 0, /* input is active low (else high) */
+};
+
+/* This is the state of a GPIO pin as defined by the fdt */
+struct fdt_gpio_state {
+ const char *name; /* name of the fdt property defining this */
+ uint gpio; /* GPIO number, or FDT_GPIO_NONE if none */
+ u8 flags; /* FDT_GPIO_... flags */
+};
+
+/* This tells us whether a fdt_gpio_state record is valid or not */
+#define fdt_gpio_isvalid(x) ((x)->gpio != FDT_GPIO_NONE)
+
+/**
+ * Read the GPIO taking into account the polarity of the pin.
+ *
+ * @param gpio pointer to the decoded gpio
+ * @return value of the gpio if successful, < 0 if unsuccessful
+ */
+int fdtdec_get_gpio(struct fdt_gpio_state *gpio);
+
+/**
+ * Write the GPIO taking into account the polarity of the pin.
+ *
+ * @param gpio pointer to the decoded gpio
+ * @return 0 if successful
+ */
+int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val);
+
+/**
+ * Find the next numbered alias for a peripheral. This is used to enumerate
+ * all the peripherals of a certain type.
+ *
+ * Do the first call with *upto = 0. Assuming /aliases/<name>0 exists then
+ * this function will return a pointer to the node the alias points to, and
+ * then update *upto to 1. Next time you call this function, the next node
+ * will be returned.
+ *
+ * All nodes returned will match the compatible ID, as it is assumed that
+ * all peripherals use the same driver.
+ *
+ * @param blob FDT blob to use
+ * @param name Root name of alias to search for
+ * @param id Compatible ID to look for
+ * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more
+ */
+int fdtdec_next_alias(const void *blob, const char *name,
+ enum fdt_compat_id id, int *upto);
+
+/**
+ * Find the compatible ID for a given node.
+ *
+ * Generally each node has at least one compatible string attached to it.
+ * This function looks through our list of known compatible strings and
+ * returns the corresponding ID which matches the compatible string.
+ *
+ * @param blob FDT blob to use
+ * @param node Node containing compatible string to find
+ * @return compatible ID, or COMPAT_UNKNOWN if we cannot find a match
+ */
+enum fdt_compat_id fdtdec_lookup(const void *blob, int node);
+
+/**
+ * Find the next compatible node for a peripheral.
+ *
+ * Do the first call with node = 0. This function will return a pointer to
+ * the next compatible node. Next time you call this function, pass the
+ * value returned, and the next node will be provided.
+ *
+ * @param blob FDT blob to use
+ * @param node Start node for search
+ * @param id Compatible ID to look for (enum fdt_compat_id)
+ * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more
+ */
+int fdtdec_next_compatible(const void *blob, int node,
+ enum fdt_compat_id id);
+
+/**
+ * Find the next compatible subnode for a peripheral.
+ *
+ * Do the first call with node set to the parent and depth = 0. This
+ * function will return the offset of the next compatible node. Next time
+ * you call this function, pass the node value returned last time, with
+ * depth unchanged, and the next node will be provided.
+ *
+ * @param blob FDT blob to use
+ * @param node Start node for search
+ * @param id Compatible ID to look for (enum fdt_compat_id)
+ * @param depthp Current depth (set to 0 before first call)
+ * @return offset of next compatible node, or -FDT_ERR_NOTFOUND if no more
+ */
+int fdtdec_next_compatible_subnode(const void *blob, int node,
+ enum fdt_compat_id id, int *depthp);
+
+/**
+ * Look up an address property in a node and return it as an address.
+ * The property must hold either one address with no trailing data or
+ * one address with a length. This is only tested on 32-bit machines.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr(const void *blob, int node,
+ const char *prop_name);
+
+/**
+ * Look up an address property in a node and return it as an address.
+ * The property must hold one address with a length. This is only tested
+ * on 32-bit machines.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @return address, if found, or FDT_ADDR_T_NONE if not
+ */
+fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
+ const char *prop_name, fdt_size_t *sizep);
+
+/**
+ * Look up a 32-bit integer property in a node and return it. The property
+ * must have at least 4 bytes of data. The value of the first cell is
+ * returned.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param default_val default value to return if the property is not found
+ * @return integer value, if found, or default_val if not
+ */
+s32 fdtdec_get_int(const void *blob, int node, const char *prop_name,
+ s32 default_val);
+
+/**
+ * Look up a 64-bit integer property in a node and return it. The property
+ * must have at least 8 bytes of data (2 cells). The first two cells are
+ * concatenated to form a 8 bytes value, where the first cell is top half and
+ * the second cell is bottom half.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param default_val default value to return if the property is not found
+ * @return integer value, if found, or default_val if not
+ */
+uint64_t fdtdec_get_uint64(const void *blob, int node, const char *prop_name,
+ uint64_t default_val);
+
+/**
+ * Checks whether a node is enabled.
+ * This looks for a 'status' property. If this exists, then returns 1 if
+ * the status is 'ok' and 0 otherwise. If there is no status property,
+ * it returns 1 on the assumption that anything mentioned should be enabled
+ * by default.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @return integer value 0 (not enabled) or 1 (enabled)
+ */
+int fdtdec_get_is_enabled(const void *blob, int node);
+
+/**
+ * Make sure we have a valid fdt available to control U-Boot.
+ *
+ * If not, a message is printed to the console if the console is ready.
+ *
+ * @return 0 if all ok, -1 if not
+ */
+int fdtdec_prepare_fdt(void);
+
+/**
+ * Checks that we have a valid fdt available to control U-Boot.
+
+ * However, if not then for the moment nothing is done, since this function
+ * is called too early to panic().
+ *
+ * @returns 0
+ */
+int fdtdec_check_fdt(void);
+
+/**
+ * Find the nodes for a peripheral and return a list of them in the correct
+ * order. This is used to enumerate all the peripherals of a certain type.
+ *
+ * To use this, optionally set up a /aliases node with alias properties for
+ * a peripheral. For example, for usb you could have:
+ *
+ * aliases {
+ * usb0 = "/ehci@c5008000";
+ * usb1 = "/ehci@c5000000";
+ * };
+ *
+ * Pass "usb" as the name to this function and will return a list of two
+ * nodes offsets: /ehci@c5008000 and ehci@c5000000.
+ *
+ * All nodes returned will match the compatible ID, as it is assumed that
+ * all peripherals use the same driver.
+ *
+ * If no alias node is found, then the node list will be returned in the
+ * order found in the fdt. If the aliases mention a node which doesn't
+ * exist, then this will be ignored. If nodes are found with no aliases,
+ * they will be added in any order.
+ *
+ * If there is a gap in the aliases, then this function return a 0 node at
+ * that position. The return value will also count these gaps.
+ *
+ * This function checks node properties and will not return nodes which are
+ * marked disabled (status = "disabled").
+ *
+ * @param blob FDT blob to use
+ * @param name Root name of alias to search for
+ * @param id Compatible ID to look for
+ * @param node_list Place to put list of found nodes
+ * @param maxcount Maximum number of nodes to find
+ * @return number of nodes found on success, FTD_ERR_... on error
+ */
+int fdtdec_find_aliases_for_id(const void *blob, const char *name,
+ enum fdt_compat_id id, int *node_list, int maxcount);
+
+/*
+ * This function is similar to fdtdec_find_aliases_for_id() except that it
+ * adds to the node_list that is passed in. Any 0 elements are considered
+ * available for allocation - others are considered already used and are
+ * skipped.
+ *
+ * You can use this by calling fdtdec_find_aliases_for_id() with an
+ * uninitialised array, then setting the elements that are returned to -1,
+ * say, then calling this function, perhaps with a different compat id.
+ * Any elements you get back that are >0 are new nodes added by the call
+ * to this function.
+ *
+ * Note that if you have some nodes with aliases and some without, you are
+ * sailing close to the wind. The call to fdtdec_find_aliases_for_id() with
+ * one compat_id may fill in positions for which you have aliases defined
+ * for another compat_id. When you later call *this* function with the second
+ * compat_id, the alias positions may already be used. A debug warning may
+ * be generated in this case, but it is safest to define aliases for all
+ * nodes when you care about the ordering.
+ */
+int fdtdec_add_aliases_for_id(const void *blob, const char *name,
+ enum fdt_compat_id id, int *node_list, int maxcount);
+
+/*
+ * Get the name for a compatible ID
+ *
+ * @param id Compatible ID to look for
+ * @return compatible string for that id
+ */
+const char *fdtdec_get_compatible(enum fdt_compat_id id);
+
+/* Look up a phandle and follow it to its node. Then return the offset
+ * of that node.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @return node offset if found, -ve error code on error
+ */
+int fdtdec_lookup_phandle(const void *blob, int node, const char *prop_name);
+
+/**
+ * Look up a property in a node and return its contents in an integer
+ * array of given length. The property must have at least enough data for
+ * the array (4*count bytes). It may have more, but this will be ignored.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param array array to fill with data
+ * @param count number of array elements
+ * @return 0 if ok, or -FDT_ERR_NOTFOUND if the property is not found,
+ * or -FDT_ERR_BADLAYOUT if not enough data
+ */
+int fdtdec_get_int_array(const void *blob, int node, const char *prop_name,
+ u32 *array, int count);
+
+/**
+ * Look up a property in a node and return a pointer to its contents as a
+ * unsigned int array of given length. The property must have at least enough
+ * data for the array ('count' cells). It may have more, but this will be
+ * ignored. The data is not copied.
+ *
+ * Note that you must access elements of the array with fdt32_to_cpu(),
+ * since the elements will be big endian even on a little endian machine.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param count number of array elements
+ * @return pointer to array if found, or NULL if the property is not
+ * found or there is not enough data
+ */
+const u32 *fdtdec_locate_array(const void *blob, int node,
+ const char *prop_name, int count);
+
+/**
+ * Look up a boolean property in a node and return it.
+ *
+ * A boolean properly is true if present in the device tree and false if not
+ * present, regardless of its value.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @return 1 if the properly is present; 0 if it isn't present
+ */
+int fdtdec_get_bool(const void *blob, int node, const char *prop_name);
+
+/**
+ * Decode a single GPIOs from an FDT.
+ *
+ * If the property is not found, then the GPIO structure will still be
+ * initialised, with gpio set to FDT_GPIO_NONE. This makes it easy to
+ * provide optional GPIOs.
+ *
+ * @param blob FDT blob to use
+ * @param node Node to look at
+ * @param prop_name Node property name
+ * @param gpio gpio elements to fill from FDT
+ * @return 0 if ok, -FDT_ERR_NOTFOUND if the property is missing.
+ */
+int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
+ struct fdt_gpio_state *gpio);
+
+/**
+ * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no
+ * terminating item.
+ *
+ * @param blob FDT blob to use
+ * @param node Node to look at
+ * @param prop_name Node property name
+ * @param gpio Array of gpio elements to fill from FDT. This will be
+ * untouched if either 0 or an error is returned
+ * @param max_count Maximum number of elements allowed
+ * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
+ * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
+ */
+int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
+ struct fdt_gpio_state *gpio, int max_count);
+
+/**
+ * Set up a GPIO pin according to the provided gpio information. At present this
+ * just requests the GPIO.
+ *
+ * If the gpio is FDT_GPIO_NONE, no action is taken. This makes it easy to
+ * deal with optional GPIOs.
+ *
+ * @param gpio GPIO info to use for set up
+ * @return 0 if all ok or gpio was FDT_GPIO_NONE; -1 on error
+ */
+int fdtdec_setup_gpio(struct fdt_gpio_state *gpio);
+
+/**
+ * Look in the FDT for a config item with the given name and return its value
+ * as a 32-bit integer. The property must have at least 4 bytes of data. The
+ * value of the first cell is returned.
+ *
+ * @param blob FDT blob to use
+ * @param prop_name Node property name
+ * @param default_val default value to return if the property is not found
+ * @return integer value, if found, or default_val if not
+ */
+int fdtdec_get_config_int(const void *blob, const char *prop_name,
+ int default_val);
+
+/**
+ * Look in the FDT for a config item with the given name
+ * and return whether it exists.
+ *
+ * @param blob FDT blob
+ * @param prop_name property name to look up
+ * @return 1, if it exists, or 0 if not
+ */
+int fdtdec_get_config_bool(const void *blob, const char *prop_name);
+
+/**
+ * Look in the FDT for a config item with the given name and return its value
+ * as a string.
+ *
+ * @param blob FDT blob
+ * @param prop_name property name to look up
+ * @returns property string, NULL on error.
+ */
+char *fdtdec_get_config_string(const void *blob, const char *prop_name);
+
+/*
+ * Look up a property in a node and return its contents in a byte
+ * array of given length. The property must have at least enough data for
+ * the array (count bytes). It may have more, but this will be ignored.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param array array to fill with data
+ * @param count number of array elements
+ * @return 0 if ok, or -FDT_ERR_MISSING if the property is not found,
+ * or -FDT_ERR_BADLAYOUT if not enough data
+ */
+int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
+ u8 *array, int count);
+
+/**
+ * Look up a property in a node and return a pointer to its contents as a
+ * byte array of given length. The property must have at least enough data
+ * for the array (count bytes). It may have more, but this will be ignored.
+ * The data is not copied.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param count number of array elements
+ * @return pointer to byte array if found, or NULL if the property is not
+ * found or there is not enough data
+ */
+const u8 *fdtdec_locate_byte_array(const void *blob, int node,
+ const char *prop_name, int count);
+
+/**
+ * Look up a property in a node which contains a memory region address and
+ * size. Then return a pointer to this address.
+ *
+ * The property must hold one address with a length. This is only tested on
+ * 32-bit machines.
+ *
+ * @param blob FDT blob
+ * @param node node to examine
+ * @param prop_name name of property to find
+ * @param ptrp returns pointer to region, or NULL if no address
+ * @param size returns size of region
+ * @return 0 if ok, -1 on error (propery not found)
+ */
+int fdtdec_decode_region(const void *blob, int node,
+ const char *prop_name, void **ptrp, size_t *size);
+#endif
diff --git a/include/hush.h b/include/hush.h
index 0805ff3d88..595303a652 100644
--- a/include/hush.h
+++ b/include/hush.h
@@ -2,23 +2,7 @@
* (C) Copyright 2001
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _HUSH_H_
@@ -29,11 +13,12 @@
#define FLAG_REPARSING (1 << 2) /* >=2nd pass */
extern int u_boot_hush_start(void);
-extern int parse_string_outer(char *, int);
+extern int parse_string_outer(const char *, int);
extern int parse_file_outer(void);
int set_local_var(const char *s, int flg_export);
void unset_local_var(const char *name);
+char *get_local_var(const char *s);
#if defined(CONFIG_HUSH_INIT_VAR)
extern int hush_init_var (void);
diff --git a/include/image.h b/include/image.h
index 49d62805c3..316c60cfec 100644
--- a/include/image.h
+++ b/include/image.h
@@ -450,7 +450,7 @@ static inline void image_set_name (image_header_t *hdr, const char *name)
int image_check_hcrc (const image_header_t *hdr);
int image_check_dcrc (const image_header_t *hdr);
#ifndef USE_HOSTCC
-int getenv_yesno (char *var);
+int getenv_yesno (const char *var);
ulong getenv_bootm_low(void);
phys_size_t getenv_bootm_size(void);
void memmove_wd (void *to, void *from, size_t len, ulong chunksz);
diff --git a/include/iomux.h b/include/iomux.h
index e38a81e775..d104baf028 100644
--- a/include/iomux.h
+++ b/include/iomux.h
@@ -2,23 +2,7 @@
* (C) Copyright 2008
* Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- *This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _IO_MUX_H
@@ -43,6 +27,6 @@ extern int cd_count[MAX_FILES];
int iomux_doenv(const int, const char *);
void iomux_printdevs(const int);
-struct stdio_dev *search_device(int, char *);
+struct stdio_dev *search_device(int, const char *);
#endif /* _IO_MUX_H */
diff --git a/include/linker_lists.h b/include/linker_lists.h
new file mode 100644
index 0000000000..1eebb95fbb
--- /dev/null
+++ b/include/linker_lists.h
@@ -0,0 +1,288 @@
+/*
+ * include/linker_lists.h
+ *
+ * Implementation of linker-generated arrays
+ *
+ * Copyright (C) 2012 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * There is no use in including this from ASM files, but that happens
+ * anyway, e.g. PPC kgdb.S includes command.h which incluse us.
+ * So just don't define anything when included from ASM.
+ */
+
+#if !defined(__ASSEMBLY__)
+
+/**
+ * A linker list is constructed by grouping together linker input
+ * sections, each containning one entry of the list. Each input section
+ * contains a constant initialized variable which holds the entry's
+ * content. Linker list input sections are constructed from the list
+ * and entry names, plus a prefix which allows grouping all lists
+ * together. Assuming _list and _entry are the list and entry names,
+ * then the corresponding input section name is
+ *
+ * _u_boot_list + _2_ + @_list + _2_ + @_entry
+ *
+ * and the C variable name is
+ *
+ * .u_boot_list_ + 2_ + @_list + _2_ + @_entry
+ *
+ * This ensures uniqueness for both input section and C variable name.
+ *
+ * Note that the names differ only in the first character, "." for the
+ * setion and "_" for the variable, so that the linker cannot confuse
+ * section and symbol names. From now on, both names will be referred
+ * to as
+ *
+ * %u_boot_list_ + 2_ + @_list + _2_ + @_entry
+ *
+ * Entry variables need never be referred to directly.
+ *
+ * The naming scheme for input sections allows grouping all linker lists
+ * into a single linker output section and grouping all entries for a
+ * single list.
+ *
+ * Note the two '_2_' constant components in the names: their presence
+ * allows putting a start and end symbols around a list, by mapping
+ * these symbols to sections names with components "1" (before) and
+ * "3" (after) instead of "2" (within).
+ * Start and end symbols for a list can generally be defined as
+ *
+ * %u_boot_list_2_ + @_list + _1_...
+ * %u_boot_list_2_ + @_list + _3_...
+ *
+ * Start and end symbols for the whole of the linker lists area can be
+ * defined as
+ *
+ * %u_boot_list_1_...
+ * %u_boot_list_3_...
+ *
+ * Here is an example of the sorted sections which result from a list
+ * "array" made up of three entries : "first", "second" and "third",
+ * iterated at least once.
+ *
+ * .u_boot_list_2_array_1
+ * .u_boot_list_2_array_2_first
+ * .u_boot_list_2_array_2_second
+ * .u_boot_list_2_array_2_third
+ * .u_boot_list_2_array_3
+ *
+ * If lists must be divided into sublists (e.g. for iterating only on
+ * part of a list), one can simply give the list a name of the form
+ * 'outer_2_inner', where 'outer' is the global list name and 'inner'
+ * is the sub-list name. Iterators for the whole list should use the
+ * global list name ("outer"); iterators for only a sub-list should use
+ * the full sub-list name ("outer_2_inner").
+ *
+ * Here is an example of the sections generated from a global list
+ * named "drivers", two sub-lists named "i2c" and "pci", and iterators
+ * defined for the whole list and each sub-list:
+ *
+ * %u_boot_list_2_drivers_1
+ * %u_boot_list_2_drivers_2_i2c_1
+ * %u_boot_list_2_drivers_2_i2c_2_first
+ * %u_boot_list_2_drivers_2_i2c_2_first
+ * %u_boot_list_2_drivers_2_i2c_2_second
+ * %u_boot_list_2_drivers_2_i2c_2_third
+ * %u_boot_list_2_drivers_2_i2c_3
+ * %u_boot_list_2_drivers_2_pci_1
+ * %u_boot_list_2_drivers_2_pci_2_first
+ * %u_boot_list_2_drivers_2_pci_2_second
+ * %u_boot_list_2_drivers_2_pci_2_third
+ * %u_boot_list_2_drivers_2_pci_3
+ * %u_boot_list_2_drivers_3
+ */
+
+#ifndef __LINKER_LISTS_H__
+#define __LINKER_LISTS_H__
+
+/**
+ * ll_entry_declare() - Declare linker-generated array entry
+ * @_type: Data type of the entry
+ * @_name: Name of the entry
+ * @_list: name of the list. Should contain only characters allowed
+ * in a C variable name!
+ *
+ * This macro declares a variable that is placed into a linker-generated
+ * array. This is a basic building block for more advanced use of linker-
+ * generated arrays. The user is expected to build their own macro wrapper
+ * around this one.
+ *
+ * A variable declared using this macro must be compile-time initialized.
+ *
+ * Special precaution must be made when using this macro:
+ *
+ * 1) The _type must not contain the "static" keyword, otherwise the
+ * entry is generated and can be iterated but is listed in the map
+ * file and cannot be retrieved by name.
+ *
+ * 2) In case a section is declared that contains some array elements AND
+ * a subsection of this section is declared and contains some elements,
+ * it is imperative that the elements are of the same type.
+ *
+ * 4) In case an outer section is declared that contains some array elements
+ * AND an inner subsection of this section is declared and contains some
+ * elements, then when traversing the outer section, even the elements of
+ * the inner sections are present in the array.
+ *
+ * Example:
+ * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = {
+ * .x = 3,
+ * .y = 4,
+ * };
+ */
+#define ll_entry_declare(_type, _name, _list) \
+ _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
+ __attribute__((unused, \
+ section(".u_boot_list_2_"#_list"_2_"#_name)))
+
+/**
+ * We need a 0-byte-size type for iterator symbols, and the compiler
+ * does not allow defining objects of C type 'void'. Using an empty
+ * struct is allowed by the compiler, but causes gcc versions 4.4 and
+ * below to complain about aliasing. Therefore we use the next best
+ * thing: zero-sized arrays, which are both 0-byte-size and exempt from
+ * aliasing warnings.
+ */
+
+/**
+ * ll_entry_start() - Point to first entry of linker-generated array
+ * @_type: Data type of the entry
+ * @_list: Name of the list in which this entry is placed
+ *
+ * This function returns (_type *) pointer to the very first entry of a
+ * linker-generated array placed into subsection of .u_boot_list section
+ * specified by _list argument.
+ *
+ * Since this macro defines an array start symbol, its leftmost index
+ * must be 2 and its rightmost index must be 1.
+ *
+ * Example:
+ * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub);
+ */
+#define ll_entry_start(_type, _list) \
+({ \
+ static char start[0] __aligned(4) __attribute__((unused, \
+ section(".u_boot_list_2_"#_list"_1"))); \
+ (_type *)&start; \
+})
+
+/**
+ * ll_entry_end() - Point after last entry of linker-generated array
+ * @_type: Data type of the entry
+ * @_list: Name of the list in which this entry is placed
+ * (with underscores instead of dots)
+ *
+ * This function returns (_type *) pointer after the very last entry of
+ * a linker-generated array placed into subsection of .u_boot_list
+ * section specified by _list argument.
+ *
+ * Since this macro defines an array end symbol, its leftmost index
+ * must be 2 and its rightmost index must be 3.
+ *
+ * Example:
+ * struct my_sub_cmd *msc = ll_entry_end(struct my_sub_cmd, cmd_sub);
+ */
+#define ll_entry_end(_type, _list) \
+({ \
+ static char end[0] __aligned(4) __attribute__((unused, \
+ section(".u_boot_list_2_"#_list"_3"))); \
+ (_type *)&end; \
+})
+/**
+ * ll_entry_count() - Return the number of elements in linker-generated array
+ * @_type: Data type of the entry
+ * @_list: Name of the list of which the number of elements is computed
+ *
+ * This function returns the number of elements of a linker-generated array
+ * placed into subsection of .u_boot_list section specified by _list
+ * argument. The result is of an unsigned int type.
+ *
+ * Example:
+ * int i;
+ * const unsigned int count = ll_entry_count(struct my_sub_cmd, cmd_sub);
+ * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub);
+ * for (i = 0; i < count; i++, msc++)
+ * printf("Entry %i, x=%i y=%i\n", i, msc->x, msc->y);
+ */
+#define ll_entry_count(_type, _list) \
+ ({ \
+ _type *start = ll_entry_start(_type, _list); \
+ _type *end = ll_entry_end(_type, _list); \
+ unsigned int _ll_result = end - start; \
+ _ll_result; \
+ })
+
+/**
+ * ll_entry_get() - Retrieve entry from linker-generated array by name
+ * @_type: Data type of the entry
+ * @_name: Name of the entry
+ * @_list: Name of the list in which this entry is placed
+ *
+ * This function returns a pointer to a particular entry in LG-array
+ * identified by the subsection of u_boot_list where the entry resides
+ * and it's name.
+ *
+ * Example:
+ * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = {
+ * .x = 3,
+ * .y = 4,
+ * };
+ * ...
+ * struct my_sub_cmd *c = ll_entry_get(struct my_sub_cmd, my_sub_cmd, cmd_sub);
+ */
+#define ll_entry_get(_type, _name, _list) \
+ ({ \
+ extern _type _u_boot_list_2_##_list##_2_##_name; \
+ _type *_ll_result = \
+ &_u_boot_list_2_##_list##_2_##_name; \
+ _ll_result; \
+ })
+
+/**
+ * ll_start() - Point to first entry of first linker-generated array
+ * @_type: Data type of the entry
+ *
+ * This function returns (_type *) pointer to the very first entry of
+ * the very first linker-generated array.
+ *
+ * Since this macro defines the start of the linker-generated arrays,
+ * its leftmost index must be 1.
+ *
+ * Example:
+ * struct my_sub_cmd *msc = ll_start(struct my_sub_cmd);
+ */
+#define ll_start(_type) \
+({ \
+ static char start[0] __aligned(4) __attribute__((unused, \
+ section(".u_boot_list_1"))); \
+ (_type *)&start; \
+})
+
+/**
+ * ll_entry_end() - Point after last entry of last linker-generated array
+ * @_type: Data type of the entry
+ *
+ * This function returns (_type *) pointer after the very last entry of
+ * the very last linker-generated array.
+ *
+ * Since this macro defines the end of the linker-generated arrays,
+ * its leftmost index must be 3.
+ *
+ * Example:
+ * struct my_sub_cmd *msc = ll_end(struct my_sub_cmd);
+ */
+#define ll_end(_type) \
+({ \
+ static char end[0] __aligned(4) __attribute__((unused, \
+ section(".u_boot_list_3"))); \
+ (_type *)&end; \
+})
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __LINKER_LISTS_H__ */
diff --git a/include/linux/ctype.h b/include/linux/ctype.h
index afa3639229..42f9305a02 100644
--- a/include/linux/ctype.h
+++ b/include/linux/ctype.h
@@ -15,7 +15,7 @@
#define _X 0x40 /* hex digit */
#define _SP 0x80 /* hard space (0x20) */
-extern unsigned char _ctype[];
+extern const unsigned char _ctype[];
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
@@ -31,6 +31,12 @@ extern unsigned char _ctype[];
#define isupper(c) ((__ismask(c)&(_U)) != 0)
#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
+/*
+ * Rather than doubling the size of the _ctype lookup table to hold a 'blank'
+ * flag, just check for space or tab.
+ */
+#define isblank(c) (c == ' ' || c == '\t')
+
#define isascii(c) (((unsigned char)(c))<=0x7f)
#define toascii(c) (((unsigned char)(c))&0x7f)
diff --git a/include/linux/linux_string.h b/include/linux/linux_string.h
new file mode 100644
index 0000000000..192b4c9bea
--- /dev/null
+++ b/include/linux/linux_string.h
@@ -0,0 +1,8 @@
+#ifndef _LINUX_LINUX_STRING_H_
+#define _LINUX_LINUX_STRING_H_
+
+extern char * skip_spaces(const char *);
+
+extern char *strim(char *);
+
+#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index 62390399b0..8e44855712 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -38,8 +38,11 @@ extern int strcmp(const char *,const char *);
#ifndef __HAVE_ARCH_STRNCMP
extern int strncmp(const char *,const char *,__kernel_size_t);
#endif
-#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */
-extern int strnicmp(const char *, const char *, __kernel_size_t);
+#ifndef __HAVE_ARCH_STRCASECMP
+int strcasecmp(const char *s1, const char *s2);
+#endif
+#ifndef __HAVE_ARCH_STRNCASECMP
+extern int strncasecmp(const char *s1, const char *s2, __kernel_size_t len);
#endif
#ifndef __HAVE_ARCH_STRCHR
extern char * strchr(const char *,int);
@@ -47,6 +50,7 @@ extern char * strchr(const char *,int);
#ifndef __HAVE_ARCH_STRRCHR
extern char * strrchr(const char *,int);
#endif
+#include <linux/linux_string.h>
#ifndef __HAVE_ARCH_STRSTR
extern char * strstr(const char *,const char *);
#endif
@@ -81,6 +85,9 @@ extern int memcmp(const void *,const void *,__kernel_size_t);
#ifndef __HAVE_ARCH_MEMCHR
extern void * memchr(const void *,int,__kernel_size_t);
#endif
+#ifndef __HAVE_ARCH_MEMCHR_INV
+void *memchr_inv(const void *, int, size_t);
+#endif
#ifdef __cplusplus
}
diff --git a/include/linux/stringify.h b/include/linux/stringify.h
new file mode 100644
index 0000000000..841cec8ed5
--- /dev/null
+++ b/include/linux/stringify.h
@@ -0,0 +1,12 @@
+#ifndef __LINUX_STRINGIFY_H
+#define __LINUX_STRINGIFY_H
+
+/* Indirect stringification. Doing two levels allows the parameter to be a
+ * macro itself. For example, compile with -DFOO=bar, __stringify(FOO)
+ * converts to "bar".
+ */
+
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+#endif /* !__LINUX_STRINGIFY_H */
diff --git a/include/malloc.h b/include/malloc.h
index 3e145ad11c..ecf3c678fe 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -285,14 +285,6 @@ extern "C" {
*/
-#ifdef DEBUG
-/* #include <assert.h> */
-#define assert(x) ((void)0)
-#else
-#define assert(x) ((void)0)
-#endif
-
-
/*
INTERNAL_SIZE_T is the word-size used for internal bookkeeping
of chunk sizes. On a 64-bit machine, you can reduce malloc
diff --git a/include/menu.h b/include/menu.h
new file mode 100644
index 0000000000..063cd196bd
--- /dev/null
+++ b/include/menu.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010-2011 Calxeda, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __MENU_H__
+#define __MENU_H__
+
+struct menu;
+
+struct menu *menu_create(char *title, int timeout, int prompt,
+ void (*item_data_print)(void *),
+ char *(*item_choice)(void *),
+ void *item_choice_data);
+int menu_default_set(struct menu *m, char *item_key);
+int menu_get_choice(struct menu *m, void **choice);
+int menu_item_add(struct menu *m, char *item_key, void *item_data);
+int menu_destroy(struct menu *m);
+void menu_display_statusline(struct menu *m);
+int menu_default_choice(struct menu *m, void **choice);
+
+#if defined(CONFIG_MENU_SHOW)
+int menu_show(int bootdelay);
+#endif
+#endif /* __MENU_H__ */
diff --git a/include/search.h b/include/search.h
index fccc757e0e..ae3efc43ca 100644
--- a/include/search.h
+++ b/include/search.h
@@ -3,26 +3,13 @@
* Copyright (C) 1995-1999, 2000 Free Software Foundation, Inc.
* This file is part of the GNU C Library.
*
- * The GNU C Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * The GNU C Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the GNU C Library; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA.
+ * SPDX-License-Identifier: LGPL-2.1+
*/
/*
* Based on code from uClibc-0.9.30.3
* Extensions for use within U-Boot
- * Copyright (C) 2010 Wolfgang Denk <wd@denx.de>
+ * Copyright (C) 2010-2013 Wolfgang Denk <wd@denx.de>
*/
#ifndef _SEARCH_H
@@ -32,14 +19,11 @@
#define __set_errno(val) do { errno = val; } while (0)
-/*
- * Prototype structure for a linked-list data structure.
- * This is the type used by the `insque' and `remque' functions.
- */
-
-/* For use with hsearch(3). */
-typedef int (*__compar_fn_t) (__const void *, __const void *);
-typedef __compar_fn_t comparison_fn_t;
+enum env_op {
+ env_op_create,
+ env_op_delete,
+ env_op_overwrite,
+};
/* Action which shall be performed in the call the hsearch. */
typedef enum {
@@ -48,8 +32,11 @@ typedef enum {
} ACTION;
typedef struct entry {
- char *key;
+ const char *key;
char *data;
+ int (*callback)(const char *name, const char *value, enum env_op op,
+ int flags);
+ int flags;
} ENTRY;
/* Opaque type for internal use. */
@@ -66,14 +53,21 @@ struct hsearch_data {
struct _ENTRY *table;
unsigned int size;
unsigned int filled;
+/*
+ * Callback function which will check whether the given change for variable
+ * "item" to "newval" may be applied or not, and possibly apply such change.
+ * When (flag & H_FORCE) is set, it shall not print out any error message and
+ * shall force overwriting of write-once variables.
+.* Must return 0 for approval, 1 for denial.
+ */
+ int (*change_ok)(const ENTRY *__item, const char *newval, enum env_op,
+ int flag);
};
/* Create a new hashing table which will at most contain NEL elements. */
-extern int hcreate(size_t __nel);
extern int hcreate_r(size_t __nel, struct hsearch_data *__htab);
/* Destroy current internal hashing table. */
-extern void hdestroy(void);
extern void hdestroy_r(struct hsearch_data *__htab);
/*
@@ -82,25 +76,48 @@ extern void hdestroy_r(struct hsearch_data *__htab);
* NULL. If ACTION is `ENTER' replace existing data (if any) with
* ITEM.data.
* */
-extern ENTRY *hsearch(ENTRY __item, ACTION __action);
extern int hsearch_r(ENTRY __item, ACTION __action, ENTRY ** __retval,
- struct hsearch_data *__htab);
+ struct hsearch_data *__htab, int __flag);
+
+/*
+ * Search for an entry matching `MATCH'. Otherwise, Same semantics
+ * as hsearch_r().
+ */
+extern int hmatch_r(const char *__match, int __last_idx, ENTRY ** __retval,
+ struct hsearch_data *__htab);
/* Search and delete entry matching ITEM.key in internal hash table. */
-extern int hdelete(const char *__key);
-extern int hdelete_r(const char *__key, struct hsearch_data *__htab);
+extern int hdelete_r(const char *__key, struct hsearch_data *__htab,
+ int __flag);
-extern ssize_t hexport(const char __sep, char **__resp, size_t __size);
extern ssize_t hexport_r(struct hsearch_data *__htab,
- const char __sep, char **__resp, size_t __size);
+ const char __sep, int __flag, char **__resp, size_t __size,
+ int argc, char * const argv[]);
-extern int himport(const char *__env, size_t __size, const char __sep,
- int __flag);
+/*
+ * nvars: length of vars array
+ * vars: array of strings (variable names) to import (nvars == 0 means all)
+ * do_apply: whether to call callback function to check the new argument,
+ * and possibly apply changes (false means accept everything)
+ */
extern int himport_r(struct hsearch_data *__htab,
const char *__env, size_t __size, const char __sep,
- int __flag);
-
-/* Flags for himport() / himport_r() */
-#define H_NOCLEAR 1 /* do not clear hash table before importing */
+ int __flag, int nvars, char * const vars[]);
+
+/* Walk the whole table calling the callback on each element */
+extern int hwalk_r(struct hsearch_data *__htab, int (*callback)(ENTRY *));
+
+/* Flags for himport_r(), hexport_r(), hdelete_r(), and hsearch_r() */
+#define H_NOCLEAR (1 << 0) /* do not clear hash table before importing */
+#define H_FORCE (1 << 1) /* overwrite read-only/write-once variables */
+#define H_INTERACTIVE (1 << 2) /* indicate that an import is user directed */
+#define H_HIDE_DOT (1 << 3) /* don't print env vars that begin with '.' */
+#define H_MATCH_KEY (1 << 4) /* search/grep key = variable names */
+#define H_MATCH_DATA (1 << 5) /* search/grep data = variable values */
+#define H_MATCH_BOTH (H_MATCH_KEY | H_MATCH_DATA) /* search/grep both */
+#define H_MATCH_IDENT (1 << 6) /* search for indentical strings */
+#define H_MATCH_SUBSTR (1 << 7) /* search for substring matches */
+#define H_MATCH_REGEX (1 << 8) /* search for regular expression matches */
+#define H_MATCH_METHOD (H_MATCH_IDENT | H_MATCH_SUBSTR | H_MATCH_REGEX)
#endif /* search.h */
diff --git a/include/slre.h b/include/slre.h
new file mode 100644
index 0000000000..4b41a4b276
--- /dev/null
+++ b/include/slre.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
+ * All rights reserved
+ *
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * Sergey Lyubka wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return.
+ */
+
+/*
+ * Downloaded Sat Nov 5 17:42:08 CET 2011 at
+ * http://slre.sourceforge.net/1.0/slre.h
+ */
+
+/*
+ * This is a regular expression library that implements a subset of Perl RE.
+ * Please refer to http://slre.sourceforge.net for detailed description.
+ *
+ * Usage example (parsing HTTP request):
+ *
+ * struct slre slre;
+ * struct cap captures[4 + 1]; // Number of braket pairs + 1
+ * ...
+ *
+ * slre_compile(&slre,"^(GET|POST) (\S+) HTTP/(\S+?)\r\n");
+ *
+ * if (slre_match(&slre, buf, len, captures)) {
+ * printf("Request line length: %d\n", captures[0].len);
+ * printf("Method: %.*s\n", captures[1].len, captures[1].ptr);
+ * printf("URI: %.*s\n", captures[2].len, captures[2].ptr);
+ * }
+ *
+ * Supported syntax:
+ * ^ Match beginning of a buffer
+ * $ Match end of a buffer
+ * () Grouping and substring capturing
+ * [...] Match any character from set
+ * [^...] Match any character but ones from set
+ * \s Match whitespace
+ * \S Match non-whitespace
+ * \d Match decimal digit
+ * \r Match carriage return
+ * \n Match newline
+ * + Match one or more times (greedy)
+ * +? Match one or more times (non-greedy)
+ * * Match zero or more times (greedy)
+ * *? Match zero or more times (non-greedy)
+ * ? Match zero or once
+ * \xDD Match byte with hex value 0xDD
+ * \meta Match one of the meta character: ^$().[*+?\
+ */
+
+#ifndef SLRE_HEADER_DEFINED
+#define SLRE_HEADER_DEFINED
+
+/*
+ * Compiled regular expression
+ */
+struct slre {
+ unsigned char code[256];
+ unsigned char data[256];
+ int code_size;
+ int data_size;
+ int num_caps; /* Number of bracket pairs */
+ int anchored; /* Must match from string start */
+ const char *err_str; /* Error string */
+};
+
+/*
+ * Captured substring
+ */
+struct cap {
+ const char *ptr; /* Pointer to the substring */
+ int len; /* Substring length */
+};
+
+/*
+ * Compile regular expression. If success, 1 is returned.
+ * If error, 0 is returned and slre.err_str points to the error message.
+ */
+int slre_compile(struct slre *, const char *re);
+
+/*
+ * Return 1 if match, 0 if no match.
+ * If `captured_substrings' array is not NULL, then it is filled with the
+ * values of captured substrings. captured_substrings[0] element is always
+ * a full matched substring. The round bracket captures start from
+ * captured_substrings[1].
+ * It is assumed that the size of captured_substrings array is enough to
+ * hold all captures. The caller function must make sure it is! So, the
+ * array_size = number_of_round_bracket_pairs + 1
+ */
+int slre_match(const struct slre *, const char *buf, int buf_len,
+ struct cap *captured_substrings);
+
+#ifdef SLRE_TEST
+void slre_dump(const struct slre *r, FILE *fp);
+#endif /* SLRE_TEST */
+#endif /* SLRE_HEADER_DEFINED */
diff --git a/include/stdio_dev.h b/include/stdio_dev.h
index 83da4cdff1..e6dc12ac39 100644
--- a/include/stdio_dev.h
+++ b/include/stdio_dev.h
@@ -2,23 +2,7 @@
* (C) Copyright 2000
* Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#ifndef _STDIO_DEV_H_
@@ -93,21 +77,15 @@ int stdio_register (struct stdio_dev * dev);
int stdio_init (void);
void stdio_print_current_devices(void);
#ifdef CONFIG_SYS_STDIO_DEREGISTER
-int stdio_deregister(char *devname);
+int stdio_deregister(const char *devname);
#endif
struct list_head* stdio_get_list(void);
-struct stdio_dev* stdio_get_by_name(char* name);
+struct stdio_dev* stdio_get_by_name(const char* name);
struct stdio_dev* stdio_clone(struct stdio_dev *dev);
-#ifdef CONFIG_ARM_DCC_MULTI
-int drv_arm_dcc_init(void);
-#endif
#ifdef CONFIG_LCD
int drv_lcd_init (void);
#endif
-#ifdef CONFIG_VFD
-int drv_vfd_init (void);
-#endif
#if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
int drv_video_init (void);
#endif
@@ -123,5 +101,8 @@ int drv_nc_init (void);
#ifdef CONFIG_JTAG_CONSOLE
int drv_jtag_console_init (void);
#endif
+#ifdef CONFIG_CBMEM_CONSOLE
+int cbmemc_init(void);
+#endif
#endif
diff --git a/include/vsprintf.h b/include/vsprintf.h
new file mode 100644
index 0000000000..2ac41d1923
--- /dev/null
+++ b/include/vsprintf.h
@@ -0,0 +1,176 @@
+/*
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __VSPRINTF_H
+#define __VSPRINTF_H
+
+ulong simple_strtoul(const char *cp, char **endp, unsigned int base);
+
+/**
+ * strict_strtoul - convert a string to an unsigned long strictly
+ * @param cp The string to be converted
+ * @param base The number base to use
+ * @param res The converted result value
+ * @return 0 if conversion is successful and *res is set to the converted
+ * value, otherwise it returns -EINVAL and *res is set to 0.
+ *
+ * strict_strtoul converts a string to an unsigned long only if the
+ * string is really an unsigned long string, any string containing
+ * any invalid char at the tail will be rejected and -EINVAL is returned,
+ * only a newline char at the tail is acceptible because people generally
+ * change a module parameter in the following way:
+ *
+ * echo 1024 > /sys/module/e1000/parameters/copybreak
+ *
+ * echo will append a newline to the tail.
+ *
+ * simple_strtoul just ignores the successive invalid characters and
+ * return the converted value of prefix part of the string.
+ *
+ * Copied this function from Linux 2.6.38 commit ID:
+ * 521cb40b0c44418a4fd36dc633f575813d59a43d
+ *
+ */
+int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
+unsigned long long simple_strtoull(const char *cp, char **endp,
+ unsigned int base);
+long simple_strtol(const char *cp, char **endp, unsigned int base);
+void panic(const char *fmt, ...)
+ __attribute__ ((format (__printf__, 1, 2), noreturn));
+
+/**
+ * Format a string and place it in a buffer
+ *
+ * @param buf The buffer to place the result into
+ * @param fmt The format string to use
+ * @param ... Arguments for the format string
+ *
+ * The function returns the number of characters written
+ * into @buf.
+ *
+ * See the vsprintf() documentation for format string extensions over C99.
+ */
+int sprintf(char *buf, const char *fmt, ...)
+ __attribute__ ((format (__printf__, 2, 3)));
+
+/**
+ * Format a string and place it in a buffer (va_list version)
+ *
+ * @param buf The buffer to place the result into
+ * @param size The size of the buffer, including the trailing null space
+ * @param fmt The format string to use
+ * @param args Arguments for the format string
+ * @return the number of characters which have been written into
+ * the @buf not including the trailing '\0'. If @size is == 0 the function
+ * returns 0.
+ *
+ * If you're not already dealing with a va_list consider using scnprintf().
+ *
+ * See the vsprintf() documentation for format string extensions over C99.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args);
+char *simple_itoa(ulong i);
+
+#ifdef CONFIG_SYS_VSNPRINTF
+/**
+ * Format a string and place it in a buffer
+ *
+ * @param buf The buffer to place the result into
+ * @param size The size of the buffer, including the trailing null space
+ * @param fmt The format string to use
+ * @param ... Arguments for the format string
+ * @return the number of characters which would be
+ * generated for the given input, excluding the trailing null,
+ * as per ISO C99. If the return is greater than or equal to
+ * @size, the resulting string is truncated.
+ *
+ * See the vsprintf() documentation for format string extensions over C99.
+ */
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+ __attribute__ ((format (__printf__, 3, 4)));
+
+/**
+ * Format a string and place it in a buffer
+ *
+ * @param buf The buffer to place the result into
+ * @param size The size of the buffer, including the trailing null space
+ * @param fmt The format string to use
+ * @param ... Arguments for the format string
+ *
+ * The return value is the number of characters written into @buf not including
+ * the trailing '\0'. If @size is == 0 the function returns 0.
+ *
+ * See the vsprintf() documentation for format string extensions over C99.
+ */
+int scnprintf(char *buf, size_t size, const char *fmt, ...)
+ __attribute__ ((format (__printf__, 3, 4)));
+
+/**
+ * Format a string and place it in a buffer (base function)
+ *
+ * @param buf The buffer to place the result into
+ * @param size The size of the buffer, including the trailing null space
+ * @param fmt The format string to use
+ * @param args Arguments for the format string
+ * @return The number characters which would be generated for the given
+ * input, excluding the trailing '\0', as per ISO C99. Note that fewer
+ * characters may be written if this number of characters is >= size.
+ *
+ * This function follows C99 vsnprintf, but has some extensions:
+ * %pS output the name of a text symbol
+ * %pF output the name of a function pointer
+ * %pR output the address range in a struct resource
+ *
+ * The function returns the number of characters which would be
+ * generated for the given input, excluding the trailing '\0',
+ * as per ISO C99.
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want snprintf() instead.
+ */
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+/**
+ * Format a string and place it in a buffer (va_list version)
+ *
+ * @param buf The buffer to place the result into
+ * @param size The size of the buffer, including the trailing null space
+ * @param fmt The format string to use
+ * @param args Arguments for the format string
+ * @return the number of characters which have been written into
+ * the @buf not including the trailing '\0'. If @size is == 0 the function
+ * returns 0.
+ *
+ * If you're not already dealing with a va_list consider using scnprintf().
+ *
+ * See the vsprintf() documentation for format string extensions over C99.
+ */
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
+#else
+/*
+ * Use macros to silently drop the size parameter. Note that the 'cn'
+ * versions are the same as the 'n' versions since the functions assume
+ * there is always enough buffer space when !CONFIG_SYS_VSNPRINTF
+ */
+#define snprintf(buf, size, fmt, args...) sprintf(buf, fmt, ##args)
+#define scnprintf(buf, size, fmt, args...) sprintf(buf, fmt, ##args)
+#define vsnprintf(buf, size, fmt, args...) vsprintf(buf, fmt, ##args)
+#define vscnprintf(buf, size, fmt, args...) vsprintf(buf, fmt, ##args)
+#endif /* CONFIG_SYS_VSNPRINTF */
+
+/**
+ * print_grouped_ull() - print a value with digits grouped by ','
+ *
+ * This prints a value with grouped digits, like 12,345,678 to make it easier
+ * to read.
+ *
+ * @val: Value to print
+ * @digits: Number of digiits to print
+ */
+void print_grouped_ull(unsigned long long int_val, int digits);
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
index ffdee7d43d..c86e2f4117 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -51,6 +51,7 @@ COBJS-y += string.o
COBJS-y += strmhz.o
COBJS-y += time.o
COBJS-y += vsprintf.o
+COBJS-y += linux_string.o
COBJS-$(CONFIG_ZLIB) += zlib.o
COBJS-$(CONFIG_RBTREE) += rbtree.o
diff --git a/lib/ctype.c b/lib/ctype.c
index 6ed0468a21..65e1ac9ca7 100644
--- a/lib/ctype.c
+++ b/lib/ctype.c
@@ -2,23 +2,7 @@
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
/*
@@ -29,7 +13,7 @@
#include <linux/ctype.h>
-unsigned char _ctype[] = {
+const unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 7ac3dddda6..c5a2b08bec 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -2,7 +2,7 @@
* This implementation is based on code from uClibc-0.9.30.3 but was
* modified and extended for use within U-Boot.
*
- * Copyright (C) 2010 Wolfgang Denk <wd@denx.de>
+ * Copyright (C) 2010-2013 Wolfgang Denk <wd@denx.de>
*
* Original license header:
*
@@ -10,20 +10,7 @@
* This file is part of the GNU C Library.
* Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1993.
*
- * The GNU C Library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * The GNU C Library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the GNU C Library; if not, write to the Free
- * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- * 02111-1307 USA.
+ * SPDX-License-Identifier: LGPL-2.1+
*/
#include <errno.h>
@@ -32,6 +19,7 @@
#ifdef USE_HOSTCC /* HOST build */
# include <string.h>
# include <assert.h>
+# include <ctype.h>
# ifndef debug
# ifdef DEBUG
@@ -43,6 +31,7 @@
#else /* U-Boot build */
# include <common.h>
# include <linux/string.h>
+# include <linux/ctype.h>
#endif
#ifndef CONFIG_ENV_MIN_ENTRIES /* minimum number of entries */
@@ -52,7 +41,10 @@
#define CONFIG_ENV_MAX_ENTRIES 512
#endif
-#include "search.h"
+#include <env_callback.h>
+#include <env_flags.h>
+#include <search.h>
+#include <slre.h>
/*
* [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
@@ -60,21 +52,20 @@
*/
/*
- * The non-reentrant version use a global space for storing the hash table.
- */
-static struct hsearch_data htab;
-
-/*
* The reentrant version has no static variables to maintain the state.
* Instead the interface of all functions is extended to take an argument
* which describes the current status.
*/
+
typedef struct _ENTRY {
- unsigned int used;
+ int used;
ENTRY entry;
} _ENTRY;
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+ int idx);
+
/*
* hcreate()
*/
@@ -97,11 +88,6 @@ static int isprime(unsigned int number)
return number % div != 0;
}
-int hcreate(size_t nel)
-{
- return hcreate_r(nel, &htab);
-}
-
/*
* Before using the hash table we must allocate memory for it.
* Test for an existing table are done. We allocate one element
@@ -110,6 +96,7 @@ int hcreate(size_t nel)
* The contents of the table is zeroed, especially the field used
* becomes zero.
*/
+
int hcreate_r(size_t nel, struct hsearch_data *htab)
{
/* Test for correct arguments. */
@@ -143,15 +130,12 @@ int hcreate_r(size_t nel, struct hsearch_data *htab)
/*
* hdestroy()
*/
-void hdestroy(void)
-{
- hdestroy_r(&htab);
-}
/*
* After using the hash table it has to be destroyed. The used memory can
* be freed and the local static variable can be marked as not used.
*/
+
void hdestroy_r(struct hsearch_data *htab)
{
int i;
@@ -164,10 +148,10 @@ void hdestroy_r(struct hsearch_data *htab)
/* free used memory */
for (i = 1; i <= htab->size; ++i) {
- if (htab->table[i].used) {
+ if (htab->table[i].used > 0) {
ENTRY *ep = &htab->table[i].entry;
- free(ep->key);
+ free((void *)ep->key);
free(ep->data);
}
}
@@ -214,22 +198,85 @@ void hdestroy_r(struct hsearch_data *htab)
* example for functions like hdelete().
*/
-ENTRY *hsearch(ENTRY item, ACTION action)
+int hmatch_r(const char *match, int last_idx, ENTRY ** retval,
+ struct hsearch_data *htab)
{
- ENTRY *result;
+ unsigned int idx;
+ size_t key_len = strlen(match);
- (void) hsearch_r(item, action, &result, &htab);
+ for (idx = last_idx + 1; idx < htab->size; ++idx) {
+ if (htab->table[idx].used <= 0)
+ continue;
+ if (!strncmp(match, htab->table[idx].entry.key, key_len)) {
+ *retval = &htab->table[idx].entry;
+ return idx;
+ }
+ }
- return result;
+ __set_errno(ESRCH);
+ *retval = NULL;
+ return 0;
+}
+
+/*
+ * Compare an existing entry with the desired key, and overwrite if the action
+ * is ENTER. This is simply a helper function for hsearch_r().
+ */
+static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action,
+ ENTRY **retval, struct hsearch_data *htab, int flag,
+ unsigned int hval, unsigned int idx)
+{
+ if (htab->table[idx].used == hval
+ && strcmp(item.key, htab->table[idx].entry.key) == 0) {
+ /* Overwrite existing value? */
+ if ((action == ENTER) && (item.data != NULL)) {
+ /* check for permission */
+ if (htab->change_ok != NULL && htab->change_ok(
+ &htab->table[idx].entry, item.data,
+ env_op_overwrite, flag)) {
+ debug("change_ok() rejected setting variable "
+ "%s, skipping it!\n", item.key);
+ __set_errno(EPERM);
+ *retval = NULL;
+ return 0;
+ }
+
+ /* If there is a callback, call it */
+ if (htab->table[idx].entry.callback &&
+ htab->table[idx].entry.callback(item.key,
+ item.data, env_op_overwrite, flag)) {
+ debug("callback() rejected setting variable "
+ "%s, skipping it!\n", item.key);
+ __set_errno(EINVAL);
+ *retval = NULL;
+ return 0;
+ }
+
+ free(htab->table[idx].entry.data);
+ htab->table[idx].entry.data = strdup(item.data);
+ if (!htab->table[idx].entry.data) {
+ __set_errno(ENOMEM);
+ *retval = NULL;
+ return 0;
+ }
+ }
+ /* return found entry */
+ *retval = &htab->table[idx].entry;
+ return idx;
+ }
+ /* keep searching */
+ return -1;
}
int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
- struct hsearch_data *htab)
+ struct hsearch_data *htab, int flag)
{
unsigned int hval;
unsigned int count;
unsigned int len = strlen(item.key);
unsigned int idx;
+ unsigned int first_deleted = 0;
+ int ret;
/* Compute an value for the given string. Perhaps use a better method. */
hval = len;
@@ -257,23 +304,14 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
*/
unsigned hval2;
- if (htab->table[idx].used == hval
- && strcmp(item.key, htab->table[idx].entry.key) == 0) {
- /* Overwrite existing value? */
- if ((action == ENTER) && (item.data != NULL)) {
- free(htab->table[idx].entry.data);
- htab->table[idx].entry.data =
- strdup(item.data);
- if (!htab->table[idx].entry.data) {
- __set_errno(ENOMEM);
- *retval = NULL;
- return 0;
- }
- }
- /* return found entry */
- *retval = &htab->table[idx].entry;
- return idx;
- }
+ if (htab->table[idx].used == -1
+ && !first_deleted)
+ first_deleted = idx;
+
+ ret = _compare_and_overwrite_entry(item, action, retval, htab,
+ flag, hval, idx);
+ if (ret != -1)
+ return ret;
/*
* Second hash function:
@@ -299,23 +337,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
break;
/* If entry is found use it. */
- if ((htab->table[idx].used == hval)
- && strcmp(item.key, htab->table[idx].entry.key) == 0) {
- /* Overwrite existing value? */
- if ((action == ENTER) && (item.data != NULL)) {
- free(htab->table[idx].entry.data);
- htab->table[idx].entry.data =
- strdup(item.data);
- if (!htab->table[idx].entry.data) {
- __set_errno(ENOMEM);
- *retval = NULL;
- return 0;
- }
- }
- /* return found entry */
- *retval = &htab->table[idx].entry;
- return idx;
- }
+ ret = _compare_and_overwrite_entry(item, action, retval,
+ htab, flag, hval, idx);
+ if (ret != -1)
+ return ret;
}
while (htab->table[idx].used);
}
@@ -336,6 +361,9 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
* Create new entry;
* create copies of item.key and item.data
*/
+ if (first_deleted)
+ idx = first_deleted;
+
htab->table[idx].used = hval;
htab->table[idx].entry.key = strdup(item.key);
htab->table[idx].entry.data = strdup(item.data);
@@ -348,6 +376,34 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
++htab->filled;
+ /* This is a new entry, so look up a possible callback */
+ env_callback_init(&htab->table[idx].entry);
+ /* Also look for flags */
+ env_flags_init(&htab->table[idx].entry);
+
+ /* check for permission */
+ if (htab->change_ok != NULL && htab->change_ok(
+ &htab->table[idx].entry, item.data, env_op_create, flag)) {
+ debug("change_ok() rejected setting variable "
+ "%s, skipping it!\n", item.key);
+ _hdelete(item.key, htab, &htab->table[idx].entry, idx);
+ __set_errno(EPERM);
+ *retval = NULL;
+ return 0;
+ }
+
+ /* If there is a callback, call it */
+ if (htab->table[idx].entry.callback &&
+ htab->table[idx].entry.callback(item.key, item.data,
+ env_op_create, flag)) {
+ debug("callback() rejected setting variable "
+ "%s, skipping it!\n", item.key);
+ _hdelete(item.key, htab, &htab->table[idx].entry, idx);
+ __set_errno(EINVAL);
+ *retval = NULL;
+ return 0;
+ }
+
/* return new entry */
*retval = &htab->table[idx].entry;
return 1;
@@ -369,12 +425,21 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval,
* do that.
*/
-int hdelete(const char *key)
+static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep,
+ int idx)
{
- return hdelete_r(key, &htab);
+ /* free used ENTRY */
+ debug("hdelete: DELETING key \"%s\"\n", key);
+ free((void *)ep->key);
+ free(ep->data);
+ ep->callback = NULL;
+ ep->flags = 0;
+ htab->table[idx].used = -1;
+
+ --htab->filled;
}
-int hdelete_r(const char *key, struct hsearch_data *htab)
+int hdelete_r(const char *key, struct hsearch_data *htab, int flag)
{
ENTRY e, *ep;
int idx;
@@ -383,19 +448,31 @@ int hdelete_r(const char *key, struct hsearch_data *htab)
e.key = (char *)key;
- if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) {
+ idx = hsearch_r(e, FIND, &ep, htab, 0);
+ if (idx == 0) {
__set_errno(ESRCH);
return 0; /* not found */
}
- /* free used ENTRY */
- debug("hdelete: DELETING key \"%s\"\n", key);
+ /* Check for permission */
+ if (htab->change_ok != NULL &&
+ htab->change_ok(ep, NULL, env_op_delete, flag)) {
+ debug("change_ok() rejected deleting variable "
+ "%s, skipping it!\n", key);
+ __set_errno(EPERM);
+ return 0;
+ }
- free(ep->key);
- free(ep->data);
- htab->table[idx].used = 0;
+ /* If there is a callback, call it */
+ if (htab->table[idx].entry.callback &&
+ htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) {
+ debug("callback() rejected deleting variable "
+ "%s, skipping it!\n", key);
+ __set_errno(EINVAL);
+ return 0;
+ }
- --htab->filled;
+ _hdelete(key, htab, ep, idx);
return 1;
}
@@ -404,6 +481,7 @@ int hdelete_r(const char *key, struct hsearch_data *htab)
* hexport()
*/
+#ifndef CONFIG_SPL_BUILD
/*
* Export the data stored in the hash table in linearized form.
*
@@ -442,11 +520,6 @@ int hdelete_r(const char *key, struct hsearch_data *htab)
* bytes in the string will be '\0'-padded.
*/
-ssize_t hexport(const char sep, char **resp, size_t size)
-{
- return hexport_r(&htab, sep, resp, size);
-}
-
static int cmpkey(const void *p1, const void *p2)
{
ENTRY *e1 = *(ENTRY **) p1;
@@ -455,8 +528,68 @@ static int cmpkey(const void *p1, const void *p2)
return (strcmp(e1->key, e2->key));
}
-ssize_t hexport_r(struct hsearch_data *htab, const char sep,
- char **resp, size_t size)
+static int match_string(int flag, const char *str, const char *pat, void *priv)
+{
+ switch (flag & H_MATCH_METHOD) {
+ case H_MATCH_IDENT:
+ if (strcmp(str, pat) == 0)
+ return 1;
+ break;
+ case H_MATCH_SUBSTR:
+ if (strstr(str, pat))
+ return 1;
+ break;
+#ifdef CONFIG_REGEX
+ case H_MATCH_REGEX:
+ {
+ struct slre *slrep = (struct slre *)priv;
+ struct cap caps[slrep->num_caps + 2];
+
+ if (slre_match(slrep, str, strlen(str), caps))
+ return 1;
+ }
+ break;
+#endif
+ default:
+ printf("## ERROR: unsupported match method: 0x%02x\n",
+ flag & H_MATCH_METHOD);
+ break;
+ }
+ return 0;
+}
+
+static int match_entry(ENTRY *ep, int flag,
+ int argc, char * const argv[])
+{
+ int arg;
+ void *priv = NULL;
+
+ for (arg = 1; arg < argc; ++arg) {
+#ifdef CONFIG_REGEX
+ struct slre slre;
+
+ if (slre_compile(&slre, argv[arg]) == 0) {
+ printf("Error compiling regex: %s\n", slre.err_str);
+ return 0;
+ }
+
+ priv = (void *)&slre;
+#endif
+ if (flag & H_MATCH_KEY) {
+ if (match_string(flag, ep->key, argv[arg], priv))
+ return 1;
+ }
+ if (flag & H_MATCH_DATA) {
+ if (match_string(flag, ep->data, argv[arg], priv))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag,
+ char **resp, size_t size,
+ int argc, char * const argv[])
{
ENTRY *list[htab->size];
char *res, *p;
@@ -469,8 +602,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
return (-1);
}
- debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, size = %d\n",
- htab, htab->size, htab->filled, size);
+ debug("EXPORT table = %p, htab.size = %d, htab.filled = %d, "
+ "size = %zu\n", htab, htab->size, htab->filled, size);
/*
* Pass 1:
* search used entries,
@@ -478,8 +611,15 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
*/
for (i = 1, n = 0, totlen = 0; i <= htab->size; ++i) {
- if (htab->table[i].used) {
+ if (htab->table[i].used > 0) {
ENTRY *ep = &htab->table[i].entry;
+ int found = match_entry(ep, flag, argc, argv);
+
+ if ((argc > 0) && (found == 0))
+ continue;
+
+ if ((flag & H_HIDE_DOT) && ep->key[0] == '.')
+ continue;
list[n++] = ep;
@@ -517,8 +657,8 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
/* Check if the user supplied buffer size is sufficient */
if (size) {
if (size < totlen + 1) { /* provided buffer too small */
- debug("### buffer too small: %d, but need %d\n",
- size, totlen + 1);
+ printf("Env export buffer too small: %zu, "
+ "but need %zu\n", size, totlen + 1);
__set_errno(ENOMEM);
return (-1);
}
@@ -544,7 +684,7 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
* export sorted list of result data
*/
for (i = 0, p = res; i < n; ++i) {
- char *s;
+ const char *s;
s = list[i]->key;
while (*s)
@@ -564,6 +704,7 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
return size;
}
+#endif
/*
@@ -571,6 +712,34 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
*/
/*
+ * Check whether variable 'name' is amongst vars[],
+ * and remove all instances by setting the pointer to NULL
+ */
+static int drop_var_from_set(const char *name, int nvars, char * vars[])
+{
+ int i = 0;
+ int res = 0;
+
+ /* No variables specified means process all of them */
+ if (nvars == 0)
+ return 1;
+
+ for (i = 0; i < nvars; i++) {
+ if (vars[i] == NULL)
+ continue;
+ /* If we found it, delete all of them */
+ if (!strcmp(name, vars[i])) {
+ vars[i] = NULL;
+ res = 1;
+ }
+ }
+ if (!res)
+ debug("Skipping non-listed variable %s\n", name);
+
+ return res;
+}
+
+/*
* Import linearized data into hash table.
*
* This is the inverse function to hexport(): it takes a linear list
@@ -605,15 +774,13 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep,
* '\0' and '\n' have really been tested.
*/
-int himport(const char *env, size_t size, const char sep, int flag)
-{
- return himport_r(&htab, env, size, sep, flag);
-}
-
int himport_r(struct hsearch_data *htab,
- const char *env, size_t size, const char sep, int flag)
+ const char *env, size_t size, const char sep, int flag,
+ int nvars, char * const vars[])
{
char *data, *sp, *dp, *name, *value;
+ char *localvars[nvars];
+ int i;
/* Test for correct arguments. */
if (htab == NULL) {
@@ -623,13 +790,17 @@ int himport_r(struct hsearch_data *htab,
/* we allocate new space to make sure we can write to the array */
if ((data = malloc(size)) == NULL) {
- debug("himport_r: can't malloc %d bytes\n", size);
+ debug("himport_r: can't malloc %zu bytes\n", size);
__set_errno(ENOMEM);
return 0;
}
memcpy(data, env, size);
dp = data;
+ /* make a local copy of the list of variables */
+ if (nvars)
+ memcpy(localvars, vars, sizeof(vars[0]) * nvars);
+
if ((flag & H_NOCLEAR) == 0) {
/* Destroy old hash table if one exists */
debug("Destroy Hash Table: %p table = %p\n", htab,
@@ -646,7 +817,7 @@ int himport_r(struct hsearch_data *htab,
* size of 8 per entry (= safety factor of ~5) should provide enough
* safety margin for any existing environment definitions and still
* allow for more than enough dynamic additions. Note that the
- * "size" argument is supposed to give the maximum enviroment size
+ * "size" argument is supposed to give the maximum environment size
* (CONFIG_ENV_SIZE). This heuristics will result in
* unreasonably large numbers (and thus memory footprint) for
* big flash environments (>8,000 entries for 64 KB
@@ -675,7 +846,7 @@ int himport_r(struct hsearch_data *htab,
ENTRY e, *rv;
/* skip leading white space */
- while ((*dp == ' ') || (*dp == '\t'))
+ while (isblank(*dp))
++dp;
/* skip comment lines */
@@ -698,8 +869,10 @@ int himport_r(struct hsearch_data *htab,
*dp++ = '\0'; /* terminate name */
debug("DELETE CANDIDATE: \"%s\"\n", name);
+ if (!drop_var_from_set(name, nvars, localvars))
+ continue;
- if (hdelete_r(name, htab) == 0)
+ if (hdelete_r(name, htab, flag) == 0)
debug("DELETE ERROR ##############################\n");
continue;
@@ -715,16 +888,24 @@ int himport_r(struct hsearch_data *htab,
*sp++ = '\0'; /* terminate value */
++dp;
+ if (*name == 0) {
+ debug("INSERT: unable to use an empty key\n");
+ __set_errno(EINVAL);
+ return 0;
+ }
+
+ /* Skip variables which are not supposed to be processed */
+ if (!drop_var_from_set(name, nvars, localvars))
+ continue;
+
/* enter into hash table */
e.key = name;
e.data = value;
- hsearch_r(e, ENTER, &rv, htab);
- if (rv == NULL) {
+ hsearch_r(e, ENTER, &rv, htab, flag);
+ if (rv == NULL)
printf("himport_r: can't insert \"%s=%s\" into hash table\n",
name, value);
- return 0;
- }
debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n",
htab, htab->filled, htab->size,
@@ -734,6 +915,48 @@ int himport_r(struct hsearch_data *htab,
debug("INSERT: free(data = %p)\n", data);
free(data);
+ /* process variables which were not considered */
+ for (i = 0; i < nvars; i++) {
+ if (localvars[i] == NULL)
+ continue;
+ /*
+ * All variables which were not deleted from the variable list
+ * were not present in the imported env
+ * This could mean two things:
+ * a) if the variable was present in current env, we delete it
+ * b) if the variable was not present in current env, we notify
+ * it might be a typo
+ */
+ if (hdelete_r(localvars[i], htab, flag) == 0)
+ printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]);
+ else
+ printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]);
+ }
+
debug("INSERT: done\n");
return 1; /* everything OK */
}
+
+/*
+ * hwalk_r()
+ */
+
+/*
+ * Walk all of the entries in the hash, calling the callback for each one.
+ * this allows some generic operation to be performed on each element.
+ */
+int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *))
+{
+ int i;
+ int retval;
+
+ for (i = 1; i <= htab->size; ++i) {
+ if (htab->table[i].used > 0) {
+ retval = callback(&htab->table[i].entry);
+ if (retval)
+ return retval;
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/linux_string.c b/lib/linux_string.c
new file mode 100644
index 0000000000..d5a5e08d98
--- /dev/null
+++ b/lib/linux_string.c
@@ -0,0 +1,51 @@
+/*
+ * linux/lib/string.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifdef USE_HOSTCC
+#include <stdio.h>
+#endif
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+/**
+ * skip_spaces - Removes leading whitespace from @str.
+ * @str: The string to be stripped.
+ *
+ * Returns a pointer to the first non-whitespace character in @str.
+ */
+char *skip_spaces(const char *str)
+{
+ while (isspace(*str))
+ ++str;
+ return (char *)str;
+}
+
+/**
+ * strim - Removes leading and trailing whitespace from @s.
+ * @s: The string to be stripped.
+ *
+ * Note that the first trailing whitespace is replaced with a %NUL-terminator
+ * in the given string @s. Returns a pointer to the first non-whitespace
+ * character in @s.
+ */
+char *strim(char *s)
+{
+ size_t size;
+ char *end;
+
+ s = skip_spaces(s);
+ size = strlen(s);
+ if (!size)
+ return s;
+
+ end = s + size - 1;
+ while (end >= s && isspace(*end))
+ end--;
+ *(end + 1) = '\0';
+
+ return s;
+}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index aa214dd06f..82e5c13653 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -7,25 +7,28 @@
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
/*
* Wirzenius wrote this portably, Torvalds fucked it up :-)
+ *
+ * from hush: simple_itoa() was lifted from boa-0.93.15
*/
#include <stdarg.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include <errno.h>
#include <common.h>
-#if !defined (CONFIG_PANIC_HANG)
+#if !defined(CONFIG_PANIC_HANG)
#include <command.h>
-/*cmd_boot.c*/
-extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
#endif
#include <div64.h>
-# define NUM_TYPE long long
#define noinline __attribute__((noinline))
-const char hex_asc[] = "0123456789abcdef";
+/* some reluctance to put this into a new limits.h, so it is here */
+#define INT_MAX ((int)(~0U>>1))
+
+static const char hex_asc[] = "0123456789abcdef";
#define hex_asc_lo(x) hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4]
@@ -36,9 +39,11 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
return buf;
}
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+unsigned long simple_strtoul(const char *cp, char **endp,
+ unsigned int base)
{
- unsigned long result = 0,value;
+ unsigned long result = 0;
+ unsigned long value;
if (*cp == '0') {
cp++;
@@ -46,35 +51,63 @@ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
base = 16;
cp++;
}
- if (!base) {
+
+ if (!base)
base = 8;
- }
}
- if (!base) {
+
+ if (!base)
base = 10;
- }
+
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
? toupper(*cp) : *cp)-'A'+10) < base) {
result = result*base + value;
cp++;
}
+
if (endp)
*endp = (char *)cp;
+
return result;
}
-long simple_strtol(const char *cp,char **endp,unsigned int base)
+int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
{
- if(*cp=='-')
- return -simple_strtoul(cp+1,endp,base);
- return simple_strtoul(cp,endp,base);
+ char *tail;
+ unsigned long val;
+ size_t len;
+
+ *res = 0;
+ len = strlen(cp);
+ if (len == 0)
+ return -EINVAL;
+
+ val = simple_strtoul(cp, &tail, base);
+ if (tail == cp)
+ return -EINVAL;
+
+ if ((*tail == '\0') ||
+ ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
+ *res = val;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+long simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+ if (*cp == '-')
+ return -simple_strtoul(cp + 1, endp, base);
+
+ return simple_strtoul(cp, endp, base);
}
-int ustrtoul(const char *cp, char **endp, unsigned int base)
+unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
{
unsigned long result = simple_strtoul(cp, endp, base);
switch (**endp) {
- case 'G' :
+ case 'G':
result *= 1024;
/* fall through */
case 'M':
@@ -93,31 +126,57 @@ int ustrtoul(const char *cp, char **endp, unsigned int base)
return result;
}
-unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int base)
+unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
+{
+ unsigned long long result = simple_strtoull(cp, endp, base);
+ switch (**endp) {
+ case 'G':
+ result *= 1024;
+ /* fall through */
+ case 'M':
+ result *= 1024;
+ /* fall through */
+ case 'K':
+ case 'k':
+ result *= 1024;
+ if ((*endp)[1] == 'i') {
+ if ((*endp)[2] == 'B')
+ (*endp) += 3;
+ else
+ (*endp) += 2;
+ }
+ }
+ return result;
+}
+
+unsigned long long simple_strtoull(const char *cp, char **endp,
+ unsigned int base)
{
unsigned long long result = 0, value;
if (*cp == '0') {
cp++;
- if ((*cp == 'x') && isxdigit (cp[1])) {
+ if ((*cp == 'x') && isxdigit(cp[1])) {
base = 16;
cp++;
}
- if (!base) {
+
+ if (!base)
base = 8;
- }
}
- if (!base) {
+
+ if (!base)
base = 10;
- }
- while (isxdigit (*cp) && (value = isdigit (*cp)
- ? *cp - '0'
- : (islower (*cp) ? toupper (*cp) : *cp) - 'A' + 10) < base) {
+
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0'
+ : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) {
result = result * base + value;
cp++;
}
+
if (endp)
*endp = (char *) cp;
+
return result;
}
@@ -126,10 +185,11 @@ unsigned long long simple_strtoull (const char *cp, char **endp, unsigned int ba
static int skip_atoi(const char **s)
{
- int i=0;
+ int i = 0;
while (is_digit(**s))
- i = i*10 + *((*s)++) - '0';
+ i = i * 10 + *((*s)++) - '0';
+
return i;
}
@@ -143,7 +203,7 @@ static int skip_atoi(const char **s)
/* Formats correctly any integer in [0,99999].
* Outputs from one to five digits depending on input.
* On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
-static char* put_dec_trunc(char *buf, unsigned q)
+static char *put_dec_trunc(char *buf, unsigned q)
{
unsigned d3, d2, d1, d0;
d1 = (q>>4) & 0xf;
@@ -172,14 +232,14 @@ static char* put_dec_trunc(char *buf, unsigned q)
d3 = d3 - 10*q;
*buf++ = d3 + '0'; /* next digit */
if (q != 0)
- *buf++ = q + '0'; /* most sign. digit */
+ *buf++ = q + '0'; /* most sign. digit */
}
}
}
return buf;
}
/* Same with if's removed. Always emits five digits */
-static char* put_dec_full(char *buf, unsigned q)
+static char *put_dec_full(char *buf, unsigned q)
{
/* BTW, if q is in [0,9999], 8-bit ints will be enough, */
/* but anyway, gcc produces better code with full-sized ints */
@@ -221,7 +281,7 @@ static char* put_dec_full(char *buf, unsigned q)
return buf;
}
/* No inlining helps gcc to use registers better */
-static noinline char* put_dec(char *buf, unsigned NUM_TYPE num)
+static noinline char *put_dec(char *buf, u64 num)
{
while (1) {
unsigned rem;
@@ -240,10 +300,25 @@ static noinline char* put_dec(char *buf, unsigned NUM_TYPE num)
#define SMALL 32 /* Must be 32 == 0x20 */
#define SPECIAL 64 /* 0x */
-static char *number(char *buf, unsigned NUM_TYPE num, int base, int size, int precision, int type)
+#ifdef CONFIG_SYS_VSNPRINTF
+/*
+ * Macro to add a new character to our output string, but only if it will
+ * fit. The macro moves to the next character position in the output string.
+ */
+#define ADDCH(str, ch) do { \
+ if ((str) < end) \
+ *(str) = (ch); \
+ ++str; \
+ } while (0)
+#else
+#define ADDCH(str, ch) (*(str)++ = (ch))
+#endif
+
+static char *number(char *buf, char *end, u64 num,
+ int base, int size, int precision, int type)
{
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */
- static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
+ static const char digits[16] = "0123456789ABCDEF";
char tmp[66];
char sign;
@@ -258,9 +333,9 @@ static char *number(char *buf, unsigned NUM_TYPE num, int base, int size, int pr
type &= ~ZEROPAD;
sign = 0;
if (type & SIGN) {
- if ((signed NUM_TYPE) num < 0) {
+ if ((s64) num < 0) {
sign = '-';
- num = - (signed NUM_TYPE) num;
+ num = -(s64) num;
size--;
} else if (type & PLUS) {
sign = '+';
@@ -288,9 +363,13 @@ static char *number(char *buf, unsigned NUM_TYPE num, int base, int size, int pr
else if (base != 10) { /* 8 or 16 */
int mask = base - 1;
int shift = 3;
- if (base == 16) shift = 4;
+
+ if (base == 16)
+ shift = 4;
+
do {
- tmp[i++] = (digits[((unsigned char)num) & mask] | locase);
+ tmp[i++] = (digits[((unsigned char)num) & mask]
+ | locase);
num >>= shift;
} while (num);
} else { /* base 10 */
@@ -302,60 +381,64 @@ static char *number(char *buf, unsigned NUM_TYPE num, int base, int size, int pr
precision = i;
/* leading space padding */
size -= precision;
- if (!(type & (ZEROPAD+LEFT)))
- while(--size >= 0)
- *buf++ = ' ';
+ if (!(type & (ZEROPAD + LEFT))) {
+ while (--size >= 0)
+ ADDCH(buf, ' ');
+ }
/* sign */
if (sign)
- *buf++ = sign;
+ ADDCH(buf, sign);
/* "0x" / "0" prefix */
if (need_pfx) {
- *buf++ = '0';
+ ADDCH(buf, '0');
if (base == 16)
- *buf++ = ('X' | locase);
+ ADDCH(buf, 'X' | locase);
}
/* zero or space padding */
if (!(type & LEFT)) {
char c = (type & ZEROPAD) ? '0' : ' ';
+
while (--size >= 0)
- *buf++ = c;
+ ADDCH(buf, c);
}
/* hmm even more zero padding? */
while (i <= --precision)
- *buf++ = '0';
+ ADDCH(buf, '0');
/* actual digits of result */
while (--i >= 0)
- *buf++ = tmp[i];
+ ADDCH(buf, tmp[i]);
/* trailing space padding */
while (--size >= 0)
- *buf++ = ' ';
+ ADDCH(buf, ' ');
return buf;
}
-static char *string(char *buf, char *s, int field_width, int precision, int flags)
+static char *string(char *buf, char *end, char *s, int field_width,
+ int precision, int flags)
{
int len, i;
- if (s == 0)
+ if (s == NULL)
s = "<NULL>";
len = strnlen(s, precision);
if (!(flags & LEFT))
while (len < field_width--)
- *buf++ = ' ';
+ ADDCH(buf, ' ');
for (i = 0; i < len; ++i)
- *buf++ = *s++;
+ ADDCH(buf, *s++);
while (len < field_width--)
- *buf++ = ' ';
+ ADDCH(buf, ' ');
return buf;
}
#ifdef CONFIG_CMD_NET
-static char *mac_address_string(char *buf, u8 *addr, int field_width,
+static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
int precision, int flags)
{
- char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */
+ /* (6 * 2 hex digits), 5 colons and trailing zero */
+ char mac_addr[6 * 3];
char *p = mac_addr;
int i;
@@ -366,13 +449,15 @@ static char *mac_address_string(char *buf, u8 *addr, int field_width,
}
*p = '\0';
- return string(buf, mac_addr, field_width, precision, flags & ~SPECIAL);
+ return string(buf, end, mac_addr, field_width, precision,
+ flags & ~SPECIAL);
}
-static char *ip6_addr_string(char *buf, u8 *addr, int field_width,
+static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
int precision, int flags)
{
- char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
+ /* (8 * 4 hex digits), 7 colons and trailing zero */
+ char ip6_addr[8 * 5];
char *p = ip6_addr;
int i;
@@ -384,13 +469,15 @@ static char *ip6_addr_string(char *buf, u8 *addr, int field_width,
}
*p = '\0';
- return string(buf, ip6_addr, field_width, precision, flags & ~SPECIAL);
+ return string(buf, end, ip6_addr, field_width, precision,
+ flags & ~SPECIAL);
}
-static char *ip4_addr_string(char *buf, u8 *addr, int field_width,
+static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
int precision, int flags)
{
- char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */
+ /* (4 * 3 decimal digits), 3 dots and trailing zero */
+ char ip4_addr[4 * 4];
char temp[3]; /* hold each IP quad in reverse order */
char *p = ip4_addr;
int i, digits;
@@ -405,7 +492,8 @@ static char *ip4_addr_string(char *buf, u8 *addr, int field_width,
}
*p = '\0';
- return string(buf, ip4_addr, field_width, precision, flags & ~SPECIAL);
+ return string(buf, end, ip4_addr, field_width, precision,
+ flags & ~SPECIAL);
}
#endif
@@ -427,10 +515,18 @@ static char *ip4_addr_string(char *buf, u8 *addr, int field_width,
* function pointers are really function descriptors, which contain a
* pointer to the real address.
*/
-static char *pointer(const char *fmt, char *buf, void *ptr, int field_width, int precision, int flags)
+static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
+ int field_width, int precision, int flags)
{
+ /*
+ * Being a boot loader, we explicitly allow pointers to
+ * (physical) address null.
+ */
+#if 0
if (!ptr)
- return string(buf, "(null)", field_width, precision, flags);
+ return string(buf, end, "(null)", field_width, precision,
+ flags);
+#endif
#ifdef CONFIG_CMD_NET
switch (*fmt) {
@@ -438,15 +534,18 @@ static char *pointer(const char *fmt, char *buf, void *ptr, int field_width, int
flags |= SPECIAL;
/* Fallthrough */
case 'M':
- return mac_address_string(buf, ptr, field_width, precision, flags);
+ return mac_address_string(buf, end, ptr, field_width,
+ precision, flags);
case 'i':
flags |= SPECIAL;
/* Fallthrough */
case 'I':
if (fmt[1] == '6')
- return ip6_addr_string(buf, ptr, field_width, precision, flags);
+ return ip6_addr_string(buf, end, ptr, field_width,
+ precision, flags);
if (fmt[1] == '4')
- return ip4_addr_string(buf, ptr, field_width, precision, flags);
+ return ip4_addr_string(buf, end, ptr, field_width,
+ precision, flags);
flags &= ~SPECIAL;
break;
}
@@ -456,29 +555,14 @@ static char *pointer(const char *fmt, char *buf, void *ptr, int field_width, int
field_width = 2*sizeof(void *);
flags |= ZEROPAD;
}
- return number(buf, (unsigned long) ptr, 16, field_width, precision, flags);
+ return number(buf, end, (unsigned long)ptr, 16, field_width,
+ precision, flags);
}
-/**
- * vsprintf - Format a string and place it in a buffer
- * @buf: The buffer to place the result into
- * @fmt: The format string to use
- * @args: Arguments for the format string
- *
- * This function follows C99 vsprintf, but has some extensions:
- * %pS output the name of a text symbol
- * %pF output the name of a function pointer
- * %pR output the address range in a struct resource
- *
- * The function returns the number of characters written
- * into @buf.
- *
- * Call this function if you are already dealing with a va_list.
- * You probably want sprintf() instead.
- */
-int vsprintf(char *buf, const char *fmt, va_list args)
+static int vsnprintf_internal(char *buf, size_t size, const char *fmt,
+ va_list args)
{
- unsigned NUM_TYPE num;
+ u64 num;
int base;
char *str;
@@ -491,25 +575,43 @@ int vsprintf(char *buf, const char *fmt, va_list args)
/* 'z' support added 23/7/1999 S.H. */
/* 'z' changed to 'Z' --davidm 1/25/99 */
/* 't' added for ptrdiff_t */
+ char *end = buf + size;
+#ifdef CONFIG_SYS_VSNPRINTF
+ /* Make sure end is always >= buf - do we want this in U-Boot? */
+ if (end < buf) {
+ end = ((void *)-1);
+ size = end - buf;
+ }
+#endif
str = buf;
for (; *fmt ; ++fmt) {
if (*fmt != '%') {
- *str++ = *fmt;
+ ADDCH(str, *fmt);
continue;
}
/* process flags */
flags = 0;
- repeat:
+repeat:
++fmt; /* this also skips first '%' */
switch (*fmt) {
- case '-': flags |= LEFT; goto repeat;
- case '+': flags |= PLUS; goto repeat;
- case ' ': flags |= SPACE; goto repeat;
- case '#': flags |= SPECIAL; goto repeat;
- case '0': flags |= ZEROPAD; goto repeat;
+ case '-':
+ flags |= LEFT;
+ goto repeat;
+ case '+':
+ flags |= PLUS;
+ goto repeat;
+ case ' ':
+ flags |= SPACE;
+ goto repeat;
+ case '#':
+ flags |= SPECIAL;
+ goto repeat;
+ case '0':
+ flags |= ZEROPAD;
+ goto repeat;
}
/* get field width */
@@ -558,20 +660,22 @@ int vsprintf(char *buf, const char *fmt, va_list args)
switch (*fmt) {
case 'c':
- if (!(flags & LEFT))
+ if (!(flags & LEFT)) {
while (--field_width > 0)
- *str++ = ' ';
- *str++ = (unsigned char) va_arg(args, int);
+ ADDCH(str, ' ');
+ }
+ ADDCH(str, (unsigned char) va_arg(args, int));
while (--field_width > 0)
- *str++ = ' ';
+ ADDCH(str, ' ');
continue;
case 's':
- str = string(str, va_arg(args, char *), field_width, precision, flags);
+ str = string(str, end, va_arg(args, char *),
+ field_width, precision, flags);
continue;
case 'p':
- str = pointer(fmt+1, str,
+ str = pointer(fmt + 1, str, end,
va_arg(args, void *),
field_width, precision, flags);
/* Skip all alphanumeric pointer suffixes */
@@ -581,16 +685,16 @@ int vsprintf(char *buf, const char *fmt, va_list args)
case 'n':
if (qualifier == 'l') {
- long * ip = va_arg(args, long *);
+ long *ip = va_arg(args, long *);
*ip = (str - buf);
} else {
- int * ip = va_arg(args, int *);
+ int *ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
case '%':
- *str++ = '%';
+ ADDCH(str, '%');
continue;
/* integer number formats - set up the flags and "break" */
@@ -611,9 +715,9 @@ int vsprintf(char *buf, const char *fmt, va_list args)
break;
default:
- *str++ = '%';
+ ADDCH(str, '%');
if (*fmt)
- *str++ = *fmt;
+ ADDCH(str, *fmt);
else
--fmt;
continue;
@@ -637,45 +741,148 @@ int vsprintf(char *buf, const char *fmt, va_list args)
if (flags & SIGN)
num = (signed int) num;
}
- str = number(str, num, base, field_width, precision, flags);
+ str = number(str, end, num, base, field_width, precision,
+ flags);
+ }
+
+#ifdef CONFIG_SYS_VSNPRINTF
+ if (size > 0) {
+ ADDCH(str, '\0');
+ if (str > end)
+ end[-1] = '\0';
}
+#else
*str = '\0';
- return str-buf;
+#endif
+ /* the trailing null byte doesn't count towards the total */
+ return str - buf;
+}
+
+#ifdef CONFIG_SYS_VSNPRINTF
+int vsnprintf(char *buf, size_t size, const char *fmt,
+ va_list args)
+{
+ return vsnprintf_internal(buf, size, fmt, args);
+}
+
+int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ int i;
+
+ i = vsnprintf(buf, size, fmt, args);
+
+ if (likely(i < size))
+ return i;
+ if (size != 0)
+ return size - 1;
+ return 0;
}
+int snprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsnprintf(buf, size, fmt, args);
+ va_end(args);
+
+ return i;
+}
+
+int scnprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vscnprintf(buf, size, fmt, args);
+ va_end(args);
+
+ return i;
+}
+#endif /* CONFIG_SYS_VSNPRINT */
+
/**
- * sprintf - Format a string and place it in a buffer
- * @buf: The buffer to place the result into
- * @fmt: The format string to use
- * @...: Arguments for the format string
+ * Format a string and place it in a buffer (va_list version)
+ *
+ * @param buf The buffer to place the result into
+ * @param fmt The format string to use
+ * @param args Arguments for the format string
*
* The function returns the number of characters written
- * into @buf.
+ * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
+ * buffer overflows.
*
- * See the vsprintf() documentation for format string extensions over C99.
+ * If you're not already dealing with a va_list consider using sprintf().
*/
-int sprintf(char * buf, const char *fmt, ...)
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ return vsnprintf_internal(buf, INT_MAX, fmt, args);
+}
+
+int sprintf(char *buf, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
- i=vsprintf(buf,fmt,args);
+ i = vsprintf(buf, fmt, args);
va_end(args);
return i;
}
void panic(const char *fmt, ...)
{
- va_list args;
+ va_list args;
va_start(args, fmt);
vprintf(fmt, args);
putc('\n');
va_end(args);
-#if defined (CONFIG_PANIC_HANG)
+#if defined(CONFIG_PANIC_HANG)
hang();
#else
- udelay (100000); /* allow messages to go out */
- do_reset (NULL, 0, 0, NULL);
+ udelay(100000); /* allow messages to go out */
+ do_reset(NULL, 0, 0, NULL);
#endif
+ while (1)
+ ;
+}
+
+void __assert_fail(const char *assertion, const char *file, unsigned line,
+ const char *function)
+{
+ /* This will not return */
+ panic("%s:%u: %s: Assertion `%s' failed.", file, line, function,
+ assertion);
+}
+
+char *simple_itoa(ulong i)
+{
+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ static char local[22];
+ char *p = &local[21];
+
+ *p-- = '\0';
+ do {
+ *p-- = '0' + i % 10;
+ i /= 10;
+ } while (i > 0);
+ return p + 1;
+}
+
+/* We don't seem to have %'d in U-Boot */
+void print_grouped_ull(unsigned long long int_val, int digits)
+{
+ char str[21], *s;
+ int grab = 3;
+
+ digits = (digits + 2) / 3;
+ sprintf(str, "%*llu", digits * 3, int_val);
+ for (s = str; *s; s += grab) {
+ if (s != str)
+ putc(s[-1] != ' ' ? ',' : ' ');
+ printf("%.*s", grab, s);
+ grab = 3;
+ }
}
diff --git a/net/net.c b/net/net.c
index 1a524fc95f..f7cc29f039 100644
--- a/net/net.c
+++ b/net/net.c
@@ -211,12 +211,6 @@ int __maybe_unused net_busy_flag;
/**********************************************************************/
-enum env_op {
- env_op_create,
- env_op_delete,
- env_op_overwrite,
-};
-
static int on_bootfile(const char *name, const char *value, enum env_op op,
int flags)
{