Beispiel #1
0
static int arg_off_size(int argc, char *argv[], nand_info_t *nand, uint64_t *off, uint64_t *size)
{
	int idx = nand_curr_device;
#if defined(CONFIG_CMD_MTDPARTS)
	struct mtd_device *dev;
	struct part_info *part;
	u8 pnum;

	if (argc >= 1 && !(str2longlong(argv[0], off))) {
		if ((mtdparts_init() == 0) &&
		    (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) {
			if (dev->id->type != MTD_DEV_TYPE_NAND) {
				puts("not a NAND device\n");
				return -1;
			}
			*off = part->offset;
			if (argc >= 2) {
				if (!(str2longlong(argv[1], size))) {
					printf("'%s' is not a number\n", argv[1]);
					return -1;
				}
				if (*size > part->size)
					*size = part->size;
			} else {
				*size = part->size;
			}
			idx = dev->id->num;
			*nand = nand_info[idx];
			goto out;
		}
	}
#endif
	if (argc >= 1) {
		if (!(str2longlong(argv[0], off))) {
			printf("'%s' is not a number\n", argv[0]);
			return -1;
		}
	} else {
		*off = 0;
	}

	if (argc >= 2) {
		if (!(str2longlong(argv[1], size))) {
			printf("'%s' is not a number\n", argv[1]);
			return -1;
		}
	} else {
		*size = nand->size - *off;
	}

#if defined(CONFIG_CMD_MTDPARTS)
out:
#endif
	printf("device %d ", idx);
	if (*size == nand->size)
		printf("whole chip [0x%llx]\n",nand->size);
	else
		printf("offset 0x%llx, size 0x%llx\n", *off, *size);
	return 0;
}
Beispiel #2
0
static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size)
{
#ifdef CONFIG_CMD_MTDPARTS
	struct mtd_device *dev;
	struct part_info *part;
	u8 pnum;
	int ret;

	ret = mtdparts_init();
	if (ret)
		return ret;

	ret = find_dev_and_part(partname, &dev, &pnum, &part);
	if (ret)
		return ret;

	if (dev->id->type != MTD_DEV_TYPE_NAND) {
		puts("not a NAND device\n");
		return -1;
	}

	*off = part->offset;
	*size = part->size;
	*idx = dev->id->num;

	ret = set_dev(*idx);
	if (ret)
		return ret;

	return 0;
#else
	puts("offset is not a number\n");
	return -1;
#endif
}
Beispiel #3
0
static int get_part(const char *partname, int *idx, loff_t *off, loff_t *size,
		loff_t *maxsize, int devtype)
{
#ifdef CONFIG_CMD_MTDPARTS
	struct mtd_device *dev;
	struct part_info *part;
	u8 pnum;
	int ret;

	ret = mtdparts_init();
	if (ret)
		return ret;

	ret = find_dev_and_part(partname, &dev, &pnum, &part);
	if (ret)
		return ret;

	if (dev->id->type != devtype) {
		printf("not same typ %d != %d\n", dev->id->type, devtype);
		return -1;
	}

	*off = part->offset;
	*size = part->size;
	*maxsize = part->size;
	*idx = dev->id->num;

	return 0;
#else
	puts("mtdparts support missing.\n");
	return -1;
#endif
}
Beispiel #4
0
static int fb_nand_lookup(const char *partname,
			  struct mtd_info **mtd,
			  struct part_info **part)
{
	struct mtd_device *dev;
	int ret;
	u8 pnum;

	ret = mtdparts_init();
	if (ret) {
		error("Cannot initialize MTD partitions\n");
		fastboot_fail("cannot init mtdparts");
		return ret;
	}

	ret = find_dev_and_part(partname, &dev, &pnum, part);
	if (ret) {
		error("cannot find partition: '%s'", partname);
		fastboot_fail("cannot find partition");
		return ret;
	}

	if (dev->id->type != MTD_DEV_TYPE_NAND) {
		error("partition '%s' is not stored on a NAND device",
		      partname);
		fastboot_fail("not a NAND device");
		return -EINVAL;
	}

	*mtd = get_nand_dev_by_index(dev->id->num);

