封装了nand flash写函数

使用nandwrite的代码,封装为满足我们使用的代码

 

 

 

/*
 *  nandwrite.c
 *
 *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
 *		  2003 Thomas Gleixner (tglx@linutronix.de)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * Overview:
 *   This utility writes a binary image directly to a NAND flash
 *   chip or NAND chips contained in DoC devices. This is the
 *   "inverse operation" of nanddump.
 *
 * tglx: Major rewrite to handle bad blocks, write data with or without ECC
 *	 write oob data only on request
 *
 * Bug/ToDo:
 */

#define PROGRAM_NAME "nandwrite"
#define VERSION "$Revision: 1.32 {1}quot;

#define _GNU_SOURCE
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <getopt.h>

#include <asm/types.h>
#include "mtd/mtd-user.h"
#include "common.h"
#include "libmtd.h"

#ifdef DEBUG_THIS
#define dprintf printf
#else
#define dprintf
#endif



// oob layouts to pass into the kernel as default
static struct nand_oobinfo none_oobinfo = {
	.useecc = MTD_NANDECC_OFF,
};

static struct nand_oobinfo jffs2_oobinfo = {
	.useecc = MTD_NANDECC_PLACE,
	.eccbytes = 6,
	.eccpos = { 0, 1, 2, 3, 6, 7 }
};

static struct nand_oobinfo yaffs_oobinfo = {
	.useecc = MTD_NANDECC_PLACE,
	.eccbytes = 6,
	.eccpos = { 8, 9, 10, 13, 14, 15}
};

static struct nand_oobinfo autoplace_oobinfo = {
	.useecc = MTD_NANDECC_AUTOPLACE
};

static void erase_buffer(void *buffer, size_t size)
{
	const uint8_t kEraseByte = 0xff;

	if (buffer != NULL && size > 0) {
		memset(buffer, kEraseByte, size);
	}
}

typedef struct
{
	bool writeoob;
	int blockalign;
	bool pad;
	bool autoplace;
	bool noecc;
	bool forcejffs2;
	bool forceyaffs;
	bool noskipbad;
	const char *img;
	bool quiet;
	bool rawoob;
	bool forcelegacy;
	bool onlyoob;
	bool markbad;
}nand_other_opt;
#define USE_EXAMPLE
#ifdef USE_EXAMPLE
int main(void)
{
	unsigned long len = 0;
	unsigned char *buf = NULL;
	dprintf("ready to nand_flash_write 1\n");

	FILE *fp = NULL;
	fp = fopen("/root/mtd7bin","rb");
	if(fp == NULL)
	{
		printf("open file error\n");
		return -1;
	}
	fseek(fp,0,SEEK_END);
	len = ftell(fp);
	fseek(fp,0,SEEK_SET);
	buf = malloc(len);
	fread(buf,len,1,fp);
	dprintf("len = %d\n",len);
	jwtnand_flash_write("/dev/mtd7",(long long)0,len,buf);
	if(buf != NULL)
	free(buf);
	if(fp != NULL)
		fclose(fp);
	return 0;
}
#endif

int jwtnand_flash_write(const char *mtd_device,long long jwtoffset,unsigned long len,unsigned char *buf)
{
	nand_other_opt jwtnand_opt;
	jwtnand_opt.writeoob = false;
	jwtnand_opt.blockalign = 1;
	jwtnand_opt.autoplace = false;
	jwtnand_opt.noecc = false;
	jwtnand_opt.forcejffs2 = false;
	jwtnand_opt.forceyaffs = false;
	jwtnand_opt.noskipbad = false;
	jwtnand_opt.img = NULL;
	jwtnand_opt.quiet = false;
	jwtnand_opt.rawoob = false;
	jwtnand_opt.pad = true;
	jwtnand_opt.forcelegacy = false;
	jwtnand_opt.onlyoob = false;
	jwtnand_opt.markbad = false;
	dprintf("offset :0x%x\n",jwtoffset);
	nand_flash_write(mtd_device,jwtoffset,len,buf,jwtnand_opt);
}
	
