0
点赞
收藏
分享

微信扫一扫

getopt_long 应用及nand读写文件操作 upgrade操作

追风骚年 2022-04-06 阅读 85
c语言

(96条消息) linux——getopt()和getopt_long()函数及optarg,optind, opterr, optopt全局变量_夜风~的博客-CSDN博客_linux optarg

#include <getopt.h>
getopt被用来解析命令行选项参数。
getopt_long支持长选项的命令行解析,使用man getopt_long,得到其声明如下:
int getopt_long(int argc, char * const argv[],const char *optstring, const struct option *longopts,int *flag);
函数中的argc和argv通常直接从main()的两个参数传递而来。optsting是选项参数组成的字符串:
字符串optstring可以下列元素:
1.单个字符,表示选项,
2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。
3 单个字符后跟两个冒号,表示该选项后可以有参数也可以没有参数。如果有参数,参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。(这个特性是GNU的扩张)。
optstring是一个字符串,表示可以接受的参数。例如,"a:b:c:d:",表示可以接受的参数是a,b,c,d,其中,a和b参数后面跟有更多的参数值。(例如:-a host -b name)
参数longopts,其实是一个结构的实例:
struct option {undefined
const char *name; //name表示的是长参数名
int has_arg; //has_arg有3个值,no_argument(或者是0),表示该参数后面不跟参数值
                       ~~~~~~~~~~~~~~~~~~~~~~                      // required_argument(或者是1),表示该参数后面一定要跟个参数值
                      ~~~~~~~~~~~~~~~~~~~~~                      // optional_argument(或者是2),表示该参数后面可以跟,也可以不跟参数值
int *flag;
                      ~~~~~~~~~~~~~~~~~~~~~                      //用来决定,getopt_long()的返回值到底是什么。如果flag是null(通常情况),则函数会返回与该项option匹配的val值;如果flag不是NULL,则将val值赋予flag所指向的内存,并且返回值设置为0。

int val; //和flag联合决定返回值
}
参数flag,表示当前长参数在longopts中的索引值。
给个例子:
struct option long_options[] = {undefined
{“a123”, required_argument, 0, ‘a’},
{“c123”, no_argument, 0, ‘c’},
}
现在,如果命令行的参数是-a 123,那么调用getopt_long()将返回字符’a’,并且将字符串123由optarg返回(注意注意!字符串123由optarg带回!optarg不需要定义,在getopt.h中已经有定义),那么,如果命令行参数是-c,那么调用getopt_long()将返回字符’c’,而此时,optarg是null。最后,当getopt_long()将命令行所有参数全部解析完成后,返回-1。
 

下面原创 upgrade 升级

#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/string.h>
#ifdef __UCLIBC__
#include <bits/getopt.h>
#else
#include <getopt.h>
#endif

#include <ctype.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <basetypes.h>
#include <inttypes.h>
static void display_version (void)
{
	printf(PROGRAM " " VERSION "" AMB_VERSION "\n"
			"\n"
			"Copyright (C) 2016 Ambarella \n"
			"\n");
	printf(PROGRAM " For %s\n\n",  ptb_device);
	exit(0);
}