	return 0;
}
Beispiel #5
0
static int arg_off_size_nor(int argc, char * const argv[], unsigned int *off, unsigned int *size)
{
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
	struct mtd_device *dev;
	struct part_info *part;
	u8 pnum;

	if (argc >= 1 && !(str2long_nor(argv[0], off))) {
		if ((mtdparts_init() == 0) &&
		    (find_dev_and_part(argv[0], &dev, &pnum, &part) == 0)) {
			if (dev->id->type != MTD_DEV_TYPE_NOR) {
				puts("not a NOR device\n");
				return -1;
			}
			*off = part->offset;
			if (argc >= 2) {
				if (!(str2long_nor(argv[1], size))) {
					printf("'%s' is not a number\n", argv[1]);
					return -1;
				}
			} else {
				*size = part->size;
			}

			goto out;
		}
	}
#endif

	if (argc >= 1) {
		if (!(str2long_nor(argv[0], off))) {
			printf("'%s' is not a number\n", argv[0]);
			return -1;
		}
	} else {
		*off = 0;
	}

	if (argc >= 2) {
		if (!(str2long_nor(argv[1], size))) {
			printf("'%s' is not a number\n", argv[1]);
			return -1;
		}
	} else {
	       pFlashInfo = MDrv_SERFLASH_GetInfo();
		*size = pFlashInfo->u32TotalSize - *off;
	}

#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
out:
#endif

	printf("offset 0x%x, size 0x%x\n", *off, *size);
	return 0;
}
Beispiel #6
0
int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
{
	char *st;
	int ret, dev, part;

	dfu->data.nand.ubi = 0;
	dfu->dev_type = DFU_DEV_NAND;
	st = strsep(&s, " ");
	if (!strcmp(st, "raw")) {
		dfu->layout = DFU_RAW_ADDR;
		dfu->data.nand.start = simple_strtoul(s, &s, 16);
		s++;
		dfu->data.nand.size = simple_strtoul(s, &s, 16);
	} else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) {
		char mtd_id[32];
		struct mtd_device *mtd_dev;
		u8 part_num;
		struct part_info *pi;

		dfu->layout = DFU_RAW_ADDR;

		dev = simple_strtoul(s, &s, 10);
		s++;
		part = simple_strtoul(s, &s, 10);

		sprintf(mtd_id, "%s%d,%d", "nand", dev, part - 1);
		printf("using id '%s'\n", mtd_id);

		mtdparts_init();

		ret = find_dev_and_part(mtd_id, &mtd_dev, &part_num, &pi);
		if (ret != 0) {
			printf("Could not locate '%s'\n", mtd_id);
			return -1;
		}

		dfu->data.nand.start = pi->offset;
		dfu->data.nand.size = pi->size;
		if (!strcmp(st, "partubi"))
			dfu->data.nand.ubi = 1;
	} else {
		printf("%s: Memory layout (%s) not supported!\n", __func__, st);
		return -1;
	}

	dfu->read_medium = dfu_read_medium_nand;
	dfu->write_medium = dfu_write_medium_nand;
	dfu->flush_medium = dfu_flush_medium_nand;

	/* initial state */
	dfu->inited = 0;

	return 0;
}
Beispiel #7
0
static int ubi_dev_scan(struct mtd_info *info, char *ubidev,
		const char *vid_header_offset)
{
	struct mtd_device *dev;
	struct part_info *part;
	struct mtd_partition mtd_part;
	char ubi_mtd_param_buffer[80];
	u8 pnum;
	int err;

	if (find_dev_and_part(ubidev, &dev, &pnum, &part) != 0)
		return 1;

	sprintf(buffer, "mtd=%d", pnum);
	memset(&mtd_part, 0, sizeof(mtd_part));
	mtd_part.name = buffer;
	mtd_part.size = part->size;
	mtd_part.offset = part->offset;
	add_mtd_partitions(info, &mtd_part, 1);

	strcpy(ubi_mtd_param_buffer, buffer);
	if (vid_header_offset)
		sprintf(ubi_mtd_param_buffer, "mtd=%d,%s", pnum,
				vid_header_offset);
	err = ubi_mtd_param_parse(ubi_mtd_param_buffer, NULL);
	if (err) {
		del_mtd_partitions(info);
		return -err;
	}

	err = ubi_init();
	if (err) {
		del_mtd_partitions(info);
		return -err;
	}

	ubi_initialized = 1;

	return 0;
}
Beispiel #8
0
static int ubi_dev_scan(struct mtd_info *info, char *ubidev)
{
	struct mtd_device *dev;
	struct part_info *part;
	struct mtd_partition mtd_part;
	u8 pnum;
	int err;

	if (mtdparts_init() != 0)
		return 1;

	if (find_dev_and_part(ubidev, &dev, &pnum, &part) != 0)
		return 1;

	sprintf(buffer, "mtd=%d", pnum);
	memset(&mtd_part, 0, sizeof(mtd_part));
	mtd_part.name = buffer;
	mtd_part.size = part->size;
	mtd_part.offset = part->offset;
	add_mtd_partitions(info, &mtd_part, 1);

	err = ubi_mtd_param_parse(buffer, NULL);
	if (err) {
		del_mtd_partitions(info);
		return err;
	}

	err = ubi_init();
	if (err) {
		del_mtd_partitions(info);
		return err;
	}

	ubi_initialized = 1;

	return 0;
}
int do_flerase(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {
	flash_info_t *info;
	ulong bank, addr_first, addr_last;
	int n, sect_first, sect_last;
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
	struct mtd_device *dev;
	struct part_info *part;
	u8 dev_type, dev_num, pnum;
#endif
	int rcode = 0;

	if (argc < 2) {
#ifdef  CFG_LONGHELP
		if(cmdtp->help != NULL) {
			printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
		} else {
			printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
		}
#else
		printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
#endif
		return 1;
	}

	// erase whole flash?
	if (strcmp(argv[1], "all") == 0) {
		for (bank = 1; bank <= CFG_MAX_FLASH_BANKS; ++bank) {
			printf("Erase flash bank #%ld ", bank);
			info = &flash_info[bank - 1];
			rcode = flash_erase(info, 0, info->sector_count - 1);
		}
		return rcode;
	}

	if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
		if (n < 0) {
			puts("## Error: bad sector spec\n");
			return 1;
		}
		printf("Erase flash sectors %d-%d in bank #%d ", sect_first, sect_last, (info - flash_info) + 1);
		rcode = flash_erase(info, sect_first, sect_last);
		return rcode;
	}

#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
	/* erase <part-id> - erase partition */
	if ((argc == 2) && (id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
		mtdparts_init();
		if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
			if (dev->id->type == MTD_DEV_TYPE_NOR) {
				bank = dev->id->num;
				info = &flash_info[bank];
				addr_first = part->offset + info->start[0];
				addr_last = addr_first + part->size - 1;

				printf("Erase flash parition %s, bank %d, 0x%08lx - 0x%08lx ", argv[1], bank, addr_first, addr_last);

				rcode = flash_sect_erase(addr_first, addr_last);
				return rcode;
			}

			printf("## Error: cannot erase, not a NOR device\n");
			return 1;
		}
	}
#endif

	if (argc != 3) {
#ifdef  CFG_LONGHELP
		if(cmdtp->help != NULL) {
			printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
		} else {
			printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
		}
#else
		printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
#endif
		return 1;
	}

	if (strcmp(argv[1], "bank") == 0) {
		bank = simple_strtoul(argv[2], NULL, 16);
		if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
			printf("## Error: only flash banks #1...#%d supported\n", CFG_MAX_FLASH_BANKS);
			return 1;
		}
		printf("Erase flash bank #%ld ", bank);
		info = &flash_info[bank - 1];
		rcode = flash_erase(info, 0, info->sector_count - 1);
		return rcode;
	}

	if (addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0) {
		printf("## Error: bad address format\n");
		return 1;
	}

	if (addr_first >= addr_last) {
#ifdef  CFG_LONGHELP
		if(cmdtp->help != NULL) {
			printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
		} else {
			printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
		}
#else
		printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
#endif
		return 1;
	}

	rcode = flash_sect_erase(addr_first, addr_last);
	return rcode;
}
Beispiel #10
0
static int do_ubi(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
	size_t size = 0;
	ulong addr = 0;
	int err = 0;

	if (argc < 2)
		return CMD_RET_USAGE;

	if (mtdparts_init() != 0) {
		printf("Error initializing mtdparts!\n");
		return 1;
	}

	if (strcmp(argv[1], "part") == 0) {
		char mtd_dev[16];
		struct mtd_device *dev;
		struct part_info *part;
		const char *vid_header_offset = NULL;
		u8 pnum;

		/* Print current partition */
		if (argc == 2) {
			if (!ubi_dev.selected) {
				printf("Error, no UBI device/partition selected!\n");
				return 1;
			}

			printf("Device %d: %s, partition %s\n",
			       ubi_dev.nr, ubi_dev.mtd_info->name, ubi_dev.part_name);
			return 0;
		}

		if (argc < 3)
			return CMD_RET_USAGE;

#ifdef CONFIG_CMD_UBIFS
		/*
		 * Automatically unmount UBIFS partition when user
		 * changes the UBI device. Otherwise the following
		 * UBIFS commands will crash.
		 */
		if (ubifs_is_mounted())
			cmd_ubifs_umount();
#endif

		/* todo: get dev number for NAND... */
		ubi_dev.nr = 0;

		/*
		 * Call ubi_exit() before re-initializing the UBI subsystem
		 */
		if (ubi_initialized) {
			ubi_exit();
			del_mtd_partitions(ubi_dev.mtd_info);
		}

		/*
		 * Search the mtd device number where this partition
		 * is located
		 */
		if (find_dev_and_part(argv[2], &dev, &pnum, &part)) {
			printf("Partition %s not found!\n", argv[2]);
			return 1;
		}
		sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(dev->id->type), dev->id->num);
		ubi_dev.mtd_info = get_mtd_device_nm(mtd_dev);
		if (IS_ERR(ubi_dev.mtd_info)) {
			printf("Partition %s not found on device %s!\n", argv[2], mtd_dev);
			return 1;
		}

		ubi_dev.selected = 1;

		if (argc > 3)
			vid_header_offset = argv[3];
		strcpy(ubi_dev.part_name, argv[2]);
		err = ubi_dev_scan(ubi_dev.mtd_info, ubi_dev.part_name,
				vid_header_offset);
		if (err) {
			printf("UBI init error %d\n", err);
			ubi_dev.selected = 0;
			return err;
		}

		ubi = ubi_devices[0];

		return 0;
	}

	if ((strcmp(argv[1], "part") != 0) && (!ubi_dev.selected)) {
		printf("Error, no UBI device/partition selected!\n");
		return 1;
	}

	if (strcmp(argv[1], "info") == 0) {
		int layout = 0;
		if (argc > 2 && !strncmp(argv[2], "l", 1))
			layout = 1;
		return ubi_info(layout);
	}

	if (strncmp(argv[1], "create", 6) == 0) {
		int dynamic = 1;	/* default: dynamic volume */

		/* Use maximum available size */
		size = 0;

		/* E.g., create volume size type */
		if (argc == 5) {
			if (strncmp(argv[4], "s", 1) == 0)
				dynamic = 0;
			else if (strncmp(argv[4], "d", 1) != 0) {
				printf("Incorrect type\n");
				return 1;
			}
			argc--;
		}
		/* E.g., create volume size */
		if (argc == 4) {
			size = simple_strtoul(argv[3], NULL, 16);
			argc--;
		}
		/* Use maximum available size */
		if (!size) {
			size = ubi->avail_pebs * ubi->leb_size;
			printf("No size specified -> Using max size (%u)\n", size);
		}
		/* E.g., create volume */
		if (argc == 3)
			return ubi_create_vol(argv[2], size, dynamic);
	}

	if (strncmp(argv[1], "remove", 6) == 0) {
		/* E.g., remove volume */
		if (argc == 3)
			return ubi_remove_vol(argv[2]);
	}

	if (strncmp(argv[1], "write", 5) == 0) {
		if (argc < 5) {
			printf("Please see usage\n");
			return 1;
		}

		addr = simple_strtoul(argv[2], NULL, 16);
		size = simple_strtoul(argv[4], NULL, 16);

		return ubi_volume_write(argv[3], (void *)addr, size);
	}

	if (strncmp(argv[1], "read", 4) == 0) {
		size = 0;

		/* E.g., read volume size */
		if (argc == 5) {
			size = simple_strtoul(argv[4], NULL, 16);
			argc--;
		}

		/* E.g., read volume */
		if (argc == 4) {
			addr = simple_strtoul(argv[2], NULL, 16);
			argc--;
		}

		if (argc == 3)
			return ubi_volume_read(argv[3], (char *)addr, size);
	}

	printf("Please see usage\n");
	return 1;
}
Beispiel #11
0
int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
	flash_info_t *info;
	ulong bank, addr_first, addr_last;
	int n, sect_first, sect_last;
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
	struct mtd_device *dev;
	struct part_info *part;
	u8 dev_type, dev_num, pnum;
