(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;
}
}