static void init_nand_update_global(nand_update_global_t *pG)
{
	pG->none_oobinfo.useecc = MTD_NANDECC_OFF;
	pG->autoplace_oobinfo.useecc = MTD_NANDECC_AUTOPLACE;

	pG->jffs2_oobinfo.useecc = MTD_NANDECC_PLACE;
	pG->jffs2_oobinfo.eccbytes = 6;
	pG->jffs2_oobinfo.eccpos[0] = 0;
	pG->jffs2_oobinfo.eccpos[1] = 1;
	pG->jffs2_oobinfo.eccpos[2] = 2;
	pG->jffs2_oobinfo.eccpos[3] = 3;
	pG->jffs2_oobinfo.eccpos[4] = 6;
	pG->jffs2_oobinfo.eccpos[5] = 7;

	pG->yaffs_oobinfo.useecc = MTD_NANDECC_PLACE;
pG->jffs2_oobinfo.eccpos[4] = 6;
	pG->jffs2_oobinfo.eccpos[5] = 7;

	pG->yaffs_oobinfo.useecc = MTD_NANDECC_PLACE;
	pG->yaffs_oobinfo.eccbytes = 6;
	pG->yaffs_oobinfo.eccpos[0] = 8;
	pG->yaffs_oobinfo.eccpos[1] = 9;
	pG->yaffs_oobinfo.eccpos[2] = 10;
	pG->yaffs_oobinfo.eccpos[3] = 13;
	pG->yaffs_oobinfo.eccpos[4] = 14;
	pG->yaffs_oobinfo.eccpos[5] = 15;

	memset(pG->oobbuf, 0xff, sizeof(pG->oobbuf));

}
static int get_ptb_buf_size(int ptb_fd, int *size, int *ptb_offset)
{
	int ret = 0;
	loff_t ptb_bad_offset;
	struct mtd_info_user ptb_meminfo;

	if (is_emmc_boot()) {
		*size = AMBOOT_PTB_BUF_SIZE;
	} else {
		/* Fill in MTD device capability structure */
		if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
			perror("PTB MEMGETINFO");
			return -1;
		}

		for (*ptb_offset = 0; *ptb_offset < ptb_meminfo.size; *ptb_offset += ptb_meminfo.erasesize) {
			ptb_bad_offset = *ptb_offset;
			if ((ret = ioctl(ptb_fd, MEMGETBADBLOCK, &ptb_bad_offset)) < 0) {
				perror("ioctl(MEMGETBADBLOCK)");
				return -1;
			}

			if (ret == 0)
				break;

			if (!quiet)
				fprintf (stderr,
				"Bad block at %x, from %x will be skipped\n", (int)ptb_bad_offset, *ptb_offset);
		}
		if (*ptb_offset >= ptb_meminfo.size) {
			fprintf(stderr, "Can't find good block in PTB.\n");
			return -1;
		}
		*size = ptb_meminfo.erasesize > AMBOOT_PTB_BUF_SIZE ? ptb_meminfo.erasesize
	}

	return ret;
}

/**
 * Get the content of the partition table.
 */
static int flprog_get_part_table (u8 **ptb_buf)
{
	int ptb_fd = -1, ptb_offset = 0;
	int ret = 0, i = 0, count;
	flpart_table_t *table;

	/* Open the PTB device */
	if ((ptb_fd = open(ptb_device, O_RDONLY)) == -1) {
		perror("open PTB");
		exit(1);
	}

	ret = get_ptb_buf_size(ptb_fd, &count, &ptb_offset);
	if (ret < 0) {
		goto closeall;
	}
	*ptb_buf = malloc(count);

	//memset(*ptb_buf, 0x0, ptb_meminfo.erasesize);

	/* Read partition table.
	 * Note: we need to read and save the entire block data, because the
	 * entire block will be erased when write partition table back to flash.
	 * BTW, flpart_meta_t is located in the same block as flpart_table_t
	 */
	if (pread(ptb_fd, *ptb_buf, count, ptb_offset) != count) {
		perror("pread PTB");
		ret = -1;
		free(*ptb_buf);
		goto closeall;
	}
if (update_fdt || show_fdt_flag || ambarella_cmd || amboot_autoexec_enable) {
		/* dtb would be placed behind flpart_meta_t. */
		fdt_root = (void *)(*ptb_buf + PTB_HEADER_SIZE + PTB_SIZE + PTB_META_SIZE);
		if ((fdt_magic(fdt_root) == FDT_MAGIC) &&
		(fdt_version(fdt_root) >= 17)) {
			printf("fdt is in the PTB block \n");
		} else {
			perror("No FDT behind PTB");
			fdt_check_error = 1;
		}
		if (show_fdt_flag && !fdt_check_error) {
			display_fdt(fdt_root);
		}
	}

	table = PTB_TABLE(*ptb_buf);
	if (!quiet) {
		 for(i = 0; i < PART_MAX_WITH_RSV; i++){
			if( table->part[i].img_len!=0)
				display_flpart(g_part_str[i], &(table->part[i]));
		 }
		 display_dev(&(table->dev));
	}

closeall:
	close(ptb_fd);

	return ret;
}