#endif
	int rcode = 0;
	int jffs2erase = 0;

	if (argc < 2) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	// Special JFFS2 erase which will write a JFFS2 "clean" header after the erase
	if('j' == argv[0][0])
	{
		jffs2erase = 1;
	}
	
	if (strcmp(argv[1], "all") == 0) {
		for (bank=1; bank<=CFG_MAX_FLASH_BANKS; ++bank) {
			printf ("Erase Flash Bank # %ld ", bank);
			info = &flash_info[bank-1];
			rcode = flash_erase (info, 0, info->sector_count-1);
			if(jffs2erase) jffs2_write_header(info, 0, info->sector_count-1);
		}
		return rcode;
	}

	if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
		if (n < 0) {
			puts ("Bad sector specification\n");
			return 1;
		}
		printf ("Erase Flash Sectors %d-%d in Bank # %d ",
			sect_first, sect_last, (info-flash_info)+1);
		rcode = flash_erase(info, sect_first, sect_last);
		if(jffs2erase) jffs2_write_header(info, sect_first, sect_last);
		return rcode;
	}

#if (CONFIG_COMMANDS & CFG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
	/* erase <part-id> - erase partition */
	if ((argc == 2) && (id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
		mtdparts_init();
		if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
			if (dev->id->type == MTD_DEV_TYPE_NOR) {
				bank = dev->id->num;
				info = &flash_info[bank];
				addr_first = part->offset + info->start[0];
				addr_last = addr_first + part->size - 1;

				printf ("Erase Flash Parition %s, "
						"bank %d, 0x%08lx - 0x%08lx ",
						argv[1], bank, addr_first,
						addr_last);

				rcode = flash_sect_erase(addr_first, addr_last);
				return rcode;
			}

			printf("cannot erase, not a NOR device\n");
			return 1;
		}
	}