int nand_flash_write(const char* mtd_device,long long jwtoffset,unsigned long len,unsigned char *buf,nand_other_opt jwtnand_opt)
{

	bool pad;
	bool writeoob;
	int	blockalign;
	long long mtdoffset;
	bool autoplace;
	bool noecc;
	bool forcejffs2;
	bool forceyaffs;
	bool forcelegacy;
	char *img;
	bool quiet;
	bool noskipbad;
	bool rawoob;
	bool onlyoob;
	bool markbad;
	
	int cnt = 0;
	int fd = -1;
	int ifd = -1;
	int imglen = 0, pagelen;
	bool baderaseblock = false;
	long long blockstart = -1;
	struct mtd_dev_info mtd;
	long long offs;
	int ret;
	int oobinfochanged = 0;
	struct nand_oobinfo old_oobinfo;
	bool failed = true;
	// contains all the data read from the file so far for the current eraseblock
	unsigned char *filebuf = NULL;
	size_t filebuf_max = 0;
	size_t filebuf_len = 0;
	// points to the current page inside filebuf
	unsigned char *writebuf = NULL;
	// points to the OOB for the current page in filebuf
	unsigned char *oobreadbuf = NULL;
	unsigned char *oobbuf = NULL;
	libmtd_t mtd_desc;
	int ebsize_aligned;
//	jieen
	nand_other_opt *jwtnand_ptr = &jwtnand_opt;

	pad = jwtnand_ptr->pad;
	writeoob = jwtnand_ptr->writeoob;
	blockalign = jwtnand_ptr->blockalign;
	mtdoffset = jwtoffset;
	autoplace = jwtnand_ptr->autoplace;
	noecc = jwtnand_ptr->noecc;
	forcejffs2 = jwtnand_ptr->forcejffs2;
	forceyaffs = jwtnand_ptr->forceyaffs;
	forcelegacy = jwtnand_ptr->forcelegacy;
	img = (char *)jwtnand_ptr->img;
	quiet = jwtnand_ptr->quiet;
	noskipbad = jwtnand_ptr->noskipbad;
	rawoob = jwtnand_ptr->rawoob;
	onlyoob = jwtnand_ptr->onlyoob;
	markbad = jwtnand_ptr->markbad;

	dprintf("pad:%d,writeoob:%d,onlyoob:%d img:%d,len:%d\n",pad,writeoob,onlyoob,(img == NULL),len);
	if (!onlyoob && (pad && writeoob)){
		fprintf(stderr, "Can't pad when oob data is present.\n");
		return -1;;
	}

	/* Open the device */
	if ((fd = open(mtd_device, O_RDWR)) == -1) {
		perror(mtd_device);
		return -1;
	}
	mtd_desc = libmtd_open();
	if (!mtd_desc)
		return errmsg("can't initialize libmtd");
	/* Fill in MTD device capability structure */

	if (mtd_get_dev_info(mtd_desc, mtd_device, &mtd) < 0)
		return errmsg("mtd_get_dev_info failed");

	/*
	 * Pretend erasesize is specified number of blocks - to match jffs2
	 *   (virtual) block size
	 * Use this value throughout unless otherwise necessary
	 */
	ebsize_aligned = mtd.eb_size * blockalign;

	if (mtdoffset & (mtd.min_io_size - 1)) {
		fprintf(stderr, "The start address is not page-aligned !\n"
				"The pagesize of this NAND Flash is 0x%x.\n",
				mtd.min_io_size);
		close(fd);
		exit(EXIT_FAILURE);
	}

	if (autoplace) {
		/* Read the current oob info */
		if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
			perror("MEMGETOOBSEL");
			close(fd);
			return -1;
		}

		// autoplace ECC ?
		if (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE) {
			if (ioctl(fd, MEMSETOOBSEL, &autoplace_oobinfo) != 0) {
				perror("MEMSETOOBSEL");
				close(fd);
				return -1;
			}
			oobinfochanged = 1;
		}
	}

	if (noecc)  {
		ret = ioctl(fd, MTDFILEMODE, MTD_MODE_RAW);
		if (ret == 0) {
			oobinfochanged = 2;
		} else {
			switch (errno) {
			case ENOTTY:
				if (ioctl(fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
					perror("MEMGETOOBSEL");
					close(fd);
					return -1;
				}
				if (ioctl(fd, MEMSETOOBSEL, &none_oobinfo) != 0) {
					perror("MEMSETOOBSEL");
					close(fd);
					return -1;
				}
				oobinfochanged = 1;
				break;
			default:
				perror("MTDFILEMODE");
				close(fd);
				return -1;
			}
		}
	}

	/*
	 * force oob layout for jffs2 or yaffs ?
	 * Legacy support
	 */
	if (forcejffs2 || forceyaffs) {
		struct nand_oobinfo *oobsel = forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;

		if (autoplace) {
			fprintf(stderr, "Autoplacement is not possible for legacy -j/-y options\n");
			goto restoreoob;
		}
		if ((old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) && !forcelegacy) {
			fprintf(stderr, "Use -f option to enforce legacy placement on autoplacement enabled mtd device\n");
			goto restoreoob;
		}
		if (mtd.oob_size == 8) {
			if (forceyaffs) {
				fprintf(stderr, "YAFSS cannot operate on 256 Byte page size");
				goto restoreoob;
			}
			/* Adjust number of ecc bytes */
			jffs2_oobinfo.eccbytes = 3;
		}

		if (ioctl(fd, MEMSETOOBSEL, oobsel) != 0) {
			perror("MEMSETOOBSEL");
			goto restoreoob;
		}
	}
	
	dprintf("img : %x,mtd.size:%d\n",img,mtd.size);
	/* Determine if we are reading from standard input or from a file. */
	if(img == NULL)
	{
		ifd == -1;
	}
	else if (strcmp(img, "-") == 0) {
		ifd = STDIN_FILENO;
	} else
	{
		dprintf("ready to open file %s\n",img);
		ifd = open(img, O_RDONLY);
		if(ifd == -1)
		{
			fprintf(stderr,"open file %s error\n",img);
			return -1;
		}
	}
	pagelen = mtd.min_io_size + ((writeoob) ? mtd.oob_size : 0);

	/*
	 * For the standard input case, the input size is merely an
	 * invariant placeholder and is set to the write page
	 * size. Otherwise, just use the input file size.
	 *
	 * TODO: Add support for the -l,--length=length option (see
	 * previous discussion by Tommi Airikka <tommi.airikka@ericsson.com> at
	 * <http://lists.infradead.org/pipermail/linux-mtd/2008-September/
	 * 022913.html>
	 */
	if(ifd == -1)
	{
		imglen = len;
	}
	else if (ifd == STDIN_FILENO) 
	{
	    imglen = pagelen;
	}
	else
	{
	    imglen = lseek(ifd, 0, SEEK_END);
	    lseek(ifd, 0, SEEK_SET);
	}
	
	// Check, if file is page-aligned
	if ((!pad) && ((imglen % pagelen) != 0)) {
		fprintf(stderr, "Input file is not page-aligned. Use the padding "
				 "option.\n");
		goto closeall;
	}

	dprintf("mtdoffset = 0x%x ;imglen = %d,pagelen= %d;mtd.size:%d\n\n",mtdoffset,imglen,pagelen,mtd.size);
	// Check, if length fits into device	
	if (((imglen / pagelen) * mtd.min_io_size) > (mtd.size - mtdoffset)) {
		fprintf(stderr, "Image %d bytes, NAND page %d bytes, OOB area %d"
				" bytes, device size %lld bytes\n",
				imglen, pagelen, mtd.oob_size, mtd.size);
		perror("Input file does not fit into device");
		goto closeall;
	}
	/*
	 * Allocate a buffer big enough to contain all the data (OOB included)
	 * for one eraseblock. The order of operations here matters; if ebsize
	 * and pagelen are large enough, then "ebsize_aligned * pagelen" could
	 * overflow a 32-bit data type.
	 */
	filebuf_max = ebsize_aligned / mtd.min_io_size * pagelen;
	filebuf = xmalloc(filebuf_max);
	erase_buffer(filebuf, filebuf_max);

	oobbuf = xmalloc(mtd.oob_size);
	erase_buffer(oobbuf, mtd.oob_size);
	/*
	 * Get data from input and write to the device while there is
	 * still input to read and we are still within the device
	 * bounds. Note that in the case of standard input, the input
	 * length is simply a quasi-boolean flag whose values are page
	 * length or zero.
	 */
	while (((imglen > 0) || (writebuf < (filebuf + filebuf_len)))
		&& (mtdoffset < mtd.size)) {
		/*
		 * New eraseblock, check for bad block(s)
		 * Stay in the loop to be sure that, if mtdoffset changes because
		 * of a bad block, the next block that will be written to
		 * is also checked. Thus, we avoid errors if the block(s) after the
		 * skipped block(s) is also bad (number of blocks depending on
		 * the blockalign).
		 */
		while (blockstart != (mtdoffset & (~ebsize_aligned + 1))) {
			blockstart = mtdoffset & (~ebsize_aligned + 1);
			offs = blockstart;

			// if writebuf == filebuf, we are rewinding so we must not
			// reset the buffer but just replay it
			if (writebuf != filebuf) {
				erase_buffer(filebuf, filebuf_len);
				filebuf_len = 0;
				writebuf = filebuf;
			}

			baderaseblock = false;
			if (!quiet)
				fprintf(stdout, "Writing data to block %lld at offset 0x%llx\n",
						 blockstart / ebsize_aligned, blockstart);

			/* Check all the blocks in an erase block for bad blocks */
			if (noskipbad)
				continue;
			do {
				if ((ret = mtd_is_bad(&mtd, fd, offs / ebsize_aligned)) < 0) {
					sys_errmsg("%s: MTD get bad block failed", mtd_device);
					goto closeall;
				} else if (ret == 1) {
					baderaseblock = true;
					if (!quiet)
						fprintf(stderr, "Bad block at %llx, %u block(s) "
								"from %llx will be skipped\n",
								offs, blockalign, blockstart);
				}

				if (baderaseblock) {
					mtdoffset = blockstart + ebsize_aligned;
				}
				offs +=  ebsize_aligned / blockalign;
			} while (offs < blockstart + ebsize_aligned);

		}

		// Read more data from the input if there isn't enough in the buffer
		if ((writebuf + mtd.min_io_size) > (filebuf + filebuf_len)) {
			int readlen = mtd.min_io_size;

			int alreadyread = (filebuf + filebuf_len) - writebuf;
			int tinycnt = alreadyread;

			while (tinycnt < readlen) {
				if(img != NULL)
				{
					cnt = read(ifd, writebuf + tinycnt, readlen - tinycnt);
					if (cnt == 0) { // EOF
						break;
					} else if (cnt < 0) {
						perror("File I/O error on input");
						goto closeall;
					}
					tinycnt += cnt;
				}else
				{
					memcpy(writebuf+tinycnt,buf+tinycnt,pagelen);
					tinycnt += pagelen;
				}
			}

			/* No padding needed - we are done */
			if (tinycnt == 0) {
				/*
				 * For standard input, set imglen to 0 to signal
				 * the end of the "file". For nonstandard input,
				 * leave it as-is to detect an early EOF.
				 */
				if (ifd == STDIN_FILENO) {
					imglen = 0;
				}
				break;
			}

			/* Padding */
			if (tinycnt < readlen) {
				if (!pad) {
					fprintf(stderr, "Unexpected EOF. Expecting at least "
							"%d more bytes. Use the padding option.\n",
							readlen - tinycnt);
					goto closeall;
				}
				erase_buffer(writebuf + tinycnt, readlen - tinycnt);
			}

			filebuf_len += readlen - alreadyread;
			if (ifd != STDIN_FILENO) {
				imglen -= tinycnt - alreadyread;
			}
			else if (cnt == 0) {
				/* No more bytes - we are done after writing the remaining bytes */
				imglen = 0;
			}
		}

		if (writeoob) {
			oobreadbuf = writebuf + mtd.min_io_size;

			// Read more data for the OOB from the input if there isn't enough in the buffer
			if ((oobreadbuf + mtd.oob_size) > (filebuf + filebuf_len)) {
				int readlen = mtd.oob_size;
				int alreadyread = (filebuf + filebuf_len) - oobreadbuf;
				int tinycnt = alreadyread;

				while (tinycnt < readlen) {
					if(img != NULL)
					{
						cnt = read(ifd, oobreadbuf + tinycnt, readlen - tinycnt);
						if (cnt == 0) { // EOF
							break;
						} else if (cnt < 0) {
							perror("File I/O error on input");
							goto closeall;
						}
						tinycnt += cnt;
					}else
					{
						memcpy(oobreadbuf+tinycnt,buf+tinycnt,mtd.oob_size);
						tinycnt += mtd.oob_size;
					}
				}

				if (tinycnt < readlen) {
					fprintf(stderr, "Unexpected EOF. Expecting at least "
							"%d more bytes for OOB\n", readlen - tinycnt);
					goto closeall;
				}

				filebuf_len += readlen - alreadyread;
				if (ifd != STDIN_FILENO) {
					imglen -= tinycnt - alreadyread;
				}
				else if (cnt == 0) {
					/* No more bytes - we are done after writing the remaining bytes */
					imglen = 0;
				}
			}

			if (!noecc) {
				int i, start, len;
				int tags_pos = 0;
				/*
				 * 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 (i = 0; old_oobinfo.oobfree[i][1]; i++) {
						/* Set the reserved bytes to 0xff */
						start = old_oobinfo.oobfree[i][0];
						len = old_oobinfo.oobfree[i][1];
						if (rawoob)
							memcpy(oobbuf + start,
									oobreadbuf + start, len);
						else
							memcpy(oobbuf + start,
									oobreadbuf + tags_pos, len);
						tags_pos += len;
					}
				} else {
					/* Set at least the ecc byte positions to 0xff */
					start = old_oobinfo.eccbytes;
					len = mtd.oob_size - start;
					memcpy(oobbuf + start,
							oobreadbuf + start,
							len);
				}
			}
			/* Write OOB data first, as ecc will be placed in there */
			if (mtd_write_oob(mtd_desc, &mtd, fd, mtdoffset,
						mtd.oob_size,
						noecc ? oobreadbuf : oobbuf)) {
				sys_errmsg("%s: MTD writeoob failure", mtd_device);
				goto closeall;
			}
		}

		/* Write out the Page data */
		if (!onlyoob && mtd_write(&mtd, fd, mtdoffset / mtd.eb_size, mtdoffset % mtd.eb_size,
					writebuf, mtd.min_io_size)) {
			int i;
			if (errno != EIO) {
				sys_errmsg("%s: MTD write failure", mtd_device);
				goto closeall;
			}

			/* Must rewind to blockstart if we can */
			writebuf = filebuf;

			fprintf(stderr, "Erasing failed write from %#08llx to %#08llx\n",
				blockstart, blockstart + ebsize_aligned - 1);
			for (i = blockstart; i < blockstart + ebsize_aligned; i += mtd.eb_size) {
				if (mtd_erase(mtd_desc, &mtd, fd, mtd.eb_size)) {
					int errno_tmp = errno;
					sys_errmsg("%s: MTD Erase failure", mtd_device);
					if (errno_tmp != EIO) {
						goto closeall;
					}
				}
			}

			if (markbad) {
				fprintf(stderr, "Marking block at %08llx bad\n",
						mtdoffset & (~mtd.eb_size + 1));
				if (mtd_mark_bad(&mtd, fd, mtdoffset / mtd.eb_size)) {
					sys_errmsg("%s: MTD Mark bad block failure", mtd_device);
					goto closeall;
				}
			}
			mtdoffset = blockstart + ebsize_aligned;

			continue;
		}
		mtdoffset += mtd.min_io_size;
		writebuf += pagelen;
	}

	failed = false;

closeall:
	if(ifd != -1)
	{
		close(ifd);
	}

restoreoob:
	libmtd_close(mtd_desc);
	free(filebuf);
	free(oobbuf);

	if (oobinfochanged == 1) {
		if (ioctl(fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
			perror("MEMSETOOBSEL");
			close(fd);
			return -1;
		}
	}

	close(fd);

	if (failed) {
		perror("Data was only partially written due to error\n");
		return -1;
	}

	/* Return happy */
	return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值