int nand_is_bad_block(int ptb_fd, int block)
{
    struct mtd_info_user ptb_meminfo;
    int ret = 0;
    loff_t ptb_bad_offset = 0;
    if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
        perror("PTB MEMGETINFO");
        return -1;
    }
    ptb_bad_offset = block * ptb_meminfo.erasesize;
    if ((ret = ioctl(ptb_fd, MEMGETBADBLOCK, &ptb_bad_offset)) < 0) {
        perror("ioctl(MEMGETBADBLOCK)");
        return -1;
    }
    return ret;
}


static int nand_erase_block(int ptb_fd, int block)
{
    struct mtd_info_user ptb_meminfo;
    int ret = 0;
    if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
        perror("PTB MEMGETINFO");
        return -1;
    }
    loff_t ptb_offset = block * ptb_meminfo.erasesize;
    erase_info_t erase;
    erase.start = ptb_offset;
    erase.length = ptb_meminfo.erasesize;
    if ((ret = ioctl(ptb_fd, MEMERASE, &erase)) != 0) {
        perror("PTB MEMERASE");
        return -1;
    }
    return 0;
}


static int nand_mark_bad_block(int ptb_fd, int block)
{
    int ret = 0;
    struct mtd_info_user ptb_meminfo;
    
    if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
        perror("PTB MEMGETINFO");
        return -1;
    }
    u32 offs = (loff_t) block * ptb_meminfo.erasesize;
    if ((ret = ioctl(ptb_fd, MEMSETBADBLOCK, &offs)) < 0) {
        perror("ioctl(MEMSETBADBLOCK)");
        return -1;
    }
    if (ret == 0) {        
        fprintf (stdout, "set Bad block at %x !\n", block * ptb_meminfo.erasesize);            
    }
    return 0;
}