#endif

	if (argc != 3) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	if (strcmp(argv[1], "bank") == 0) {
		bank = simple_strtoul(argv[2], NULL, 16);
		if ((bank < 1) || (bank > CFG_MAX_FLASH_BANKS)) {
			printf ("Only FLASH Banks # 1 ... # %d supported\n",
				CFG_MAX_FLASH_BANKS);
			return 1;
		}
		printf ("Erase Flash Bank # %ld ", bank);
		info = &flash_info[bank-1];
		rcode = flash_erase (info, 0, info->sector_count-1);
		if(jffs2erase) jffs2_write_header(info, 0, info->sector_count-1);
		return rcode;
	}

	if (addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0){
		printf ("Bad address format\n");
		return 1;
	}

	if (addr_first >= addr_last) {
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	if (jffs2erase)
	{
		printf ("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	rcode = flash_sect_erase(addr_first, addr_last);
	return rcode;
}
Beispiel #12
0
void env_relocate_spec (void)
{
#if defined(CONFIG_CMD_UBI)

#if !defined(ENV_IS_EMBEDDED)
	int ret, i, readfrombackup;
	char cmd_buf[30];
	struct mtd_device *dev;
	struct part_info *part;
	uint32_t crc;
	size_t size;
	env_t *ep;
	u8 pnum;

#if defined(CONFIG_ENV_OFFSET_OOB)
	ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
	/*
	 * If unable to read environment offset from NAND OOB then fall through
	 * to the normal environment reading code below
	 */
	if (!ret) {
		printf("Found Environment offset in OOB..\n");
	} else {
		set_default_env("!no env offset in OOB");
		return;
	}
#endif
	
	//get mtdpart string from pni
	set_default_env("!set default for mtdparts");
 
	#if (ENABLE_MODULE_NAND_FLASH == 1)
	drvNAND_GetMtdParts(mtdstr);
	#endif
	#if (ENABLE_MODULE_SPI_NAND_FLASH == 1)
	MDrv_SPINAND_GetMtdParts(mtdstr);
	#endif	

	setenv("mtdparts", mtdstr);
	setenv("mtdids", IdsStr);

	mtdparts_init();
	if(find_dev_and_part(env_partition, &dev, &pnum, &part))
	{
		printf("Partition %s not found!\n", env_partition);
		printf("read env fail\n");
		return;
	}

	if(!ubi_find_volume(ENV_VOL_NAME))
	{
		sprintf(cmd_buf, "ubi part %s", env_partition);
		if(run_command(cmd_buf, 0) == -1)
			return;
	}
	if(!ubi_leb_sz)
		ubi_leb_sz = ubi_get_leb_size();

	if(!env_vol_sz)
		env_vol_sz = (ubi_get_avai_peb() - 1) * ubi_leb_sz;
    
	if(cfg_env_offset == 0)
	{
	    MsApiChunkHeader_GetValue(CH_UBOOT_ENVIRONMENT_ROM_OFFSET,&cfg_env_offset);
		ubi_get_volume_size(ENV_VOL_NAME, &size);
		cfg_env_offset = size - (cfg_env_offset*ubi_leb_sz);
	}
	//find ENV volume

	readfrombackup = 0;
	if(ubi_find_volume(ENV_VOL_NAME))
	{
		for(i = 0 ;i < CONFIG_ENV_BLOCK_NUM; i ++)
		{
			ret = readenv(CONFIG_ENV_OFFSET + i * ubi_leb_sz, (u_char *)gbuf);
			if (ret) {
				if(i < (CONFIG_ENV_BLOCK_NUM - 1))
				{
					printf("Read ENV fail, Read Backup ENV\n");
					readfrombackup = 1;
					continue;
				}
				else
				{
					printf("Read Backup ENV Failed\n");
					return;
				}
			}
			ep = (env_t*) gbuf;
			memcpy(&crc, &ep->crc, sizeof(crc));
//			printf("Calc crc %X, Read crc %X\n", crc32(0, ep->data, ENV_SIZE), crc);
			if(crc32_env_ubi(0,  ep->data, ENV_SIZE) == crc)
			{
				env_import(gbuf, 0);
				break;
			}
			else
			{	
				if(i < (CONFIG_ENV_BLOCK_NUM - 1))
				{
					printf("Read ENV crc error, Read Backup ENV\n");
					readfrombackup = 1;
				}
				else
				{
					printf("Read Backup ENV crc error\n");
					return;
				}
			}
		}
	}
	else
	{
		printf("Found no %s Volume\n Create %s volume\n", ENV_VOL_NAME, ENV_VOL_NAME);
		ret = ubi_create_vol(ENV_VOL_NAME, env_vol_sz, 1);
		if(ret)
			printf("create %s volume in %s partition fail with size = 0x%X\n",  ENV_VOL_NAME, env_partition, env_vol_sz);

		ubi_leb_sz = ubi_get_leb_size();

		ubi_get_volume_size(ENV_VOL_NAME, &size);

		MsApiChunkHeader_GetValue(CH_UBOOT_ENVIRONMENT_ROM_OFFSET,&cfg_env_offset);
		cfg_env_offset = size - (cfg_env_offset*ubi_leb_sz);
	}

	//restore data from backup 
	if(readfrombackup == 1)
	{
		ret = saveenv();
		if(ret)
			printf("restore data fail\n");
	}
#endif /* ! ENV_IS_EMBEDDED */

#else
	set_default_env("!set default for NAND program");

#endif /* ! CONFIG_CMD_UBI*/
}
Beispiel #13
0
int saveenv(void)
{
#if defined(CONFIG_CMD_UBI)
	int ret;
	char cmd_buf[30];
	ssize_t len;
	size_t size;
	char *res;
	struct mtd_device *dev;
	struct part_info *part;
	char last_ubi_partname[32];
	char last_sb_name[32];
	u8 pnum;
	
	memset(last_ubi_partname, 0, 32);
	memset(last_sb_name, 0, 32);
	ubi_get_part_name(last_ubi_partname);
	ubifs_get_sb_name(last_sb_name);
			
	if(find_dev_and_part(env_partition, &dev, &pnum, &part))
	{
		printf("Partition %s not found!\n", env_partition);
		printf("save env fail\n");
		return 1;
	}
	
	if(!ubi_find_volume(ENV_VOL_NAME))
	{
		sprintf(cmd_buf, "ubi part %s", env_partition);
		if(run_command(cmd_buf, 0) == -1)
			return 1;
	}
	if(!ubi_leb_sz)
		ubi_leb_sz = ubi_get_leb_size();
	
	res = (char *)&env_new.data;
	len = hexport_r(&env_htab, '\0', &res, ENV_SIZE);
	if (len < 0) {
		printf("Cannot export environment\n");
		return 1;
	}
	env_new.crc = crc32_env_ubi(0, env_new.data, ENV_SIZE);
	//printf("saveenv crc = %X\n", env_new.crc);

	if(ubi_find_volume(ENV_VOL_NAME))
	{
		printf("Write Env to %X...\n", CONFIG_ENV_OFFSET);
		ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new);
		if (ret) {
			puts("Failed\n");
			return ret;
		}
		printf("Write Backup Env to %X...\n", CONFIG_ENV_OFFSET + ubi_leb_sz);
		ret = writeenv(CONFIG_ENV_OFFSET + ubi_leb_sz, (u_char *) &env_new);
		if (ret)
		{
			puts("Backup Failed\n");
			return ret;
		}
	}
	else
	{
		printf("Found no %s Volume\n Create %s volume\n", ENV_VOL_NAME, ENV_VOL_NAME);
		ret = ubi_create_vol(ENV_VOL_NAME, env_vol_sz, 1);
		if(ret)
		{
			printf("create %s volume in %s partition fail with size = %0xX\n", ENV_VOL_NAME, env_partition, env_vol_sz);
			return ret;
		}
		ubi_leb_sz = ubi_get_leb_size();

	    MsApiChunkHeader_GetValue(CH_UBOOT_ENVIRONMENT_ROM_OFFSET,&cfg_env_offset);
		ubi_get_volume_size(ENV_VOL_NAME, &size);
		cfg_env_offset = size - (cfg_env_offset*ubi_leb_sz);

		ret = writeenv(CONFIG_ENV_OFFSET, (u_char *)&env_new);
        if (ret) {
			puts("Failed\n");
            return ret;
        }
		ret = writeenv(CONFIG_ENV_OFFSET + ubi_leb_sz, (u_char *) &env_new);
		if (ret)
		{
			puts("Backup Failed\n");
			return ret;
		}
	}
	if(last_ubi_partname[0]){
		sprintf(cmd_buf, "ubi part %s", last_ubi_partname);
		if(run_command(cmd_buf, 0) == -1){
			printf("restore ubi part %s failed\n", last_ubi_partname);
			return -1;
		}	
	}
	if(last_sb_name[0]){
		sprintf(cmd_buf, "ubifsmount %s", last_sb_name);
		if(run_command(cmd_buf, 0) == -1){
			printf("remount volume %s failed\n", last_sb_name);
			return -1;
		}
	}
	puts("done\n");
	return ret;
#else
	return 0;
#endif
}
Beispiel #14
0
int ubi_part(char *part_name, const char *vid_header_offset)
{
	int err = 0;
	char mtd_dev[16];
	struct mtd_device *dev;
	struct part_info *part;
	u8 pnum;

	if (mtdparts_init() != 0) {
		printf("Error initializing mtdparts!\n");
		return 1;
	}

#ifdef CONFIG_CMD_UBIFS
	/*
	 * Automatically unmount UBIFS partition when user
	 * changes the UBI device. Otherwise the following
	 * UBIFS commands will crash.
	 */
	if (ubifs_is_mounted())
		cmd_ubifs_umount();
#endif

	/* todo: get dev number for NAND... */
	ubi_dev.nr = 0;

	/*
	 * Call ubi_exit() before re-initializing the UBI subsystem
	 */
	if (ubi_initialized) {
		ubi_exit();
		del_mtd_partitions(ubi_dev.mtd_info);
	}

	/*
	 * Search the mtd device number where this partition
	 * is located
	 */
	if (find_dev_and_part(part_name, &dev, &pnum, &part)) {
		printf("Partition %s not found!\n", part_name);
		return 1;
	}
	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(dev->id->type), dev->id->num);
	ubi_dev.mtd_info = get_mtd_device_nm(mtd_dev);
	if (IS_ERR(ubi_dev.mtd_info)) {
		printf("Partition %s not found on device %s!\n", part_name,
		       mtd_dev);
		return 1;
	}

	ubi_dev.selected = 1;

	strcpy(ubi_dev.part_name, part_name);
	err = ubi_dev_scan(ubi_dev.mtd_info, ubi_dev.part_name,
			vid_header_offset);
	if (err) {
		printf("UBI init error %d\n", err);
		ubi_dev.selected = 0;
		return err;
	}

	ubi = ubi_devices[0];

	return 0;
}
Beispiel #15
0
int do_nandboot(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	char *boot_device = NULL;
	int idx;
	ulong addr, offset = 0;
#if defined(CONFIG_CMD_MTDPARTS)
	struct mtd_device *dev;
	struct part_info *part;
	u8 pnum;

	if (argc >= 2) {
		char *p = (argc == 2) ? argv[1] : argv[2];
		if (!(str2long(p, &addr)) && (mtdparts_init() == 0) &&
		    (find_dev_and_part(p, &dev, &pnum, &part) == 0)) {
			if (dev->id->type != MTD_DEV_TYPE_NAND) {
				puts("Not a NAND device\n");
				return 1;
			}
			if (argc > 3)
				goto usage;
			if (argc == 3)
				addr = simple_strtoul(argv[1], NULL, 16);
			else
				addr = CONFIG_SYS_LOAD_ADDR;
			return nand_load_image(cmdtp, &nand_info[dev->id->num],
					       part->offset, addr, argv[0]);
		}
	}
#endif

	show_boot_progress(52);
	switch (argc) {
	case 1:
		addr = CONFIG_SYS_LOAD_ADDR;
		boot_device = getenv("bootdevice");
		break;
	case 2:
		addr = simple_strtoul(argv[1], NULL, 16);
		boot_device = getenv("bootdevice");
		break;
	case 3:
		addr = simple_strtoul(argv[1], NULL, 16);
		boot_device = argv[2];
		break;
	case 4:
		addr = simple_strtoul(argv[1], NULL, 16);
		boot_device = argv[2];
		offset = simple_strtoul(argv[3], NULL, 16);
		break;
	default:
#if defined(CONFIG_CMD_MTDPARTS)
usage:
#endif
		cmd_usage(cmdtp);
		show_boot_progress(-53);
		return 1;
	}

	show_boot_progress(53);
	if (!boot_device) {
		puts("\n** No boot device **\n");
		show_boot_progress(-54);
		return 1;
	}
	show_boot_progress(54);

	idx = simple_strtoul(boot_device, NULL, 16);

	if (idx < 0 || idx >= CONFIG_SYS_MAX_NAND_DEVICE || !nand_info[idx].name) {
		printf("\n** Device %d not available\n", idx);
		show_boot_progress(-55);
		return 1;
	}
	show_boot_progress(55);

	return nand_load_image(cmdtp, &nand_info[idx], offset, addr, argv[0]);
}
Beispiel #16
0
int do_flerase (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#ifndef CONFIG_SYS_NO_FLASH
	flash_info_t *info;
	ulong bank, addr_first, addr_last;
	int n, sect_first, sect_last;
#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
	struct mtd_device *dev;
	struct part_info *part;
	u8 dev_type, dev_num, pnum;
#endif
	int rcode = 0;

	if (argc < 2) {
		cmd_usage(cmdtp);
		return 1;
	}

	if (strcmp(argv[1], "all") == 0) {
		for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
			printf ("Erase Flash Bank # %ld ", bank);
			info = &flash_info[bank-1];
			rcode = flash_erase (info, 0, info->sector_count-1);
		}
		return rcode;
	}

	if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
		if (n < 0) {
			puts ("Bad sector specification\n");
			return 1;
		}
		printf ("Erase Flash Sectors %d-%d in Bank # %zu ",
			sect_first, sect_last, (info-flash_info)+1);
		rcode = flash_erase(info, sect_first, sect_last);
		return rcode;
	}

