diff options
Diffstat (limited to 'common')
| -rw-r--r-- | common/Makefile | 7 | ||||
| -rw-r--r-- | common/cmd_bdinfo.c | 10 | ||||
| -rw-r--r-- | common/cmd_dfu.c | 81 | ||||
| -rw-r--r-- | common/cmd_ext2.c | 219 | ||||
| -rw-r--r-- | common/cmd_ext4.c | 237 | ||||
| -rw-r--r-- | common/cmd_ext_common.c | 259 | ||||
| -rw-r--r-- | common/cmd_fdt.c | 13 | ||||
| -rw-r--r-- | common/cmd_flash.c | 3 | ||||
| -rw-r--r-- | common/cmd_mmc.c | 3 | ||||
| -rw-r--r-- | common/cmd_nand.c | 25 | ||||
| -rw-r--r-- | common/cmd_nvedit.c | 194 | ||||
| -rw-r--r-- | common/cmd_spi.c | 2 | ||||
| -rw-r--r-- | common/dlmalloc.c | 10 | ||||
| -rw-r--r-- | common/env_common.c | 39 | ||||
| -rw-r--r-- | common/env_mmc.c | 64 | ||||
| -rw-r--r-- | common/env_nand.c | 10 | ||||
| -rw-r--r-- | common/flash.c | 3 | ||||
| -rw-r--r-- | common/hush.c | 107 | ||||
| -rw-r--r-- | common/image.c | 7 | ||||
| -rw-r--r-- | common/usb_hub.c | 14 | ||||
| -rw-r--r-- | common/usb_storage.c | 58 | 
21 files changed, 1022 insertions, 343 deletions
| diff --git a/common/Makefile b/common/Makefile index 3d62775dc..22e8a6fb3 100644 --- a/common/Makefile +++ b/common/Makefile @@ -86,7 +86,13 @@ COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o  COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o  COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o  COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_exit.o +COBJS-$(CONFIG_CMD_EXT4) += cmd_ext4.o  COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o +ifdef CONFIG_CMD_EXT4 +COBJS-y	+= cmd_ext_common.o +else +COBJS-$(CONFIG_CMD_EXT2) += cmd_ext_common.o +endif  COBJS-$(CONFIG_CMD_FAT) += cmd_fat.o  COBJS-$(CONFIG_CMD_FDC)$(CONFIG_CMD_FDOS) += cmd_fdc.o  COBJS-$(CONFIG_OF_LIBFDT) += cmd_fdt.o fdt_support.o @@ -184,6 +190,7 @@ COBJS-$(CONFIG_MENU) += menu.o  COBJS-$(CONFIG_MODEM_SUPPORT) += modem.o  COBJS-$(CONFIG_UPDATE_TFTP) += update.o  COBJS-$(CONFIG_USB_KEYBOARD) += usb_kbd.o +COBJS-$(CONFIG_CMD_DFU) += cmd_dfu.o  endif  ifdef CONFIG_SPL_BUILD diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index 42f08fdd0..23bd8a509 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -216,15 +216,15 @@ int do_bdinfo(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  	print_num("flashstart             ", bd->bi_flashstart);  	print_num("CONFIG_SYS_MONITOR_BASE       ", CONFIG_SYS_MONITOR_BASE);  	print_num("CONFIG_ENV_ADDR           ", CONFIG_ENV_ADDR); -	printf("CONFIG_SYS_RELOC_MONITOR_BASE = 0x%lx (%d)\n", CONFIG_SYS_RELOC_MONITOR_BASE, +	printf("CONFIG_SYS_RELOC_MONITOR_BASE = 0x%x (%d)\n", CONFIG_SYS_RELOC_MONITOR_BASE,  	       CONFIG_SYS_MONITOR_LEN); -	printf("CONFIG_SYS_MALLOC_BASE        = 0x%lx (%d)\n", CONFIG_SYS_MALLOC_BASE, +	printf("CONFIG_SYS_MALLOC_BASE        = 0x%x (%d)\n", CONFIG_SYS_MALLOC_BASE,  	       CONFIG_SYS_MALLOC_LEN); -	printf("CONFIG_SYS_INIT_SP_OFFSET     = 0x%lx (%d)\n", CONFIG_SYS_INIT_SP_OFFSET, +	printf("CONFIG_SYS_INIT_SP_OFFSET     = 0x%x (%d)\n", CONFIG_SYS_INIT_SP_OFFSET,  	       CONFIG_SYS_STACK_SIZE); -	printf("CONFIG_SYS_PROM_OFFSET        = 0x%lx (%d)\n", CONFIG_SYS_PROM_OFFSET, +	printf("CONFIG_SYS_PROM_OFFSET        = 0x%x (%d)\n", CONFIG_SYS_PROM_OFFSET,  	       CONFIG_SYS_PROM_SIZE); -	printf("CONFIG_SYS_GBL_DATA_OFFSET    = 0x%lx (%d)\n", CONFIG_SYS_GBL_DATA_OFFSET, +	printf("CONFIG_SYS_GBL_DATA_OFFSET    = 0x%x (%d)\n", CONFIG_SYS_GBL_DATA_OFFSET,  	       GENERATED_GBL_DATA_SIZE);  #if defined(CONFIG_CMD_NET) diff --git a/common/cmd_dfu.c b/common/cmd_dfu.c new file mode 100644 index 000000000..62fb8904c --- /dev/null +++ b/common/cmd_dfu.c @@ -0,0 +1,81 @@ +/* + * cmd_dfu.c -- dfu command + * + * Copyright (C) 2012 Samsung Electronics + * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + *	    Lukasz Majewski <l.majewski@samsung.com> + * + * 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 + */ + +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <dfu.h> +#include <asm/errno.h> +#include <g_dnl.h> + +static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	const char *str_env; +	char s[] = "dfu"; +	char *env_bkp; +	int ret; + +	if (argc < 3) +		return CMD_RET_USAGE; + +	str_env = getenv("dfu_alt_info"); +	if (str_env == NULL) { +		printf("%s: \"dfu_alt_info\" env variable not defined!\n", +		       __func__); +		return CMD_RET_FAILURE; +	} + +	env_bkp = strdup(str_env); +	ret = dfu_config_entities(env_bkp, argv[1], +			    (int)simple_strtoul(argv[2], NULL, 10)); +	if (ret) +		return CMD_RET_FAILURE; + +	if (strcmp(argv[3], "list") == 0) { +		dfu_show_entities(); +		goto done; +	} + +	board_usb_init(); +	g_dnl_register(s); +	while (1) { +		if (ctrlc()) +			goto exit; + +		usb_gadget_handle_interrupts(); +	} +exit: +	g_dnl_unregister(); +done: +	dfu_free_entities(); +	free(env_bkp); + +	return CMD_RET_SUCCESS; +} + +U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu, +	"Device Firmware Upgrade", +	"<interface> <dev> [list]\n" +	"  - device firmware upgrade on a device <dev>\n" +	"    attached to interface <interface>\n" +	"    [list] - list available alt settings" +); diff --git a/common/cmd_ext2.c b/common/cmd_ext2.c index 79b1e2fb6..c27d9c7ed 100644 --- a/common/cmd_ext2.c +++ b/common/cmd_ext2.c @@ -1,4 +1,9 @@  /* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> +   * (C) Copyright 2004   * esd gmbh <www.esd-electronics.com>   * Reinhard Arlt <reinhard.arlt@esd-electronics.com> @@ -33,225 +38,35 @@   * Ext2fs support   */  #include <common.h> -#include <part.h> -#include <config.h> -#include <command.h> -#include <image.h> -#include <linux/ctype.h> -#include <asm/byteorder.h> -#include <ext2fs.h> -#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) -#include <usb.h> -#endif - -#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) -#error DOS or EFI partition support must be selected -#endif - -/* #define	EXT2_DEBUG */ - -#ifdef	EXT2_DEBUG -#define	PRINTF(fmt,args...)	printf (fmt ,##args) -#else -#define PRINTF(fmt,args...) -#endif +#include <ext_common.h>  int do_ext2ls (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	char *filename = "/"; -	int dev=0; -	int part=1; -	char *ep; -	block_dev_desc_t *dev_desc=NULL; -	int part_length; - -	if (argc < 3) -		return CMD_RET_USAGE; - -	dev = (int)simple_strtoul (argv[2], &ep, 16); -	dev_desc = get_dev(argv[1],dev); - -	if (dev_desc == NULL) { -		printf ("\n** Block device %s %d not supported\n", argv[1], dev); -		return 1; -	} - -	if (*ep) { -		if (*ep != ':') { -			puts ("\n** Invalid boot device, use `dev[:part]' **\n"); -			return 1; -		} -		part = (int)simple_strtoul(++ep, NULL, 16); -	} - -	if (argc == 4) -		filename = argv[3]; - -	PRINTF("Using device %s %d:%d, directory: %s\n", argv[1], dev, part, filename); - -	if ((part_length = ext2fs_set_blk_dev(dev_desc, part)) == 0) { -		printf ("** Bad partition - %s %d:%d **\n",  argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	if (!ext2fs_mount(part_length)) { -		printf ("** Bad ext2 partition or disk - %s %d:%d **\n",  argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	if (ext2fs_ls (filename)) { -		printf ("** Error ext2fs_ls() **\n"); -		ext2fs_close(); -		return 1; -	}; - -	ext2fs_close(); +	if (do_ext_ls(cmdtp, flag, argc, argv)) +		return -1;  	return 0;  } -U_BOOT_CMD( -	ext2ls,	4,	1,	do_ext2ls, -	"list files in a directory (default /)", -	"<interface> <dev[:part]> [directory]\n" -	"    - list files from 'dev' on 'interface' in a 'directory'" -); -  /******************************************************************************   * Ext2fs boot command intepreter. Derived from diskboot   */  int do_ext2load (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  { -	char *filename = NULL; -	char *ep; -	int dev, part = 1; -	ulong addr = 0, part_length; -	int filelen; -	disk_partition_t info; -	block_dev_desc_t *dev_desc = NULL; -	char buf [12]; -	unsigned long count; -	char *addr_str; - -	switch (argc) { -	case 3: -		addr_str = getenv("loadaddr"); -		if (addr_str != NULL) -			addr = simple_strtoul (addr_str, NULL, 16); -		else -			addr = CONFIG_SYS_LOAD_ADDR; - -		filename = getenv ("bootfile"); -		count = 0; -		break; -	case 4: -		addr = simple_strtoul (argv[3], NULL, 16); -		filename = getenv ("bootfile"); -		count = 0; -		break; -	case 5: -		addr = simple_strtoul (argv[3], NULL, 16); -		filename = argv[4]; -		count = 0; -		break; -	case 6: -		addr = simple_strtoul (argv[3], NULL, 16); -		filename = argv[4]; -		count = simple_strtoul (argv[5], NULL, 16); -		break; - -	default: -		return CMD_RET_USAGE; -	} - -	if (!filename) { -		puts ("** No boot file defined **\n"); -		return 1; -	} - -	dev = (int)simple_strtoul (argv[2], &ep, 16); -	dev_desc = get_dev(argv[1],dev); -	if (dev_desc==NULL) { -		printf ("** Block device %s %d not supported\n", argv[1], dev); -		return 1; -	} -	if (*ep) { -		if (*ep != ':') { -			puts ("** Invalid boot device, use `dev[:part]' **\n"); -			return 1; -		} -		part = (int)simple_strtoul(++ep, NULL, 16); -	} - -	PRINTF("Using device %s%d, partition %d\n", argv[1], dev, part); - -	if (part != 0) { -		if (get_partition_info (dev_desc, part, &info)) { -			printf ("** Bad partition %d **\n", part); -			return 1; -		} - -		if (strncmp((char *)info.type, BOOT_PART_TYPE, sizeof(info.type)) != 0) { -			printf ("** Invalid partition type \"%.32s\"" -				" (expect \"" BOOT_PART_TYPE "\")\n", -				info.type); -			return 1; -		} -		printf ("Loading file \"%s\" " -			"from %s device %d:%d (%.32s)\n", -			filename, -			argv[1], dev, part, info.name); -	} else { -		printf ("Loading file \"%s\" from %s device %d\n", -			filename, argv[1], dev); -	} - - -	if ((part_length = ext2fs_set_blk_dev(dev_desc, part)) == 0) { -		printf ("** Bad partition - %s %d:%d **\n",  argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	if (!ext2fs_mount(part_length)) { -		printf ("** Bad ext2 partition or disk - %s %d:%d **\n", -			argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	filelen = ext2fs_open(filename); -	if (filelen < 0) { -		printf("** File not found %s\n", filename); -		ext2fs_close(); -		return 1; -	} -	if ((count < filelen) && (count != 0)) { -	    filelen = count; -	} - -	if (ext2fs_read((char *)addr, filelen) != filelen) { -		printf("** Unable to read \"%s\" from %s %d:%d **\n", -			filename, argv[1], dev, part); -		ext2fs_close(); -		return 1; -	} - -	ext2fs_close(); - -	/* Loading ok, update default load address */ -	load_addr = addr; - -	printf ("%d bytes read\n", filelen); -	sprintf(buf, "%X", filelen); -	setenv("filesize", buf); +	if (do_ext_load(cmdtp, flag, argc, argv)) +		return -1;  	return 0;  }  U_BOOT_CMD( +	ext2ls,	4,	1,	do_ext2ls, +	"list files in a directory (default /)", +	"<interface> <dev[:part]> [directory]\n" +	"    - list files from 'dev' on 'interface' in a 'directory'" +); + +U_BOOT_CMD(  	ext2load,	6,	0,	do_ext2load,  	"load binary file from a Ext2 filesystem",  	"<interface> <dev[:part]> [addr] [filename] [bytes]\n" diff --git a/common/cmd_ext4.c b/common/cmd_ext4.c new file mode 100644 index 000000000..77094c4eb --- /dev/null +++ b/common/cmd_ext4.c @@ -0,0 +1,237 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * Ext4fs support + * made from existing cmd_ext2.c file of Uboot + * + * (C) Copyright 2004 + * esd gmbh <www.esd-electronics.com> + * Reinhard Arlt <reinhard.arlt@esd-electronics.com> + * + * made from cmd_reiserfs by + * + * (C) Copyright 2003 - 2004 + * Sysgo Real-Time Solutions, AG <www.elinos.com> + * Pavel Bartusek <pba@sysgo.com> + * + * 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 + * + */ + +/* + * Changelog: + *	0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c + *	        file in uboot. Added ext4fs ls load and write support. + */ + +#include <common.h> +#include <part.h> +#include <config.h> +#include <command.h> +#include <image.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <ext_common.h> +#include <ext4fs.h> +#include <linux/stat.h> +#include <malloc.h> + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) +#include <usb.h> +#endif + +#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) +#error DOS or EFI partition support must be selected +#endif + +uint64_t total_sector; +uint64_t part_offset; +#if defined(CONFIG_CMD_EXT4_WRITE) +static uint64_t part_size; +static uint16_t cur_part = 1; +#endif + +#define DOS_PART_MAGIC_OFFSET		0x1fe +#define DOS_FS_TYPE_OFFSET		0x36 +#define DOS_FS32_TYPE_OFFSET		0x52 + +int do_ext4_load(cmd_tbl_t *cmdtp, int flag, int argc, +						char *const argv[]) +{ +	if (do_ext_load(cmdtp, flag, argc, argv)) +		return -1; + +	return 0; +} + +int do_ext4_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	if (do_ext_ls(cmdtp, flag, argc, argv)) +		return -1; + +	return 0; +} + +#if defined(CONFIG_CMD_EXT4_WRITE) +static int ext4_register_device(block_dev_desc_t *dev_desc, int part_no) +{ +	unsigned char buffer[SECTOR_SIZE]; +	disk_partition_t info; + +	if (!dev_desc->block_read) +		return -1; + +	/* check if we have a MBR (on floppies we have only a PBR) */ +	if (dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *) buffer) != 1) { +		printf("** Can't read from device %d **\n", dev_desc->dev); +		return -1; +	} +	if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 || +	    buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) { +		/* no signature found */ +		return -1; +	} + +	/* First we assume there is a MBR */ +	if (!get_partition_info(dev_desc, part_no, &info)) { +		part_offset = info.start; +		cur_part = part_no; +		part_size = info.size; +	} else if ((strncmp((char *)&buffer[DOS_FS_TYPE_OFFSET], +			    "FAT", 3) == 0) || (strncmp((char *)&buffer +							[DOS_FS32_TYPE_OFFSET], +							"FAT32", 5) == 0)) { +		/* ok, we assume we are on a PBR only */ +		cur_part = 1; +		part_offset = 0; +	} else { +		printf("** Partition %d not valid on device %d **\n", +		       part_no, dev_desc->dev); +		return -1; +	} + +	return 0; +} + +int do_ext4_write(cmd_tbl_t *cmdtp, int flag, int argc, +				char *const argv[]) +{ +	const char *filename = "/"; +	int part_length; +	unsigned long part = 1; +	int dev; +	char *ep; +	unsigned long ram_address; +	unsigned long file_size; +	disk_partition_t info; +	struct ext_filesystem *fs; + +	if (argc < 6) +		return cmd_usage(cmdtp); + +	dev = (int)simple_strtoul(argv[2], &ep, 16); +	ext4_dev_desc = get_dev(argv[1], dev); +	if (ext4_dev_desc == NULL) { +		printf("Block device %s %d not supported\n", argv[1], dev); +		return 1; +	} +	if (init_fs(ext4_dev_desc)) +		return 1; + +	fs = get_fs(); +	if (*ep) { +		if (*ep != ':') { +			puts("Invalid boot device, use `dev[:part]'\n"); +			goto fail; +		} +		part = simple_strtoul(++ep, NULL, 16); +	} + +	/* get the filename */ +	filename = argv[3]; + +	/* get the address in hexadecimal format (string to int) */ +	ram_address = simple_strtoul(argv[4], NULL, 16); + +	/* get the filesize in base 10 format */ +	file_size = simple_strtoul(argv[5], NULL, 10); + +	/* set the device as block device */ +	part_length = ext4fs_set_blk_dev(fs->dev_desc, part); +	if (part_length == 0) { +		printf("Bad partition - %s %d:%lu\n", argv[1], dev, part); +		goto fail; +	} + +	/* register the device and partition */ +	if (ext4_register_device(fs->dev_desc, part) != 0) { +		printf("Unable to use %s %d:%lu for fattable\n", +		       argv[1], dev, part); +		goto fail; +	} + +	/* get the partition information */ +	if (!get_partition_info(fs->dev_desc, part, &info)) { +		total_sector = (info.size * info.blksz) / SECTOR_SIZE; +		fs->total_sect = total_sector; +	} else { +		printf("error : get partition info\n"); +		goto fail; +	} + +	/* mount the filesystem */ +	if (!ext4fs_mount(part_length)) { +		printf("Bad ext4 partition %s %d:%lu\n", argv[1], dev, part); +		goto fail; +	} + +	/* start write */ +	if (ext4fs_write(filename, (unsigned char *)ram_address, file_size)) { +		printf("** Error ext4fs_write() **\n"); +		goto fail; +	} +	ext4fs_close(); +	deinit_fs(fs->dev_desc); + +	return 0; + +fail: +	ext4fs_close(); +	deinit_fs(fs->dev_desc); + +	return 1; +} + +U_BOOT_CMD(ext4write, 6, 1, do_ext4_write, +	"create a file in the root directory", +	"<interface> <dev[:part]> [Absolute filename path] [Address] [sizebytes]\n" +	"	  - create a file in / directory"); + +#endif + +U_BOOT_CMD(ext4ls, 4, 1, do_ext4_ls, +	   "list files in a directory (default /)", +	   "<interface> <dev[:part]> [directory]\n" +	   "	  - list files from 'dev' on 'interface' in a 'directory'"); + +U_BOOT_CMD(ext4load, 6, 0, do_ext4_load, +	   "load binary file from a Ext4 filesystem", +	   "<interface> <dev[:part]> [addr] [filename] [bytes]\n" +	   "	  - load binary file 'filename' from 'dev' on 'interface'\n" +	   "		 to address 'addr' from ext4 filesystem"); diff --git a/common/cmd_ext_common.c b/common/cmd_ext_common.c new file mode 100644 index 000000000..56ee9a55b --- /dev/null +++ b/common/cmd_ext_common.c @@ -0,0 +1,259 @@ +/* + * (C) Copyright 2011 - 2012 Samsung Electronics + * EXT2/4 filesystem implementation in Uboot by + * Uma Shankar <uma.shankar@samsung.com> + * Manjunatha C Achar <a.manjunatha@samsung.com> + * + * Ext4fs support + * made from existing cmd_ext2.c file of Uboot + * + * (C) Copyright 2004 + * esd gmbh <www.esd-electronics.com> + * Reinhard Arlt <reinhard.arlt@esd-electronics.com> + * + * made from cmd_reiserfs by + * + * (C) Copyright 2003 - 2004 + * Sysgo Real-Time Solutions, AG <www.elinos.com> + * Pavel Bartusek <pba@sysgo.com> + * + * 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 + * + */ + +/* + * Changelog: + *	0.1 - Newly created file for ext4fs support. Taken from cmd_ext2.c + *	        file in uboot. Added ext4fs ls load and write support. + */ + +#include <common.h> +#include <part.h> +#include <config.h> +#include <command.h> +#include <image.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <ext_common.h> +#include <ext4fs.h> +#include <linux/stat.h> +#include <malloc.h> + +#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE) +#include <usb.h> +#endif + +#if !defined(CONFIG_DOS_PARTITION) && !defined(CONFIG_EFI_PARTITION) +#error DOS or EFI partition support must be selected +#endif + +#define DOS_PART_MAGIC_OFFSET		0x1fe +#define DOS_FS_TYPE_OFFSET		0x36 +#define DOS_FS32_TYPE_OFFSET		0x52 + +int do_ext_load(cmd_tbl_t *cmdtp, int flag, int argc, +						char *const argv[]) +{ +	char *filename = NULL; +	char *ep; +	int dev; +	unsigned long part = 1; +	ulong addr = 0; +	ulong part_length; +	int filelen; +	disk_partition_t info; +	struct ext_filesystem *fs; +	char buf[12]; +	unsigned long count; +	const char *addr_str; + +	count = 0; +	addr = simple_strtoul(argv[3], NULL, 16); +	filename = getenv("bootfile"); +	switch (argc) { +	case 3: +		addr_str = getenv("loadaddr"); +		if (addr_str != NULL) +			addr = simple_strtoul(addr_str, NULL, 16); +		else +			addr = CONFIG_SYS_LOAD_ADDR; + +		break; +	case 4: +		break; +	case 5: +		filename = argv[4]; +		break; +	case 6: +		filename = argv[4]; +		count = simple_strtoul(argv[5], NULL, 16); +		break; + +	default: +		return cmd_usage(cmdtp); +	} + +	if (!filename) { +		puts("** No boot file defined **\n"); +		return 1; +	} + +	dev = (int)simple_strtoul(argv[2], &ep, 16); +	ext4_dev_desc = get_dev(argv[1], dev); +	if (ext4_dev_desc == NULL) { +		printf("** Block device %s %d not supported\n", argv[1], dev); +		return 1; +	} +	if (init_fs(ext4_dev_desc)) +		return 1; + +	fs = get_fs(); +	if (*ep) { +		if (*ep != ':') { +			puts("** Invalid boot device, use `dev[:part]' **\n"); +			goto fail; +		} +		part = simple_strtoul(++ep, NULL, 16); +	} + +	if (part != 0) { +		if (get_partition_info(fs->dev_desc, part, &info)) { +			printf("** Bad partition %lu **\n", part); +			goto fail; +		} + +		if (strncmp((char *)info.type, BOOT_PART_TYPE, +			    strlen(BOOT_PART_TYPE)) != 0) { +			printf("** Invalid partition type \"%s\"" +			       " (expect \"" BOOT_PART_TYPE "\")\n", info.type); +			goto fail; +		} +		printf("Loading file \"%s\" " +		       "from %s device %d:%lu %s\n", +		       filename, argv[1], dev, part, info.name); +	} else { +		printf("Loading file \"%s\" from %s device %d\n", +		       filename, argv[1], dev); +	} + +	part_length = ext4fs_set_blk_dev(fs->dev_desc, part); +	if (part_length == 0) { +		printf("**Bad partition - %s %d:%lu **\n", argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	if (!ext4fs_mount(part_length)) { +		printf("** Bad ext2 partition or disk - %s %d:%lu **\n", +		       argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	filelen = ext4fs_open(filename); +	if (filelen < 0) { +		printf("** File not found %s\n", filename); +		ext4fs_close(); +		goto fail; +	} +	if ((count < filelen) && (count != 0)) +		filelen = count; + +	if (ext4fs_read((char *)addr, filelen) != filelen) { +		printf("** Unable to read \"%s\" from %s %d:%lu **\n", +		       filename, argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	ext4fs_close(); +	deinit_fs(fs->dev_desc); +	/* Loading ok, update default load address */ +	load_addr = addr; + +	printf("%d bytes read\n", filelen); +	sprintf(buf, "%X", filelen); +	setenv("filesize", buf); + +	return 0; +fail: +	deinit_fs(fs->dev_desc); +	return 1; +} + +int do_ext_ls(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ +	const char *filename = "/"; +	int dev; +	unsigned long part = 1; +	char *ep; +	struct ext_filesystem *fs; +	int part_length; +	if (argc < 3) +		return cmd_usage(cmdtp); + +	dev = (int)simple_strtoul(argv[2], &ep, 16); + +	ext4_dev_desc = get_dev(argv[1], dev); + +	if (ext4_dev_desc == NULL) { +		printf("\n** Block device %s %d not supported\n", argv[1], dev); +		return 1; +	} + +	if (init_fs(ext4_dev_desc)) +		return 1; + +	fs = get_fs(); +	if (*ep) { +		if (*ep != ':') { +			puts("\n** Invalid boot device, use `dev[:part]' **\n"); +			goto fail; +		} +		part = simple_strtoul(++ep, NULL, 16); +	} + +	if (argc == 4) +		filename = argv[3]; + +	part_length = ext4fs_set_blk_dev(fs->dev_desc, part); +	if (part_length == 0) { +		printf("** Bad partition - %s %d:%lu **\n", argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	if (!ext4fs_mount(part_length)) { +		printf("** Bad ext2 partition or disk - %s %d:%lu **\n", +		       argv[1], dev, part); +		ext4fs_close(); +		goto fail; +	} + +	if (ext4fs_ls(filename)) { +		printf("** Error extfs_ls() **\n"); +		ext4fs_close(); +		goto fail; +	}; + +	ext4fs_close(); +	deinit_fs(fs->dev_desc); +	return 0; + +fail: +	deinit_fs(fs->dev_desc); +	return 1; +} diff --git a/common/cmd_fdt.c b/common/cmd_fdt.c index 9a5c53ec0..e2225c4d5 100644 --- a/common/cmd_fdt.c +++ b/common/cmd_fdt.c @@ -114,10 +114,21 @@ int do_fdt (cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  			}  		} +		return CMD_RET_SUCCESS; +	} + +	if (!working_fdt) { +		puts( +			"No FDT memory address configured. Please configure\n" +			"the FDT address via \"fdt addr <address>\" command.\n" +			"Aborting!\n"); +		return CMD_RET_FAILURE; +	} +  	/*  	 * Move the working_fdt  	 */ -	} else if (strncmp(argv[1], "mo", 2) == 0) { +	if (strncmp(argv[1], "mo", 2) == 0) {  		struct fdt_header *newaddr;  		int  len;  		int  err; diff --git a/common/cmd_flash.c b/common/cmd_flash.c index 0e9b2e3c7..e55d366c6 100644 --- a/common/cmd_flash.c +++ b/common/cmd_flash.c @@ -443,7 +443,8 @@ int flash_sect_erase (ulong addr_first, ulong addr_last)  				rcode = flash_erase (info, s_first[bank], s_last[bank]);  			}  		} -		printf ("Erased %d sectors\n", erased); +		if (rcode == 0) +			printf("Erased %d sectors\n", erased);  	} else if (rcode == 0) {  		puts ("Error: start and/or end address"  			" not on sector boundary\n"); diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c index 750509da5..79a1088f3 100644 --- a/common/cmd_mmc.c +++ b/common/cmd_mmc.c @@ -144,8 +144,7 @@ int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  U_BOOT_CMD(  	mmcinfo, 1, 0, do_mmcinfo,  	"display MMC info", -	"    - device number of the device to dislay info of\n" -	"" +	"- dislay info of the current MMC device"  );  int do_mmcops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) diff --git a/common/cmd_nand.c b/common/cmd_nand.c index a91ccf4df..e24ed7f9c 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -48,8 +48,8 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat)  	last = off; -	datbuf = malloc(nand->writesize); -	oobbuf = malloc(nand->oobsize); +	datbuf = memalign(ARCH_DMA_MINALIGN, nand->writesize); +	oobbuf = memalign(ARCH_DMA_MINALIGN, nand->oobsize);  	if (!datbuf || !oobbuf) {  		puts("No memory for page buffer\n");  		return 1; @@ -231,12 +231,18 @@ print:  #ifdef CONFIG_CMD_NAND_LOCK_UNLOCK  static void print_status(ulong start, ulong end, ulong erasesize, int status)  { +	/* +	 * Micron NAND flash (e.g. MT29F4G08ABADAH4) BLOCK LOCK READ STATUS is +	 * not the same as others.  Instead of bit 1 being lock, it is +	 * #lock_tight. To make the driver support either format, ignore bit 1 +	 * and use only bit 0 and bit 2. +	 */  	printf("%08lx - %08lx: %08lx blocks %s%s%s\n",  		start,  		end - 1,  		(end - start) / erasesize,  		((status & NAND_LOCK_STATUS_TIGHT) ?  "TIGHT " : ""), -		((status & NAND_LOCK_STATUS_LOCK) ?  "LOCK " : ""), +		(!(status & NAND_LOCK_STATUS_UNLOCK) ?  "LOCK " : ""),  		((status & NAND_LOCK_STATUS_UNLOCK) ?  "UNLOCK " : ""));  } @@ -749,11 +755,18 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])  		return 0;  	} -	if (strcmp(cmd, "unlock") == 0) { +	if (strncmp(cmd, "unlock", 5) == 0) { +		int allexcept = 0; + +		s = strchr(cmd, '.'); + +		if (s && !strcmp(s, ".allexcept")) +			allexcept = 1; +  		if (arg_off_size(argc - 2, argv + 2, &dev, &off, &size) < 0)  			return 1; -		if (!nand_unlock(&nand_info[dev], off, size)) { +		if (!nand_unlock(&nand_info[dev], off, size, allexcept)) {  			puts("NAND flash successfully unlocked\n");  		} else {  			puts("Error unlocking NAND flash, " @@ -807,7 +820,7 @@ U_BOOT_CMD(  	"\n"  	"nand lock [tight] [status]\n"  	"    bring nand to lock state or display locked pages\n" -	"nand unlock [offset] [size] - unlock section" +	"nand unlock[.allexcept] [offset] [size] - unlock section"  #endif  #ifdef CONFIG_ENV_OFFSET_OOB  	"\n" diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index fd05e725d..3474bc609 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -198,31 +198,20 @@ static int do_env_grep(cmd_tbl_t *cmdtp, int flag,  #endif  /* - * Set a new environment variable, - * or replace or delete an existing one. + * Perform consistency checking before setting, replacing, or deleting an + * environment variable, then (if successful) apply the changes to internals so + * to make them effective.  Code for this function was taken out of + * _do_env_set(), which now calls it instead. + * Also called as a callback function by himport_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 _do_env_set(int flag, int argc, char * const argv[]) + +int env_check_apply(const char *name, const char *oldval, +			const char *newval, int flag)  { -	int   i, len;  	int   console = -1; -	char  *name, *value, *s; -	ENTRY e, *ep; - -	name = argv[1]; - -	if (strchr(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; -	hsearch_r(e, FIND, &ep, &env_htab);  	/* Check for console redirection */  	if (strcmp(name, "stdin") == 0) @@ -233,60 +222,75 @@ int _do_env_set(int flag, int argc, char * const argv[])  		console = stderr;  	if (console != -1) { -		if (argc < 3) {		/* Cannot delete it! */ -			printf("Can't delete \"%s\"\n", name); +		if ((newval == NULL) || (*newval == '\0')) { +			/* We cannot delete stdin/stdout/stderr */ +			if ((flag & H_FORCE) == 0) +				printf("Can't delete \"%s\"\n", name);  			return 1;  		}  #ifdef CONFIG_CONSOLE_MUX -		i = iomux_doenv(console, argv[2]); -		if (i) -			return i; +		if (iomux_doenv(console, newval)) +			return 1;  #else  		/* Try assigning specified device */ -		if (console_assign(console, argv[2]) < 0) +		if (console_assign(console, newval) < 0)  			return 1;  #ifdef CONFIG_SERIAL_MULTI -		if (serial_assign(argv[2]) < 0) +		if (serial_assign(newval) < 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. +	 * Some variables like "ethaddr" and "serial#" can be set only once and +	 * cannot be deleted, unless CONFIG_ENV_OVERWRITE is defined.  	 */ -	if (ep) {		/* variable exists */  #ifndef CONFIG_ENV_OVERWRITE +	if (oldval != NULL &&			/* variable exists */ +		(flag & H_FORCE) == 0) {	/* and we are not forced */  		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 +		     && strcmp(oldval, MK_STR(CONFIG_ETHADDR)) != 0  #endif	/* CONFIG_OVERWRITE_ETHADDR_ONCE && CONFIG_ETHADDR */  			)) {  			printf("Can't overwrite \"%s\"\n", name);  			return 1;  		} +	}  #endif +	/* +	 * When we change baudrate, or we are doing an env default -a +	 * (which will erase all variables prior to calling this), +	 * we want the baudrate to actually change - for real. +	 */ +	if (oldval != NULL ||			/* variable exists */ +		(flag & H_NOCLEAR) == 0) {	/* or env is clear */  		/*  		 * Switch to new baudrate if new baudrate is supported  		 */  		if (strcmp(name, "baudrate") == 0) { -			int baudrate = simple_strtoul(argv[2], NULL, 10); +			int baudrate = simple_strtoul(newval, 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); +				if ((flag & H_FORCE) == 0) +					printf("## Baudrate %d bps not " +						"supported\n", baudrate);  				return 1;  			} +			if (gd->baudrate == baudrate) { +				/* If unchanged, we just say it's OK */ +				return 0; +			}  			printf("## Switch baudrate to %d bps and" -			       "press ENTER ...\n", baudrate); +				"press ENTER ...\n", baudrate);  			udelay(50000);  			gd->baudrate = baudrate;  #if defined(CONFIG_PPC) || defined(CONFIG_MCF52x2) @@ -300,9 +304,62 @@ int _do_env_set(int flag, int argc, char * const argv[])  		}  	} +	/* +	 * Some variables should be updated when the corresponding +	 * entry in the environment is changed +	 */ +	if (strcmp(name, "loadaddr") == 0) { +		load_addr = simple_strtoul(newval, NULL, 16); +		return 0; +	} +#if defined(CONFIG_CMD_NET) +	else if (strcmp(name, "bootfile") == 0) { +		copy_filename(BootFile, newval, sizeof(BootFile)); +		return 0; +	} +#endif +	return 0; +} + +/* + * Set a new environment variable, + * or replace or delete an existing one. +*/ +int _do_env_set(int flag, int argc, char * const argv[]) +{ +	int   i, len; +	char  *name, *value, *s; +	ENTRY e, *ep; + +	name = argv[1]; +	value = argv[2]; + +	if (strchr(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; +	hsearch_r(e, FIND, &ep, &env_htab); + +	/* +	 * Perform requested checks. Notice how since we are overwriting +	 * a single variable, we need to set H_NOCLEAR +	 */ +	if (env_check_apply(name, ep ? ep->data : NULL, value, H_NOCLEAR)) { +		debug("check function did not approve, refusing\n"); +		return 1; +	} +  	/* Delete only ? */  	if (argc < 3 || argv[2] == NULL) { -		int rc = hdelete_r(name, &env_htab); +		int rc = hdelete_r(name, &env_htab, 0);  		return !rc;  	} @@ -337,20 +394,6 @@ 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(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;  } @@ -613,14 +656,41 @@ int envmatch(uchar *s1, int i2)  	return -1;  } -static int do_env_default(cmd_tbl_t *cmdtp, int flag, +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_RET_USAGE; +	int all = 0, flag = 0; -	set_default_env("## Resetting to default environment\n"); -	return 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); +			} +		} +	} +	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, @@ -872,7 +942,8 @@ static int do_env_import(cmd_tbl_t *cmdtp, int flag,  		addr = (char *)ep->data;  	} -	if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR) == 0) { +	if (himport_r(&env_htab, addr, size, sep, del ? 0 : H_NOCLEAR, +			0, NULL, 0 /* do_apply */) == 0) {  		error("Environment import failed: errno = %d\n", errno);  		return 1;  	} @@ -950,15 +1021,20 @@ U_BOOT_CMD(  #if defined(CONFIG_CMD_ASKENV)  	"ask name [message] [size] - ask for environment variable\nenv "  #endif -	"default -f - reset default environment\n" +	"default [-f] -a - [forcibly] reset default environment\n" +	"env default [-f] var [...] - [forcibly] reset variable(s) to their default values\n"  #if defined(CONFIG_CMD_EDITENV)  	"env edit name - edit environment variable\n"  #endif +#if defined(CONFIG_CMD_EXPORTENV)  	"env export [-t | -b | -c] [-s size] addr [var ...] - export environment\n" +#endif  #if defined(CONFIG_CMD_GREPENV)  	"env grep string [...] - search environment\n"  #endif +#if defined(CONFIG_CMD_IMPORTENV)  	"env import [-d] [-t | -b | -c] addr [size] - import environment\n" +#endif  	"env print [name ...] - print environment\n"  #if defined(CONFIG_CMD_RUN)  	"env run var [...] - run commands in an environment variable\n" diff --git a/common/cmd_spi.c b/common/cmd_spi.c index 8c623c9fc..eba5fb83d 100644 --- a/common/cmd_spi.c +++ b/common/cmd_spi.c @@ -89,7 +89,7 @@ int do_spi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])  				cs = bus;  				bus = CONFIG_DEFAULT_SPI_BUS;  			} -			if (*cp == '.'); +			if (*cp == '.')  				mode = simple_strtoul(cp+1, NULL, 10);  		}  		if (argc >= 3) diff --git a/common/dlmalloc.c b/common/dlmalloc.c index c645d7314..1d7e527b9 100644 --- a/common/dlmalloc.c +++ b/common/dlmalloc.c @@ -1487,11 +1487,11 @@ static mbinptr av_[NAV * 2 + 2] = {  #ifdef CONFIG_NEEDS_MANUAL_RELOC  void malloc_bin_reloc (void)  { -	unsigned long *p = (unsigned long *)(&av_[2]); -	int i; -	for (i=2; i<(sizeof(av_)/sizeof(mbinptr)); ++i) { -		*p++ += gd->reloc_off; -	} +	mbinptr *p = &av_[2]; +	size_t i; + +	for (i = 2; i < ARRAY_SIZE(av_); ++i, ++p) +		*p = (mbinptr)((ulong)*p + gd->reloc_off);  }  #endif diff --git a/common/env_common.c b/common/env_common.c index d9e990dbb..3e46c260d 100644 --- a/common/env_common.c +++ b/common/env_common.c @@ -80,6 +80,9 @@ const uchar default_environment[] = {  #ifdef	CONFIG_ETH5ADDR  	"eth5addr="	MK_STR(CONFIG_ETH5ADDR)		"\0"  #endif +#ifdef	CONFIG_ETHPRIME +	"ethprime="	CONFIG_ETHPRIME			"\0" +#endif  #ifdef	CONFIG_IPADDR  	"ipaddr="	MK_STR(CONFIG_IPADDR)		"\0"  #endif @@ -133,7 +136,9 @@ const uchar default_environment[] = {  	"\0"  }; -struct hsearch_data env_htab; +struct hsearch_data env_htab = { +	.apply = env_check_apply, +};  static uchar __env_get_char_spec(int index)  { @@ -175,6 +180,11 @@ const uchar *env_get_addr(int index)  void set_default_env(const char *s)  { +	/* +	 * By default, do not apply changes as they will eventually +	 * be applied by someone else +	 */ +	int do_apply = 0;  	if (sizeof(default_environment) > ENV_SIZE) {  		puts("*** Error - default environment is too large\n\n");  		return; @@ -186,6 +196,14 @@ void set_default_env(const char *s)  				"using default environment\n\n",  				s + 1);  		} else { +			/* +			 * This set_to_default was explicitly asked for +			 * by the user, as opposed to being a recovery +			 * mechanism.  Therefore we check every single +			 * variable and apply changes to the system +			 * right away (e.g. baudrate, console). +			 */ +			do_apply = 1;  			puts(s);  		}  	} else { @@ -193,12 +211,26 @@ void set_default_env(const char *s)  	}  	if (himport_r(&env_htab, (char *)default_environment, -			sizeof(default_environment), '\0', 0) == 0) +			sizeof(default_environment), '\0', 0, +			0, NULL, do_apply) == 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, +				nvars, vars, 1 /* do_apply */); +} +  /*   * Check if CRC is valid and (if yes) import the environment.   * Note that "buf" may or may not be aligned. @@ -218,7 +250,8 @@ int env_import(const char *buf, int check)  		}  	} -	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0)) { +	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, +			0, NULL, 0 /* do_apply */)) {  		gd->flags |= GD_FLG_ENV_READY;  		return 1;  	} diff --git a/common/env_mmc.c b/common/env_mmc.c index be2f2be20..a2ff90bf4 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -75,9 +75,28 @@ static int init_mmc_for_env(struct mmc *mmc)  		return -1;  	} +#ifdef CONFIG_SYS_MMC_ENV_PART +	if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) { +		if (mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, +				    CONFIG_SYS_MMC_ENV_PART)) { +			puts("MMC partition switch failed\n"); +			return -1; +		} +	} +#endif +  	return 0;  } +static void fini_mmc_for_env(struct mmc *mmc) +{ +#ifdef CONFIG_SYS_MMC_ENV_PART +	if (CONFIG_SYS_MMC_ENV_PART != mmc->part_num) +		mmc_switch_part(CONFIG_SYS_MMC_ENV_DEV, +				mmc->part_num); +#endif +} +  #ifdef CONFIG_CMD_SAVEENV  static inline int write_env(struct mmc *mmc, unsigned long size,  			    unsigned long offset, const void *buffer) @@ -100,26 +119,38 @@ int saveenv(void)  	char	*res;  	struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);  	u32	offset; +	int	ret; -	if (init_mmc_for_env(mmc) || mmc_get_env_addr(mmc, &offset)) +	if (init_mmc_for_env(mmc))  		return 1; +	if (mmc_get_env_addr(mmc, &offset)) { +		ret = 1; +		goto fini; +	} +  	res = (char *)&env_new->data;  	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno); -		return 1; +		ret = 1; +		goto fini;  	}  	env_new->crc = crc32(0, &env_new->data[0], ENV_SIZE);  	printf("Writing to MMC(%d)... ", CONFIG_SYS_MMC_ENV_DEV);  	if (write_env(mmc, CONFIG_ENV_SIZE, offset, (u_char *)env_new)) {  		puts("failed\n"); -		return 1; +		ret = 1; +		goto fini;  	}  	puts("done\n"); -	return 0; +	ret = 0; + +fini: +	fini_mmc_for_env(mmc); +	return ret;  }  #endif /* CONFIG_CMD_SAVEENV */ @@ -143,13 +174,30 @@ void env_relocate_spec(void)  	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);  	struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);  	u32 offset; +	int ret; -	if (init_mmc_for_env(mmc) || mmc_get_env_addr(mmc, &offset)) -		return set_default_env(NULL); +	if (init_mmc_for_env(mmc)) { +		ret = 1; +		goto err; +	} -	if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) -		return set_default_env(NULL); +	if (mmc_get_env_addr(mmc, &offset)) { +		ret = 1; +		goto fini; +	} + +	if (read_env(mmc, CONFIG_ENV_SIZE, offset, buf)) { +		ret = 1; +		goto fini; +	}  	env_import(buf, 1); +	ret = 0; + +fini: +	fini_mmc_for_env(mmc); +err: +	if (ret) +		set_default_env(NULL);  #endif  } diff --git a/common/env_nand.c b/common/env_nand.c index e8daec971..79e803370 100644 --- a/common/env_nand.c +++ b/common/env_nand.c @@ -226,7 +226,7 @@ int saveenv(void)  int saveenv(void)  {  	int	ret = 0; -	env_t	env_new; +	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);  	ssize_t	len;  	char	*res;  	nand_erase_options_t nand_erase_options; @@ -238,20 +238,20 @@ int saveenv(void)  	if (CONFIG_ENV_RANGE < CONFIG_ENV_SIZE)  		return 1; -	res = (char *)&env_new.data; +	res = (char *)&env_new->data;  	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE, 0, NULL);  	if (len < 0) {  		error("Cannot export environment: errno = %d\n", errno);  		return 1;  	} -	env_new.crc = crc32(0, env_new.data, ENV_SIZE); +	env_new->crc = crc32(0, env_new->data, ENV_SIZE);  	puts("Erasing Nand...\n");  	if (nand_erase_opts(&nand_info[0], &nand_erase_options))  		return 1;  	puts("Writing to Nand... "); -	if (writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new)) { +	if (writeenv(CONFIG_ENV_OFFSET, (u_char *)env_new)) {  		puts("FAILED!\n");  		return 1;  	} @@ -398,7 +398,7 @@ void env_relocate_spec(void)  {  #if !defined(ENV_IS_EMBEDDED)  	int ret; -	char buf[CONFIG_ENV_SIZE]; +	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);  #if defined(CONFIG_ENV_OFFSET_OOB)  	ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset); diff --git a/common/flash.c b/common/flash.c index 781cb9c4a..8244ba2dd 100644 --- a/common/flash.c +++ b/common/flash.c @@ -221,6 +221,9 @@ void flash_perror (int err)  	case ERR_PROG_ERROR:  		puts ("General Flash Programming Error\n");  		break; +	case ERR_ABORTED: +		puts("Flash Programming Aborted\n"); +		break;  	default:  		printf ("%s[%d] FIXME: rc=%d\n", __FILE__, __LINE__, err);  		break; diff --git a/common/hush.c b/common/hush.c index 1eff182ef..4c84c2f50 100644 --- a/common/hush.c +++ b/common/hush.c @@ -127,6 +127,7 @@  #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 */ @@ -499,6 +500,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 *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 @@ -2743,13 +2745,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;  } @@ -3051,6 +3090,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; @@ -3092,6 +3146,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 @@ -3431,25 +3489,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; @@ -3513,9 +3603,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, " "); diff --git a/common/image.c b/common/image.c index 0c601bbc4..f084d2bae 100644 --- a/common/image.c +++ b/common/image.c @@ -2043,13 +2043,13 @@ void fit_image_print(const void *fit, int image_noffset, const char *p)  		printf("%s  Architecture: %s\n", p, genimg_get_arch_name(arch));  	} -	if (type == IH_TYPE_KERNEL) { +	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_RAMDISK)) {  		fit_image_get_os(fit, image_noffset, &os);  		printf("%s  OS:           %s\n", p, genimg_get_os_name(os));  	}  	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) || -		(type == IH_TYPE_FIRMWARE)) { +		(type == IH_TYPE_FIRMWARE) || (type == IH_TYPE_RAMDISK)) {  		ret = fit_image_get_load(fit, image_noffset, &load);  		printf("%s  Load Address: ", p);  		if (ret) @@ -2058,7 +2058,8 @@ void fit_image_print(const void *fit, int image_noffset, const char *p)  			printf("0x%08lx\n", load);  	} -	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE)) { +	if ((type == IH_TYPE_KERNEL) || (type == IH_TYPE_STANDALONE) || +		(type == IH_TYPE_RAMDISK)) {  		fit_image_get_entry(fit, image_noffset, &entry);  		printf("%s  Entry Point:  ", p);  		if (ret) diff --git a/common/usb_hub.c b/common/usb_hub.c index f35ad9532..32750e8d0 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -43,6 +43,7 @@  #include <common.h>  #include <command.h>  #include <asm/processor.h> +#include <asm/unaligned.h>  #include <linux/ctype.h>  #include <asm/byteorder.h>  #include <asm/unaligned.h> @@ -269,6 +270,7 @@ static int usb_hub_configure(struct usb_device *dev)  	int i;  	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, USB_BUFSIZ);  	unsigned char *bitmap; +	short hubCharacteristics;  	struct usb_hub_descriptor *descriptor;  	struct usb_hub_device *hub;  #ifdef USB_HUB_DEBUG @@ -304,8 +306,9 @@ static int usb_hub_configure(struct usb_device *dev)  	}  	memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength);  	/* adjust 16bit values */ -	hub->desc.wHubCharacteristics = -				le16_to_cpu(descriptor->wHubCharacteristics); +	put_unaligned(le16_to_cpu(get_unaligned( +			&descriptor->wHubCharacteristics)), +			&hub->desc.wHubCharacteristics);  	/* set the bitmap */  	bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0];  	/* devices not removable by default */ @@ -322,7 +325,8 @@ static int usb_hub_configure(struct usb_device *dev)  	dev->maxchild = descriptor->bNbrPorts;  	USB_HUB_PRINTF("%d ports detected\n", dev->maxchild); -	switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) { +	hubCharacteristics = get_unaligned(&hub->desc.wHubCharacteristics); +	switch (hubCharacteristics & HUB_CHAR_LPSM) {  	case 0x00:  		USB_HUB_PRINTF("ganged power switching\n");  		break; @@ -335,12 +339,12 @@ static int usb_hub_configure(struct usb_device *dev)  		break;  	} -	if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND) +	if (hubCharacteristics & HUB_CHAR_COMPOUND)  		USB_HUB_PRINTF("part of a compound device\n");  	else  		USB_HUB_PRINTF("standalone hub\n"); -	switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) { +	switch (hubCharacteristics & HUB_CHAR_OCPM) {  	case 0x00:  		USB_HUB_PRINTF("global over-current protection\n");  		break; diff --git a/common/usb_storage.c b/common/usb_storage.c index bdc306f58..4aeed827c 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -136,6 +136,7 @@ struct us_data {  	struct usb_device *pusb_dev;	 /* this usb_device */  	unsigned int	flags;			/* from filter initially */ +#	define USB_READY	(1 << 0)  	unsigned char	ifnum;			/* interface number */  	unsigned char	ep_in;			/* in endpoint */  	unsigned char	ep_out;			/* out ....... */ @@ -155,11 +156,16 @@ struct us_data {  	trans_cmnd	transport;		/* transport routine */  }; +#ifdef CONFIG_USB_EHCI  /* - * The U-Boot EHCI driver cannot handle more than 5 page aligned buffers - * of 4096 bytes in a transfer without running itself out of qt_buffers + * The U-Boot EHCI driver can handle any transfer length as long as there is + * enough free heap space left, but the SCSI READ(10) and WRITE(10) commands are + * limited to 65535 blocks.   */ -#define USB_MAX_XFER_BLK(start, blksz)	(((4096 * 5) - (start % 4096)) / blksz) +#define USB_MAX_XFER_BLK	65535 +#else +#define USB_MAX_XFER_BLK	20 +#endif  static struct us_data usb_stor[USB_MAX_STOR_DEV]; @@ -693,7 +699,8 @@ int usb_stor_BBB_transport(ccb *srb, struct us_data *us)  		usb_stor_BBB_reset(us);  		return USB_STOR_TRANSPORT_FAILED;  	} -	mdelay(5); +	if (!(us->flags & USB_READY)) +		mdelay(5);  	pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);  	pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out);  	/* DATA phase + error handling */ @@ -958,8 +965,10 @@ static int usb_test_unit_ready(ccb *srb, struct us_data *ss)  		srb->cmd[1] = srb->lun << 5;  		srb->datalen = 0;  		srb->cmdlen = 12; -		if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) +		if (ss->transport(srb, ss) == USB_STOR_TRANSPORT_GOOD) { +			ss->flags |= USB_READY;  			return 0; +		}  		usb_request_sense(srb, ss);  		mdelay(100);  	} while (retries--); @@ -1046,7 +1055,7 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor,  unsigned long usb_stor_read(int device, unsigned long blknr,  			    unsigned long blkcnt, void *buffer)  { -	unsigned long start, blks, buf_addr, max_xfer_blk; +	unsigned long start, blks, buf_addr;  	unsigned short smallblks;  	struct usb_device *dev;  	struct us_data *ss; @@ -1074,12 +1083,6 @@ unsigned long usb_stor_read(int device, unsigned long blknr,  	buf_addr = (unsigned long)buffer;  	start = blknr;  	blks = blkcnt; -	if (usb_test_unit_ready(srb, ss)) { -		printf("Device NOT ready\n   Request Sense returned %02X %02X" -		       " %02X\n", srb->sense_buf[2], srb->sense_buf[12], -		       srb->sense_buf[13]); -		return 0; -	}  	USB_STOR_PRINTF("\nusb_read: dev %d startblk %lx, blccnt %lx"  			" buffer %lx\n", device, start, blks, buf_addr); @@ -1088,14 +1091,12 @@ unsigned long usb_stor_read(int device, unsigned long blknr,  		/* XXX need some comment here */  		retry = 2;  		srb->pdata = (unsigned char *)buf_addr; -		max_xfer_blk = USB_MAX_XFER_BLK(buf_addr, -						usb_dev_desc[device].blksz); -		if (blks > max_xfer_blk) -			smallblks = (unsigned short) max_xfer_blk; +		if (blks > USB_MAX_XFER_BLK) +			smallblks = USB_MAX_XFER_BLK;  		else  			smallblks = (unsigned short) blks;  retry_it: -		if (smallblks == max_xfer_blk) +		if (smallblks == USB_MAX_XFER_BLK)  			usb_show_progress();  		srb->datalen = usb_dev_desc[device].blksz * smallblks;  		srb->pdata = (unsigned char *)buf_addr; @@ -1111,12 +1112,13 @@ retry_it:  		blks -= smallblks;  		buf_addr += srb->datalen;  	} while (blks != 0); +	ss->flags &= ~USB_READY;  	USB_STOR_PRINTF("usb_read: end startblk %lx, blccnt %x buffer %lx\n",  			start, smallblks, buf_addr);  	usb_disable_asynch(0); /* asynch transfer allowed */ -	if (blkcnt >= max_xfer_blk) +	if (blkcnt >= USB_MAX_XFER_BLK)  		debug("\n");  	return blkcnt;  } @@ -1124,7 +1126,7 @@ retry_it:  unsigned long usb_stor_write(int device, unsigned long blknr,  				unsigned long blkcnt, const void *buffer)  { -	unsigned long start, blks, buf_addr, max_xfer_blk; +	unsigned long start, blks, buf_addr;  	unsigned short smallblks;  	struct usb_device *dev;  	struct us_data *ss; @@ -1153,12 +1155,6 @@ unsigned long usb_stor_write(int device, unsigned long blknr,  	buf_addr = (unsigned long)buffer;  	start = blknr;  	blks = blkcnt; -	if (usb_test_unit_ready(srb, ss)) { -		printf("Device NOT ready\n   Request Sense returned %02X %02X" -		       " %02X\n", srb->sense_buf[2], srb->sense_buf[12], -			srb->sense_buf[13]); -		return 0; -	}  	USB_STOR_PRINTF("\nusb_write: dev %d startblk %lx, blccnt %lx"  			" buffer %lx\n", device, start, blks, buf_addr); @@ -1169,14 +1165,12 @@ unsigned long usb_stor_write(int device, unsigned long blknr,  		 */  		retry = 2;  		srb->pdata = (unsigned char *)buf_addr; -		max_xfer_blk = USB_MAX_XFER_BLK(buf_addr, -						usb_dev_desc[device].blksz); -		if (blks > max_xfer_blk) -			smallblks = (unsigned short) max_xfer_blk; +		if (blks > USB_MAX_XFER_BLK) +			smallblks = USB_MAX_XFER_BLK;  		else  			smallblks = (unsigned short) blks;  retry_it: -		if (smallblks == max_xfer_blk) +		if (smallblks == USB_MAX_XFER_BLK)  			usb_show_progress();  		srb->datalen = usb_dev_desc[device].blksz * smallblks;  		srb->pdata = (unsigned char *)buf_addr; @@ -1192,12 +1186,13 @@ retry_it:  		blks -= smallblks;  		buf_addr += srb->datalen;  	} while (blks != 0); +	ss->flags &= ~USB_READY;  	USB_STOR_PRINTF("usb_write: end startblk %lx, blccnt %x buffer %lx\n",  			start, smallblks, buf_addr);  	usb_disable_asynch(0); /* asynch transfer allowed */ -	if (blkcnt >= max_xfer_blk) +	if (blkcnt >= USB_MAX_XFER_BLK)  		debug("\n");  	return blkcnt; @@ -1403,6 +1398,7 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *ss,  		cap[0] = 2880;  		cap[1] = 0x200;  	} +	ss->flags &= ~USB_READY;  	USB_STOR_PRINTF("Read Capacity returns: 0x%lx, 0x%lx\n", cap[0],  			cap[1]);  #if 0 |