static int flprog_nand_prog_block_loop(u8 *raw_image, unsigned int raw_size,
	u32 sblk, u32 nblk, int ptb_fd, void *arg)
{
	u32 block, page, pre_offset, offset = 0, empty_block = sblk;
	int percentage, firm_ok = 0, rval = 0;
    u32 block_offset = 0;
    int ret = 0, buf_num = 0;
    struct mtd_info_user ptb_meminfo;
    u8 *read_buf = NULL;
    if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
        perror("PTB MEMGETINFO");
        goto done;
    }
    if (raw_size > ptb_meminfo.erasesize) {
        printf("raw_size too large\n");
        goto done;
    }
    read_buf = (u8 *)malloc(sizeof(u8) * raw_size);
    if ( read_buf == NULL ) {
        printf("read buf malloc fail\n");
        goto done;
    }
    memset(read_buf, 0, sizeof(u8) * raw_size);
	for (block = sblk; block < sblk + nblk; block++) {
		rval = nand_is_bad_block(ptb_fd, block);
		if (rval != 0) {
			printf("nand_is_bad_block, block = %d\n",block);
			rval = 0;
			continue;
		}

rval = nand_erase_block(ptb_fd, block);
		if (rval < 0) {
			printf("erase failed. <block %d>\n", block);
			printf("Try next block...\n");

			/* Marked and skipped bad block */
			if (nand_mark_bad_block(ptb_fd, block) < 0)
				goto done;

			continue;
		}

#if 0 // defined(CONFIG_NAND_ERASE_UNUSED_BLOCK)
		/* erase the unused block after program ok */
		if (firm_ok == 1)
			continue;
#endif
rval = nand_erase_block(ptb_fd, block);
		if (rval < 0) {
			printf("erase failed. <block %d>\n", block);
			printf("Try next block...\n");

			/* Marked and skipped bad block */
			if (nand_mark_bad_block(ptb_fd, block) < 0)
				goto done;

			continue;
		}

#if 0 // defined(CONFIG_NAND_ERASE_UNUSED_BLOCK)
		/* erase the unused block after program ok */
		if (firm_ok == 1)
			continue;
#endif

#if 0
		/* Program each page */
		for (page = 0; page < flnand.pages_per_block; page++) {
			/* Program a page */
			rval = nand_prog_pages(block, page, 1, raw_image + offset, NULL);
			if (rval < 0) {
				printf("program failed. <block %d, page %d>\n", block, page);
				break;
			}

			/* Read it back for verification */
			rval = nand_read_pages(block, page, 1, check_buf, NULL, 1);
			if (rval < 0) {
				printf("read failed. <block %d, page %d>\n", block, page);
				break;
			}

			/* Compare memory content after read back */
			rval = memcmp(raw_image + offset, check_buf, flnand.main_size);
			if (rval != 0) {
				printf("check failed. <block %d, page %d>\n", block, page);
				rval = -1;
				break;
			}

			offset += flnand.main_size;
			if (offset >= raw_size) {
				firm_ok = 1;
				empty_block = min(block + 1, sblk + nblk);
#if !defined(CONFIG_NAND_ERASE_UNUSED_BLOCK)
				block = sblk + nblk + 1;  /* force out! */
#endif
				break;
			}
		}
#endif



        block_offset = block * ptb_meminfo.erasesize;
        printf("block_offset = %d\n",block_offset);
		/* Write out the Page data */
		if (pwrite(ptb_fd, raw_image, raw_size, block_offset) != raw_size) {
			perror ("pwrite");
			if (nand_mark_bad_block(ptb_fd, block) < 0)
				goto done;
			continue;
		}

		/* read out the Page data */
		if (pread(ptb_fd, read_buf, raw_size, block_offset) != raw_size) {
			perror ("pread");
			if (nand_mark_bad_block(ptb_fd, block) < 0)
				goto done;
			continue;
		}
        rval = memcmp(raw_image, read_buf, raw_size);
		if (rval != 0) {
			rval = nand_mark_bad_block(ptb_fd, block);
			if (rval < 0)
				break;
		}
        empty_block = min(block + 1, sblk + nblk);
        printf("empty_block = %d\n", empty_block);
        break;
	}

done:
    if ( read_buf ) {
        free(read_buf);
        read_buf = NULL;
    }
	return rval == 0 ? empty_block : rval;
}

static int erase_ptb(int ptb_fd, int *size, off_t *ptb_offset)
{
	int ret = 0;
	struct mtd_info_user ptb_meminfo;
	loff_t ptb_bad_offset;

	if (is_emmc_boot()) {
		*size = AMBOOT_PTB_BUF_SIZE;
	} else {
		/* Fill in MTD device capability structure */
		if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
			perror("PTB MEMGETINFO");
			return -1;
		}

		if (PTB_SIZE > ptb_meminfo.erasesize) {
			fprintf(stderr, "PTB can't fit into erasesize.\n");
			return -1;
		}

		for (*ptb_offset = 0; *ptb_offset < ptb_meminfo.size; *ptb_offset += ptb_meminfo.erasesize) {
			ptb_bad_offset = *ptb_offset;
			if ((ret = ioctl(ptb_fd, MEMGETBADBLOCK, &ptb_bad_offset)) < 0) {
				perror("ioctl(MEMGETBADBLOCK)");
				return -1;
			}

			if (ret == 0) {
				/* This isn't a bad block, so erase it first */
				erase_info_t erase;
				erase.start = *ptb_offset;
				erase.length = ptb_meminfo.erasesize;
				if ((ret = ioctl(ptb_fd, MEMERASE, &erase)) != 0) {
					perror("PTB MEMERASE");
					continue;
				}
				break;
			}

			if (!quiet)
				fprintf (stderr,
					"Bad block at %x, from %x will be skipped\n",
					(int)ptb_bad_offset, (int)*ptb_offset);
		}

		if (*ptb_offset >= ptb_meminfo.size) {
			fprintf(stderr, "Can't find good block in PTB.\n");
			return -1;
		}
		*size = ptb_meminfo.erasesize;
	}

	return ret;
}