#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
	/* erase <part-id> - erase partition */
	if ((argc == 2) && (mtd_id_parse(argv[1], NULL, &dev_type, &dev_num) == 0)) {
		mtdparts_init();
		if (find_dev_and_part(argv[1], &dev, &pnum, &part) == 0) {
			if (dev->id->type == MTD_DEV_TYPE_NOR) {
				bank = dev->id->num;
				info = &flash_info[bank];
				addr_first = part->offset + info->start[0];
				addr_last = addr_first + part->size - 1;

				printf ("Erase Flash Partition %s, "
						"bank %ld, 0x%08lx - 0x%08lx ",
						argv[1], bank, addr_first,
						addr_last);

				rcode = flash_sect_erase(addr_first, addr_last);
				return rcode;
			}

			printf("cannot erase, not a NOR device\n");
			return 1;
		}
	}
#endif

	if (argc != 3) {
		cmd_usage(cmdtp);
		return 1;
	}

	if (strcmp(argv[1], "bank") == 0) {
		bank = simple_strtoul(argv[2], NULL, 16);
		if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
			printf ("Only FLASH Banks # 1 ... # %d supported\n",
				CONFIG_SYS_MAX_FLASH_BANKS);
			return 1;
		}
		printf ("Erase Flash Bank # %ld ", bank);
		info = &flash_info[bank-1];
		rcode = flash_erase (info, 0, info->sector_count-1);
		return rcode;
	}

	if (addr_spec(argv[1], argv[2], &addr_first, &addr_last) < 0){
		printf ("Bad address format\n");
		return 1;
	}

	if (addr_first >= addr_last) {
		cmd_usage(cmdtp);
		return 1;
	}

	rcode = flash_sect_erase(addr_first, addr_last);
	return rcode;
