diff options
| author | wdenk <wdenk> | 2002-10-11 08:38:32 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2002-10-11 08:38:32 +0000 | 
| commit | a68d3ed0ac99cff182733e66b0812620748d7258 (patch) | |
| tree | eaf6cc8833cfc66c1587983f51be2d3b5ea7be09 | |
| parent | 32fe2871cb4cc0917881a5115cea932d5ecb1681 (diff) | |
| download | olio-uboot-2014.01-a68d3ed0ac99cff182733e66b0812620748d7258.tar.xz olio-uboot-2014.01-a68d3ed0ac99cff182733e66b0812620748d7258.zip | |
Initial revision
| -rw-r--r-- | common/cmd_nvedit.c | 535 | 
1 files changed, 535 insertions, 0 deletions
| diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c new file mode 100644 index 000000000..08e888c08 --- /dev/null +++ b/common/cmd_nvedit.c @@ -0,0 +1,535 @@ +/* + * (C) Copyright 2000-2002 + * 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. + * + * 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 + */ + +/************************************************************************** + * + * Support for persistent environment data + * + * The "environment" is stored as a list of '\0' terminated + * "name=value" strings. The end of the list is marked by a double + * '\0'. New entries are always added at the end. Deleting an entry + * shifts the remaining entries to the front. Replacing an entry is a + * combination of deleting the old value and adding the new one. + * + * The environment is preceeded by a 32 bit CRC over the data part. + * + ************************************************************************** + */ + +#include <common.h> +#include <command.h> +#include <environment.h> +#include <cmd_nvedit.h> +#include <linux/stddef.h> +#include <asm/byteorder.h> +#if (CONFIG_COMMANDS & CFG_CMD_NET) +#include <net.h> +#endif + +#if !defined(CFG_ENV_IS_IN_NVRAM) && !defined(CFG_ENV_IS_IN_EEPROM) && !defined(CFG_ENV_IS_IN_FLASH) && !defined(CFG_ENV_IS_NOWHERE) +# error Define one of CFG_ENV_IS_IN_NVRAM, CFG_ENV_IS_IN_EEPROM, CFG_ENV_IS_IN_FLASH, CFG_ENV_IS_NOWHERE +#endif + +#define XMK_STR(x)	#x +#define MK_STR(x)	XMK_STR(x) + +/************************************************************************ +************************************************************************/ + +/* Function that returns a character from the environment */ +extern uchar (*env_get_char)(int); + +/* Function that returns a pointer to a value from the environment */ +/* (Only memory version supported / needed). */ +extern uchar *env_get_addr(int); + +/* Function that updates CRC of the enironment */ +extern void env_crc_update (void); + +/************************************************************************ +************************************************************************/ + +static int envmatch (uchar *, int); + +/* + * Table with supported baudrates (defined in config_xyz.h) + */ +static const unsigned long baudrate_table[] = CFG_BAUDRATE_TABLE; +#define	N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0])) + + +/************************************************************************ + * Command interface: print one or all environment variables + */ + +int do_printenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	int i, j, k, nxt; +	int rcode = 0; + +	if (argc == 1) {		/* Print all env variables	*/ +		for (i=0; env_get_char(i) != '\0'; i=nxt+1) { +			for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) +				; +			for (k=i; k<nxt; ++k) +				putc(env_get_char(k)); +			putc  ('\n'); + +			if (ctrlc()) { +				puts ("\n ** Abort\n"); +				return 1; +			} +		} + +		printf("\nEnvironment size: %d/%d bytes\n", i, ENV_SIZE); + +		return 0; +	} + +	for (i=1; i<argc; ++i) {	/* print single env variables	*/ +		char *name = argv[i]; + +		k = -1; + +		for (j=0; env_get_char(j) != '\0'; j=nxt+1) { + +			for (nxt=j; env_get_char(nxt) != '\0'; ++nxt) +				; +			k = envmatch(name, j); +			if (k < 0) { +				continue; +			} +			puts (name); +			putc ('='); +			while (k < nxt) +				putc(env_get_char(k++)); +			putc ('\n'); +			break; +		} +		if (k < 0) { +			printf ("## Error: \"%s\" not defined\n", name); +			rcode ++; +		} +	} +	return rcode; +} + +/************************************************************************ + * Set a new environment variable, + * or replace or delete an existing one. + * + * This function will ONLY work with a in-RAM copy of the environment + */ + +int _do_setenv (int flag, int argc, char *argv[]) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	int   i, len, oldval; +	int   console = -1; +	uchar *env, *nxt = NULL; +	uchar *name; +	bd_t *bd = gd->bd; + +	uchar *env_data = env_get_addr(0); + +	if (!env_data)	/* need copy in RAM */ +		return 1; + +	name = argv[1]; + +	/* +	 * search if variable with this name already exists +	 */ +	oldval = -1; +	for (env=env_data; *env; env=nxt+1) { +		for (nxt=env; *nxt; ++nxt) +			; +		if ((oldval = envmatch(name, env-env_data)) >= 0) +			break; +	} + +	/* +	 * Delete any existing definition +	 */ +	if (oldval >= 0) { +#ifndef CONFIG_ENV_OVERWRITE + +		/* +		 * Ethernet Address and serial# can be set only once +		 */ +		if ( (strcmp (name, "serial#") == 0) || +		    ((strcmp (name, "ethaddr") == 0) +#if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) +		     && (strcmp (env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0) +#endif	/* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */ +		    ) ) { +			printf ("Can't overwrite \"%s\"\n", name); +			return 1; +		} +#endif + +		/* 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; +			} + +			/* Try assigning specified device */ +			if (console_assign (console, argv[2]) < 0) +				return 1; +		} + +		/* +		 * Switch to new baudrate if new baudrate is supported +		 */ +		if (strcmp(argv[1],"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; +			serial_setbrg (); +			udelay(50000); +			for (;;) { +				if (getc() == '\r') +				      break; +			} +		} + +		if (*++nxt == '\0') { +			if (env > env_data) { +				env--; +			} else { +				*env = '\0'; +			} +		} else { +			for (;;) { +				*env = *nxt++; +				if ((*env == '\0') && (*nxt == '\0')) +					break; +				++env; +			} +		} +		*++env = '\0'; +	} + +#ifdef CONFIG_NET_MULTI +	if (strncmp(name, "eth", 3) == 0) { +		char *end; +		int   num = simple_strtoul(name+3, &end, 10); + +		if (strcmp(end, "addr") == 0) { +			eth_set_enetaddr(num, argv[2]); +		} +	} +#endif + + +	/* Delete only ? */ +	if ((argc < 3) || argv[2] == NULL) { +		env_crc_update (); +		return 0; +	} + +	/* +	 * Append new definition at the end +	 */ +	for (env=env_data; *env || *(env+1); ++env) +		; +	if (env > env_data) +		++env; +	/* +	 * Overflow when: +	 * "name" + "=" + "val" +"\0\0"  > ENV_SIZE - (env-env_data) +	 */ +	len = strlen(name) + 2; +	/* add '=' for first arg, ' ' for all others */ +	for (i=2; i<argc; ++i) { +		len += strlen(argv[i]) + 1; +	} +	if (len > (&env_data[ENV_SIZE]-env)) { +		printf ("## Error: environment overflow, \"%s\" deleted\n", name); +		return 1; +	} +	while ((*env = *name++) != '\0') +		env++; +	for (i=2; i<argc; ++i) { +		char *val = argv[i]; + +		*env = (i==2) ? '=' : ' '; +		while ((*++env = *val++) != '\0') +			; +	} + +	/* end is marked with double '\0' */ +	*++env = '\0'; + +	/* Update CRC */ +	env_crc_update (); + +	/* +	 * Some variables should be updated when the corresponding +	 * entry in the enviornment is changed +	 */ + +	if (strcmp(argv[1],"ethaddr") == 0) { +		char *s = argv[2];	/* always use only one arg */ +		char *e; +		for (i=0; i<6; ++i) { +			bd->bi_enetaddr[i] = s ? simple_strtoul(s, &e, 16) : 0; +			if (s) s = (*e) ? e+1 : e; +		} +#ifdef CONFIG_NET_MULTI +		eth_set_enetaddr(0, argv[2]); +#endif +		return 0; +	} + +	if (strcmp(argv[1],"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; +	} +	if (strcmp(argv[1],"loadaddr") == 0) { +		load_addr = simple_strtoul(argv[2], NULL, 16); +		return 0; +	} +#if (CONFIG_COMMANDS & CFG_CMD_NET) +	if (strcmp(argv[1],"bootfile") == 0) { +		copy_filename (BootFile, argv[2], sizeof(BootFile)); +		return 0; +	} +#endif	/* CFG_CMD_NET */ +	return 0; +} + +void setenv (char *varname, char *varvalue) +{ +	char *argv[4] = { "setenv", varname, varvalue, NULL }; +	_do_setenv (0, 3, argv); +} + +int do_setenv ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	if (argc < 2) { +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; +	} + +	return _do_setenv (flag, argc, argv); +} + +/************************************************************************ + * Prompt for environment variable + */ + +#if (CONFIG_COMMANDS & CFG_CMD_ASKENV) +int do_askenv ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	extern char console_buffer[CFG_CBSIZE]; +	char message[CFG_CBSIZE]; +	int size = CFG_CBSIZE - 1; +	int len; +	char *local_args[4]; + +	local_args[0] = argv[0]; +	local_args[1] = argv[1]; +	local_args[2] = NULL; +	local_args[3] = NULL; + +	if (argc < 2) { +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; +	} +	/* Check the syntax */ +	switch (argc) { +	case 1: +		printf ("Usage:\n%s\n", cmdtp->usage); +		return 1; + +	case 2:		/* askenv envname */ +		sprintf (message, "Please enter '%s':", argv[1]); +		break; + +	case 3:		/* askenv envname size */ +		sprintf (message, "Please enter '%s':", argv[1]); +		size = simple_strtoul (argv[2], NULL, 10); +		break; + +	default:	/* askenv envname message1 ... messagen size */ +	    { +		int i; +		int pos = 0; + +		for (i = 2; i < argc - 1; i++) { +			if (pos) { +				message[pos++] = ' '; +			} +			strcpy (message+pos, argv[i]); +			pos += strlen(argv[i]); +		} +		message[pos] = '\0'; +		size = simple_strtoul (argv[argc - 1], NULL, 10); +	    } +		break; +	} + +	if (size >= CFG_CBSIZE) +		size = CFG_CBSIZE - 1; + +	if (size <= 0) +		return 1; + +	/* prompt for input */ +	len = readline (message); + +	if (size < len) +		console_buffer[size] = '\0'; + +	len = 2; +	if (console_buffer[0] != '\0') { +		local_args[2] = console_buffer; +		len = 3; +	} + +	/* Continue calling setenv code */ +	return _do_setenv (flag, len, local_args); +} +#endif	/* CFG_CMD_ASKENV */ + +/************************************************************************ + * Look up variable from environment, + * return address of storage for that variable, + * or NULL if not found + */ + +char *getenv (uchar *name) +{ +	int i, nxt; + +	for (i=0; env_get_char(i) != '\0'; i=nxt+1) { +		int val; + +		for (nxt=i; env_get_char(nxt) != '\0'; ++nxt) { +			if (nxt >= CFG_ENV_SIZE) { +				return (NULL); +			} +		} +		if ((val=envmatch(name, i)) < 0) +			continue; +		return (env_get_addr(val)); +	} + +	return (NULL); +} + +int getenv_r (uchar *name, uchar *buf, unsigned len) +{ +	int i, nxt; + +	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 >= CFG_ENV_SIZE) { +				return (-1); +			} +		} +		if ((val=envmatch(name, i)) < 0) +			continue; +		/* found; copy out */ +		n = 0; +		while ((len > n++) && (*buf++ = env_get_char(val++)) != '\0') +			; +		if (len == n) +			*buf = '\0'; +		return (n); +	} +	return (-1); +} + +#if defined(CFG_ENV_IS_IN_NVRAM) || defined(CFG_ENV_IS_IN_EEPROM) || \ +    ((CONFIG_COMMANDS & (CFG_CMD_ENV|CFG_CMD_FLASH)) == \ +      (CFG_CMD_ENV|CFG_CMD_FLASH)) +int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ +	extern char * env_name_spec; + +	printf ("Saving Environment to %s...\n", env_name_spec); + +	return (saveenv() ? 1 : 0); +} +#endif + + +/************************************************************************ + * Match a name / name=value pair + * + * 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. + */ + +static int +envmatch (uchar *s1, int i2) +{ + +	while (*s1 == env_get_char(i2++)) +		if (*s1++ == '=') +			return(i2); +	if (*s1 == '\0' && env_get_char(i2-1) == '=') +		return(i2); +	return(-1); +} |