/**
 * Program the PTB entry.
 */
static int flprog_set_part_table(u8 **ptb_buf)
{
	int ret = 0, i = 0, ptb_fd = -1, sblk = 0, nblk = 0;
	int count;
	ptb_header_t *header;
	u32 offs;
	off_t ptb_offset = 0;
	flpart_table_t *table = PTB_TABLE(*ptb_buf);
	/* Open the PTB device */

	if ((ptb_fd = open(ptb_device, O_RDWR)) == -1) {
		perror("open PTB");
		exit(1);
	}
#if 0
	ret = erase_ptb(ptb_fd, &count, &ptb_offset);
	if (ret < 0) {
		goto closeall;
	}
#endif
	if (table->dev.magic != FLPART_MAGIC) {
		fprintf(stderr, "Invalid dev magic: 0x%08x(0x%08x)\n",
			table->dev.magic, FLPART_MAGIC);
		ret = -1;
		goto closeall;
	}

	for(i = 0; i < PART_MAX_WITH_RSV; i++){
		if (table->part[i].img_len != 0 && table->part[i].magic != FLPART_MAGIC) {
			fprintf(stderr,
				"Invalid partition table magic(%d): 0x%08x(0x%08x)\n",
				i, table->part[i].magic, FLPART_MAGIC);
			ret = -1;
			goto closeall;
		}
	}

	header = PTB_HEADER(*ptb_buf);
	header->magic = PTB_HEADER_MAGIC;
	header->version = PTB_HEADER_VERSION;
	/* crc32 calculates all of the data in bld_ptb_buf, only except
	 * for header->magic and header->crc32 itself */
	offs = sizeof(u32) * 2;
	header->crc32 = crc32_amba(*ptb_buf + offs, AMBOOT_PTB_BUF_SIZE - offs);
	printf("The header crc32 is 0x%08x \n",header->crc32);
#if 0
	if (pwrite(ptb_fd, *ptb_buf, count, ptb_offset) != count) {
		perror ("pwrite PTB");
		ret = -1;
		goto closeall;
	}
#endif
#if 1    
    struct mtd_info_user ptb_meminfo;
    if ((ret = ioctl(ptb_fd, MEMGETINFO, &ptb_meminfo)) != 0) {
        perror("PTB MEMGETINFO");
        goto closeall;
    }
    int ptbSize = ptb_meminfo.size;
    int blockSize = ptb_meminfo.erasesize;

    sblk = 0;
    nblk = ptbSize / blockSize;
    printf("ptbSize=%d, blockSize=%d, sblk = %d, nblk = %d\n", ptbSize, blockSize, sblk, nblk);
  ret = flprog_nand_prog_block_loop(*ptb_buf, blockSize, sblk, nblk, ptb_fd, NULL);
    if (ret < 0) {
        printf("flprog_nand_prog_block_loop write first ptb fail (%d)\n", ret);
        goto closeall;
    }

    /* write backup PTB */
    sblk = ret;
    nblk = ptbSize / blockSize - ret;
    printf("backup sblk = %d, nblk = %d\n", sblk, nblk);
    ret = flprog_nand_prog_block_loop(*ptb_buf, blockSize, sblk, nblk, ptb_fd, NULL);
    if (ret < 0) {
        printf("flprog_nand_prog_block_loop write backup ptb fail (%d)\n", ret);
        goto closeall;
    }
#endif


	if (!quiet) {
		for(i = 0;i < PART_MAX_WITH_RSV; i++){
			if( table->part[i].img_len!=0)
				display_flpart(g_part_str[i], &table->part[i]);
		}
		display_dev(&table->dev);
	}

closeall:
	free(*ptb_buf);
	close(ptb_fd);

	return ret;
}