#else
	return 0;
#endif /* CONFIG_SYS_NO_FLASH */
}
Beispiel #17
0
int do_protect (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#ifndef CONFIG_SYS_NO_FLASH
	flash_info_t *info;
	ulong bank;
	int i, n, sect_first, sect_last;
#endif /* CONFIG_SYS_NO_FLASH */
#if !defined(CONFIG_SYS_NO_FLASH) || defined(CONFIG_HAS_DATAFLASH)
	ulong addr_first, addr_last;
#endif
#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
	struct mtd_device *dev;
	struct part_info *part;
	u8 dev_type, dev_num, pnum;
#endif
#ifdef CONFIG_HAS_DATAFLASH
	int status;
#endif
	int p;
	int rcode = 0;

	if (argc < 3) {
		cmd_usage(cmdtp);
		return 1;
	}

	if (strcmp(argv[1], "off") == 0) {
		p = 0;
	} else if (strcmp(argv[1], "on") == 0) {
		p = 1;
	} else {
		cmd_usage(cmdtp);
		return 1;
	}

#ifdef CONFIG_HAS_DATAFLASH
	if ((strcmp(argv[2], "all") != 0) && (strcmp(argv[2], "bank") != 0)) {
		addr_first = simple_strtoul(argv[2], NULL, 16);
		addr_last  = simple_strtoul(argv[3], NULL, 16);

		if (addr_dataflash(addr_first) && addr_dataflash(addr_last)) {
			status = dataflash_real_protect(p,addr_first,addr_last);
			if (status < 0){
				puts ("Bad DataFlash sector specification\n");
				return 1;
			}
			printf("%sProtect %d DataFlash Sectors\n",
				p ? "" : "Un-", status);
			return 0;
		}
	}
#endif

#ifndef CONFIG_SYS_NO_FLASH
	if (strcmp(argv[2], "all") == 0) {
		for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
			info = &flash_info[bank-1];
			if (info->flash_id == FLASH_UNKNOWN) {
				continue;
			}
			printf ("%sProtect Flash Bank # %ld\n",
				p ? "" : "Un-", bank);

			for (i=0; i<info->sector_count; ++i) {
#if defined(CONFIG_SYS_FLASH_PROTECTION)
				if (flash_real_protect(info, i, p))
					rcode = 1;
				putc ('.');
#else
				info->protect[i] = p;
#endif	/* CONFIG_SYS_FLASH_PROTECTION */
			}
#if defined(CONFIG_SYS_FLASH_PROTECTION)
			if (!rcode) puts (" done\n");
#endif	/* CONFIG_SYS_FLASH_PROTECTION */
		}
		return rcode;
	}

	if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
		if (n < 0) {
			puts ("Bad sector specification\n");
			return 1;
		}
		printf("%sProtect Flash Sectors %d-%d in Bank # %zu\n",
			p ? "" : "Un-", sect_first, sect_last,
			(info-flash_info)+1);
		for (i = sect_first; i <= sect_last; i++) {
#if defined(CONFIG_SYS_FLASH_PROTECTION)
			if (flash_real_protect(info, i, p))
				rcode =  1;
			putc ('.');
#else
			info->protect[i] = p;
#endif	/* CONFIG_SYS_FLASH_PROTECTION */
		}