static void update_partition_of_flash(uint8_t *ptb_buf, size_t *image_length, int *image_crc)
{
	int fd = -1, ifd = -1;
	int cnt = 0;
	size_t readlen = 0;
	size_t imglen = 0;
	unsigned char readbuf[MAX_PAGE_SIZE];
	int file_offset = mtdoffset;
	int buf_num = 0;
	nand_update_file_header_t image_head;

	int pagelen, baderaseblock, blockstart = -1;
	int ret, oobinfochanged = 0;
	struct nand_oobinfo old_oobinfo;
	struct mtd_info_user meminfo;
	struct mtd_oob_buf oob;
	loff_t offs;

	/* Update the partition */
	if (!mtd_device || !img) {
		printf("mtd device or img is NULL.\n");
		exit(1);
	}

	ptr_update_G = malloc(sizeof(nand_update_global_t));
	if (!ptr_update_G) {
		perror("can not malloc buffer for update global.\n");
		exit(1);
	}

	init_nand_update_global(ptr_update_G);

	if (pad && writeoob) {
		fprintf(stderr, "Can't pad when oob data is present.\n");
		exit(1);
	}

	//update_partition_with_img();
	/* Open the device */
	if ((fd = open(mtd_device, O_RDWR)) == -1) {
		perror("open flash");
		exit(1);
	}

	/* Fill in MTD device capability structure */
	if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {
		perror("MEMGETINFO");
		close(fd);
		exit(1);
	}

	/* Set erasesize to specified number of blocks - to match jffs2
	* (virtual) block size */
	meminfo.erasesize *= blockalign;

	/* Make sure device page sizes are valid */
	if (!((meminfo.oobsize == 128 && meminfo.writesize == 4096) ||
		(meminfo.oobsize == 256 && meminfo.writesize == 4096)) &&
		!((meminfo.oobsize == 64 && meminfo.writesize == 2048) ||
		(meminfo.oobsize == 128 && meminfo.writesize == 2048))) {
		fprintf(stderr, "Unknown flash (not normal NAND)\n");
		close(fd);
		exit(1);
	}

/*
	* force oob layout for jffs2 or yaffs ?
	* Legacy support
	*/
	if (forcejffs2 || forceyaffs) {
		if (meminfo.oobsize == 8) {
			if (forceyaffs) {
				fprintf (stderr, "YAFSS cannot operate on 256 Byte page size");
				goto restoreoob;
			}
			/* Adjust number of ecc bytes */
			ptr_update_G->jffs2_oobinfo.eccbytes = 3;
		}
	}

	oob.length = meminfo.oobsize;
	oob.ptr = ptr_update_G->oobbuf;

	/* Open the input file */
	if ((ifd = open(img, O_RDONLY)) == -1) {
		perror("open input file");
		goto restoreoob;
	}
// get image length
	imglen = lseek(ifd, 0, SEEK_END);
	lseek (ifd, 0, SEEK_SET);
	if (skip_head) {
		if (read(ifd, &image_head, sizeof(nand_update_file_header_t)) != sizeof(nand_update_file_header_t))
		{
			perror ("File I/O error on input file");
			goto closeall;
		}
		lseek(ifd, image_head.header_size, SEEK_SET);
		imglen =image_head.payload_size;
		file_offset +=image_head.header_size;
	}
	*image_length = imglen;

	pagelen = meminfo.writesize + ((writeoob == 1) ? meminfo.oobsize : 0);

	// Check, if file is pagealigned
	if ((!pad) && ((imglen % pagelen) != 0)) {
		fprintf (stderr, "Input file is not page aligned\n");
		goto closeall;
	}

	// Check, if length fits into device
	if ( ((imglen / pagelen) * meminfo.writesize) > (meminfo.size - mtdoffset)) {
		fprintf (stderr, "Image %zu bytes, NAND page %d bytes, OOB area %u bytes, device size %u bytes\n",
				imglen, pagelen, meminfo.writesize, meminfo.size);
		perror ("Input file does not fit into device");
		goto closeall;
	}
/* Get data from input and write to the device */
	while (imglen && (mtdoffset < meminfo.size)) {
		// new eraseblock , check for bad block(s)
		// Stay in the loop to be sure if the mtdoffset changes because
		// of a bad block, that the next block that will be written to
		// is also checked. Thus avoiding errors if the block(s) after the
		// skipped block(s) is also bad (number of blocks depending on
		// the blockalign
		while (blockstart != (mtdoffset & (~meminfo.erasesize + 1))) {
			blockstart = mtdoffset & (~meminfo.erasesize + 1);
			offs = blockstart;
			baderaseblock = 0;
			if (!quiet)
				fprintf (stdout, "Writing data to block %x\n", blockstart);

			/* Check all the blocks in an erase block for bad blocks */
			do {
				if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
					perror("ioctl(MEMGETBADBLOCK)");
					goto closeall;
				}
				if (ret == 1) {
					baderaseblock = 1;
					if (!quiet)
	fprintf (stderr, "Bad block at %x, %u block(s) "
								"from %x will be skipped\n",
								(int) offs, blockalign, blockstart);
				}

				if (baderaseblock) {
					mtdoffset = blockstart + meminfo.erasesize;
				}
				offs +=  meminfo.erasesize / blockalign ;
			} while ( offs < blockstart + meminfo.erasesize );
		}
readlen = meminfo.writesize;
		if (pad && (imglen < readlen))
		{
			readlen = imglen;
			memset(ptr_update_G->writebuf + readlen, 0xff, meminfo.writesize - readlen);
		}

		/* Read Page Data from input file */
		if ((cnt = pread(ifd, ptr_update_G->writebuf, readlen,file_offset)) != readlen) {
			if (cnt == 0)	// EOF
				break;
			perror ("File I/O error on input file");
			goto closeall;
		}

		*image_crc = crc32(*image_crc, ptr_update_G->writebuf, cnt);

		if (writeoob) {
			int i, start, len, filled;
			/* Read OOB data from input file, exit on failure */
			if ((cnt = pread(ifd, ptr_update_G->oobreadbuf, meminfo.oobsize,file_offset)) != meminfo.oobsize) {
				perror ("File I/O error on input file");
				goto closeall;
			}
			/*
			 *  We use autoplacement and have the oobinfo with the autoplacement
			 * information from the kernel available
			 *
			 * Modified to support out of order oobfree segments,
			 * such as the layout used by diskonchip.c
			 */
			if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) {
				for (filled = 0, i = 0; old_oobinfo.oobfree[i][1] && (i < MTD_MAX_OOBFREE_ENTRIES); i++) {
					/* Set the reserved bytes to 0xff */
					start = old_oobinfo.oobfree[i][0];
					len = old_oobinfo.oobfree[i][1];
					memcpy(ptr_update_G->oobbuf + start,
						ptr_update_G->oobreadbuf + filled,
						len);
					filled += len;
				}
			} else {
				/* Set at least the ecc byte positions to 0xff */
				start = old_oobinfo.eccbytes;
				len = meminfo.oobsize - start;
				memcpy(ptr_update_G->oobbuf + start,
					ptr_update_G->oobreadbuf + start,
					len);
			}
			/* Write OOB data first, as ecc will be placed in there*/
			oob.start = mtdoffset;
			if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
				perror ("ioctl(MEMWRITEOOB)");
				goto closeall;
			}
			imglen -= meminfo.oobsize;
		}

		/* Write out the Page data */
		if (pwrite(fd, ptr_update_G->writebuf, meminfo.writesize, mtdoffset) != meminfo.writesize) {
			perror ("pwrite");
			goto closeall;
		}	/* read out the Page data */
		if (pread(fd, readbuf, meminfo.writesize, mtdoffset) != meminfo.writesize) {
			perror ("pread");
			goto closeall;
		}

		buf_num=0;
		while ((ptr_update_G->writebuf[buf_num]==readbuf[buf_num]) && (buf_num < readlen)) buf_num++;

		//if (((blockstart/MAX_PAGE_SIZE/64) % 10) == 9)
		if (buf_num < readlen)
		{
			//printf("offs[%x ],blockstart[%x],mtdoffset[%x],writesize[0x%x], buf_num[0x%x]\n",(int)offs,blockstart,mtdoffset,meminfo.writesize, buf_num);

			/* set bad blocks */
			offs = (loff_t) blockstart;
			if ((ret = ioctl(fd, MEMSETBADBLOCK, &offs)) < 0) {
				perror("ioctl(MEMSETBADBLOCK)");
				goto closeall;
			}
			if (ret == 0) {
				if (!quiet)
					fprintf (stdout, "set Bad block at %x !\n",blockstart);
				file_offset = file_offset - (mtdoffset-blockstart);
				imglen = imglen+ (mtdoffset-blockstart);;
				mtdoffset = blockstart + meminfo.erasesize;
			}
		} else {
			imglen -= readlen;
			mtdoffset += meminfo.writesize;
			file_offset+= meminfo.writesize;
		}
	}


	closeall:
		close(ifd);
		ifd = -1;

	restoreoob:

		close(fd);
		if (imglen > 0) {
			perror ("Data was only partially written due to error\n");
			exit (1);
		}

		*image_crc ^= ~0U;
		printf ("FLASH image_length = 0x%zx\n", *image_length);
		printf ("FLASH image_crc = 0x%08x\n", *image_crc);
		free(ptr_update_G);
}

static const char *short_options = "b:fjopqs:ytd:KMRBGA:HQIUWXYZC:c:F:L:S:D:V:E:N:B:P:";
static struct option long_options[] = {
	{"jffs2", no_argument, 0, 'j'},
	{"yaffs", no_argument, 0, 'y'},
	{"forcelegacy", no_argument, 0, 'f'},
	{"oob", no_argument, 0, 'o'},
	{"start", required_argument, 0, 's'},
	{"pad", no_argument, 0, 'p'},
	{"blockalign", required_argument, 0, 'b'},
	{"quiet", no_argument, 0, 'q'},
	{"skiphead", no_argument, 0, 't'},
	{"help", no_argument, 0, HELP},
	{"version", no_argument, 0, VERSION_INFO},
	{"fdt", required_argument, 0, 'd'},

	{"bld", no_argument, 0, 'G'},
	{"ptb", required_argument, 0, 'A'},
};

static void process_options (int argc, char *argv[])
{
	int error = 0;
	int ch;
	int option_index = 0;
	while ((ch = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
		switch (ch) {
			case HELP:
				usage();
				break;
			case VERSION_INFO:
				display_version();
				break;
			case AUTO_DOWNLOAD:
				ambarella_auto_dl = 1;
				ambarella_auto_dl_data=strtoul (optarg, NULL, 0);
				ambarella_skip_img = 1;
				break;
			case AUTO_BOOT:
				ambarella_auto_boot = 1;
				ambarella_auto_boot_data=strtoul (optarg, NULL, 0);
				ambarella_skip_img = 1;
				break;
			case PRI_ADDR:
				ambarella_pri_addr = 1;
				ambarella_pri_addr_data = strtoul (optarg, NULL, 0);
				ambarella_skip_img = 1;
				break;
			case PRI_FILE:
				ambarella_pri_file = 1;
				strncpy(ambarella_pri_file_data, optarg, SN_SIZE - 1);
				ambarella_pri_file_data[SN_SIZE - 1] = '\0';
				ambarella_skip_img = 1;
				break;

		}
	}

	if ((((argc - optind) != 2) && (ambarella_skip_img != 1)) || error)
		usage ();

	if ((argc - optind) == 2) {
		mtd_device = argv[optind++];
		img = argv[optind];
		ambarella_skip_img = 0;
	}
}

举报

相关推荐

0 条评论