#if defined(CONFIG_SYS_FLASH_PROTECTION)
		if (!rcode) puts (" done\n");
#endif	/* CONFIG_SYS_FLASH_PROTECTION */

		return rcode;
	}

#if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_CMD_MTDPARTS)
	/* protect on/off <part-id> */
	if ((argc == 3) && (mtd_id_parse(argv[2], NULL, &dev_type, &dev_num) == 0)) {
		mtdparts_init();
		if (find_dev_and_part(argv[2], &dev, &pnum, &part) == 0) {
			if (dev->id->type == MTD_DEV_TYPE_NOR) {
				bank = dev->id->num;
				info = &flash_info[bank];
				addr_first = part->offset + info->start[0];
				addr_last = addr_first + part->size - 1;

				printf ("%sProtect Flash Partition %s, "
						"bank %ld, 0x%08lx - 0x%08lx\n",
						p ? "" : "Un", argv[1],
						bank, addr_first, addr_last);

				rcode = flash_sect_protect (p, addr_first, addr_last);
				return rcode;
			}

			printf("cannot %sprotect, not a NOR device\n",
					p ? "" : "un");
			return 1;
		}
	}
#endif

	if (argc != 4) {
		cmd_usage(cmdtp);
		return 1;
	}

	if (strcmp(argv[2], "bank") == 0) {
		bank = simple_strtoul(argv[3], NULL, 16);
		if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
			printf ("Only FLASH Banks # 1 ... # %d supported\n",
				CONFIG_SYS_MAX_FLASH_BANKS);
			return 1;
		}
		printf ("%sProtect Flash Bank # %ld\n",
			p ? "" : "Un-", bank);
		info = &flash_info[bank-1];

		if (info->flash_id == FLASH_UNKNOWN) {
			puts ("missing or unknown FLASH type\n");
			return 1;
		}
		for (i=0; i<info->sector_count; ++i) {
#if defined(CONFIG_SYS_FLASH_PROTECTION)
			if (flash_real_protect(info, i, p))
				rcode =  1;
			putc ('.');
#else
			info->protect[i] = p;
#endif	/* CONFIG_SYS_FLASH_PROTECTION */
		}

#if defined(CONFIG_SYS_FLASH_PROTECTION)
		if (!rcode) puts (" done\n");
#endif	/* CONFIG_SYS_FLASH_PROTECTION */

		return rcode;
	}

	if (addr_spec(argv[2], argv[3], &addr_first, &addr_last) < 0){
		printf("Bad address format\n");
		return 1;
	}

	if (addr_first >= addr_last) {
		cmd_usage(cmdtp);
		return 1;
	}
	rcode = flash_sect_protect (p, addr_first, addr_last);
#endif /* CONFIG_SYS_NO_FLASH */
	return rcode;
}
Beispiel #18
0
int do_ubi(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
	size_t size = 0;
	ulong addr = 0;
	int err = 0;
	size_t vol_offset = 0;

	if (argc < 2) {
		printf("Usage:\n%s\n", cmdtp->usage);
		return 1;
	}

	if (mtdparts_init() != 0) {
		printf("Error initializing mtdparts!\n");
		return 1;
	}

	if (strcmp(argv[1], "part") == 0) {
		char mtd_dev[16];
		struct mtd_device *dev;
		struct part_info *part;
		const char *vid_header_offset = NULL;
		u8 pnum;

		/* Print current partition */
		if (argc == 2) {
			if (!ubi_dev.selected) {
				printf("Error, no UBI device/partition selected!\n");
				return 1;
			}

			printf("Device %d: %s, partition %s\n",
			       ubi_dev.nr, ubi_dev.mtd_info->name, ubi_dev.part_name);
			return 0;
		}

		if (argc < 3) {
			printf("Usage:\n%s\n", cmdtp->usage);
			return 1;
		}

		/* todo: get dev number for NAND... */
		ubi_dev.nr = 0;

		/*
		 * Call ubi_exit() before re-initializing the UBI subsystem
		 */
		if (ubi_initialized) {
			ubi_exit();
			del_mtd_partitions(ubi_dev.mtd_info);
		}

		/*
		 * Search the mtd device number where this partition
		 * is located
		 */
		if (find_dev_and_part(argv[2], &dev, &pnum, &part)) {
			printf("Partition %s not found!\n", argv[2]);
			return 1;
		}
		sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(dev->id->type), dev->id->num);
		ubi_dev.mtd_info = get_mtd_device_nm(mtd_dev);
		if (IS_ERR(ubi_dev.mtd_info)) {
			printf("Partition %s not found on device %s!\n", argv[2], mtd_dev);
			return 1;
		}

		ubi_dev.selected = 1;

		if (argc > 3)
			vid_header_offset = argv[3];
		strcpy(ubi_dev.part_name, argv[2]);
		err = ubi_dev_scan(ubi_dev.mtd_info, ubi_dev.part_name,
				vid_header_offset);
		if (err) {
			printf("UBI init error %d\n", err);
			ubi_dev.selected = 0;
			return err;
		}

		ubi = ubi_devices[0];

		return 0;
	}

	if (strcmp(argv[1], "detach") == 0) {
		if (ubi_initialized) {
			ubi_exit();
			del_mtd_partitions(ubi_dev.mtd_info);
			ubi_initialized = 0;
			ubi_dev.selected = 0;
			if (ubi)
				memset(ubi, 0, sizeof(*ubi));
		}

		return 0;
	}

	if ((strcmp(argv[1], "part") != 0) && (!ubi_dev.selected)) {
		printf("Error, no UBI device/partition selected!\n");
		return 1;
	}

	if (strcmp(argv[1], "info") == 0) {
		int layout = 0;
		if (argc > 2 && !strncmp(argv[2], "l", 1))
			layout = 1;
		if (argc > 2 && !strncmp(argv[2], "w", 1))
			layout = 2;
		return ubi_info(layout);
	}

	if (strncmp(argv[1], "create", 6) == 0) {
		int dynamic = 1;	/* default: dynamic volume */

		/* Use maximum available size */
		size = 0;

		/* E.g., create volume size type */
		if (argc == 5) {
			if (strncmp(argv[4], "s", 1) == 0)
				dynamic = 0;
			else if (strncmp(argv[4], "d", 1) != 0) {
				printf("Incorrect type\n");
				return 1;
			}
			argc--;
		}
		/* E.g., create volume size */
		if (argc == 4) {
			size = simple_strtoul(argv[3], NULL, 16);
			argc--;
		}
		/* Use maximum available size */
		if (!size) {
			if (ubi->avail_pebs < MIN_AVAILABLE_PEB) {
				ubi_err("available_pebs %d < MIN_AVAILABLE_PEB %d\n",
					ubi->avail_pebs, MIN_AVAILABLE_PEB);
				return 1;
			}
			size = (ubi->avail_pebs - MIN_AVAILABLE_PEB) * ubi->leb_size;
			printf("No size specified -> Using max size (0x%x)\n", size);
		}
		/* E.g., create volume */
		if (argc == 3)
			return ubi_create_vol(argv[2], size, dynamic);
	}

	if (strncmp(argv[1], "remove", 6) == 0) {
		/* E.g., remove volume */
		if (argc == 3)
			return ubi_remove_vol(argv[2]);
	}

	if (strncmp(argv[1], "write", 5) == 0) {
		if (argc < 5) {
			printf("Please see usage\n");
			return 1;
		}

		addr = simple_strtoul(argv[2], NULL, 16);
		size = simple_strtoul(argv[4], NULL, 16);

		return ubi_volume_write(argv[3], (void *)addr, size);
	}

	if (strncmp(argv[1], "read", 4) == 0) {
		size = 0;
		vol_offset = 0;

		/* E.g., offset in volume */
		if (argc == 6) {
			vol_offset = simple_strtoul(argv[5], NULL, 16);
			argc--;
		}

		/* E.g., read volume size */
		if (argc == 5) {
			size = simple_strtoul(argv[4], NULL, 16);
			argc--;
		}

		/* E.g., read volume */
		if (argc == 4) {
			addr = simple_strtoul(argv[2], NULL, 16);
			argc--;
		}

		if (argc == 3)
			return ubi_volume_read(argv[3], (char *)addr, size, vol_offset);
	}

	printf("Please see usage\n");
	return 1;
}