⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand_base.c

📁 项目源码察看工具---- MTD工具
💻 C
📖 第 1 页 / 共 5 页
字号:
				/* Walk through the autoplace chunks */				for (i = 0; oobsel->oobfree[i][1]; i++) {					int from = oobsel->oobfree[i][0];					int num = oobsel->oobfree[i][1];					memcpy(&oob_buf[oob], &oob_data[from], num);					oob += num;				}				break;			case MTD_NANDECC_PLACE:				/* YAFFS1 legacy mode */				oob_data += this->eccsteps * sizeof (int);			default:				oob_data += mtd->oobsize;			}		}	readdata:		/* Partial page read, transfer data into fs buffer */		if (!aligned) {			for (j = col; j < end && read < len; j++)				buf[read++] = data_poi[j];			this->pagebuf = realpage;		} else			read += mtd->oobblock;		/* Apply delay or wait for ready/busy pin		 * Do this before the AUTOINCR check, so no problems		 * arise if a chip which does auto increment		 * is marked as NOAUTOINCR by the board driver.		*/		if (!this->dev_ready)			udelay (this->chip_delay);		else			nand_wait_ready(mtd);		if (read == len)			break;		/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		realpage++;		page = realpage & this->pagemask;		/* Check, if we cross a chip boundary */		if (!page) {			chipnr++;			this->select_chip(mtd, -1);			this->select_chip(mtd, chipnr);		}		/* Check, if the chip supports auto page increment		 * or if we have hit a block boundary.		*/		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))			sndcmd = 1;	}	/* Deselect and wake up anyone waiting on the device */	if (flags & NAND_GET_DEVICE)		nand_release_device(mtd);	/*	 * Return success, if no ECC failures, else -EBADMSG	 * fs driver will take care of that, because	 * retlen == desired len and result == -EBADMSG	 */	*retlen = read;	return ecc_failed ? -EBADMSG : 0;}/** * nand_read_oob - [MTD Interface] NAND read out-of-band * @mtd:	MTD device structure * @from:	offset to read from * @len:	number of bytes to read * @retlen:	pointer to variable to store the number of read bytes * @buf:	the databuffer to put data * * NAND read out-of-band data from the spare area */static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * oob_buf){	int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1, reallen = 0;	int read = 0;	struct nand_chip *this = mtd->priv;	u_char *oob_data = oob_buf;        int 	eccsteps;	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;	DEBUG (MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", __FUNCTION__, (unsigned int) from, (int) len);	/* Do not allow reads past end of device */	if ((from + len) > mtd->size) {		*retlen = 0;		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_device (this, mtd, FL_READING);	/* Select the NAND device */	chipnr = (int)(from >> this->chip_shift);	this->select_chip(mtd, chipnr);	/* First we calculate the starting page */	realpage = (int) (from >> this->page_shift);	page = realpage & this->pagemask;	/* Get raw starting column */	col = from & (mtd->oobblock - 1);	end = mtd->oobblock;	ecc = this->eccsize;	/* Loop until all data read */	while (read < len) {		if (this->eccmode == NAND_ECC_SOFT || this->eccmode == NAND_ECC_NONE) {			int thislen = mtd->oobsize - col;			if (sndcmd) {				this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);				col = 0;				sndcmd = 0;			}			thislen = min_t(int, thislen, len);			this->read_buf(mtd, &oob_buf[read], thislen);			read += thislen;		} else {			/* Check, if we must send the read command */			if (sndcmd) {				this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);				sndcmd = 0;			}			eccsteps = this->eccsteps;			for (j = 0; this->layout[j].length; j++) {				i = 0;				switch (this->layout[j].type) {				case ITEM_TYPE_DATA:					DEBUG (MTD_DEBUG_LEVEL3, "%s: dummy data read\n", __FUNCTION__);					reallen += this->layout[j].length;					if (this->options & NAND_BUSWIDTH_16)						this->cmdfunc (mtd, NAND_CMD_READ0, reallen & ~1, page);					else						this->cmdfunc (mtd, NAND_CMD_READ0, reallen, page);					break;				case ITEM_TYPE_ECC:				case ITEM_TYPE_OOB:					DEBUG (MTD_DEBUG_LEVEL3, "%s: %s bytes read\n", __FUNCTION__, this->layout[j].type == ITEM_TYPE_ECC ? "ecc" : "oob");					i = min_t(int, col, this->layout[j].length);					if (i) {						reallen += i;						if (this->options & NAND_BUSWIDTH_16)							this->cmdfunc (mtd, NAND_CMD_READ0, reallen & ~1, page);						else							this->cmdfunc (mtd, NAND_CMD_READ0, reallen, page);					}					col -= i;					if (this->layout[j].type == ITEM_TYPE_ECC)						this->enable_hwecc(mtd, NAND_ECC_READSYN);					else						this->enable_hwecc(mtd, NAND_ECC_READOOB);					i = min_t(int, len - read, this->layout[j].length - i);					if (i) {						if (this->options & NAND_BUSWIDTH_16) {							if (reallen & 1) {								oob_data[0] = cpu_to_le16(this->read_word(mtd)) >> 8;								oob_data++; i--; reallen++;							}							if (i & 1)								this->read_buf(mtd, oob_data, i - 1);							else								this->read_buf(mtd, oob_data, i); 						}						else							this->read_buf(mtd, oob_data, i);						reallen += i;					}					if (oob_buf + len == oob_data + i) {						read += i;						goto out;	 				}					break; 				}				read += i;				oob_data += i;			}		}out:		/* Apply delay or wait for ready/busy pin		 * Do this before the AUTOINCR check, so no problems		 * arise if a chip which does auto increment		 * is marked as NOAUTOINCR by the board driver.		*/		if (!this->dev_ready)			udelay (this->chip_delay);		else			nand_wait_ready(mtd);		if (read == len)			break;		/* For subsequent reads align to page boundary. */		reallen = col = 0;		/* Increment page address */		realpage++;		page = realpage & this->pagemask;		/* Check, if we cross a chip boundary */		if (!page) {			chipnr++;			this->select_chip(mtd, -1);			this->select_chip(mtd, chipnr);		}		/* Check, if the chip supports auto page increment		 * or if we have hit a block boundary.		*/		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))			sndcmd = 1;	}	/* Deselect and wake up anyone waiting on the device */	nand_release_device(mtd);	*retlen = read;	/*	 * Return success	 */	return 0;}/** * nand_read_raw - [GENERIC] Read raw data including oob into buffer * @mtd:	MTD device structure * @buf:	temporary buffer * @from:	offset to read from * @len:	number of bytes to read * @ooblen:	number of oob data bytes to read * * Read raw data including oob into buffer */int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len, size_t ooblen){	struct nand_chip *this = mtd->priv;	int page = (int) (from >> this->page_shift);	int chip = (int) (from >> this->chip_shift);	int sndcmd = 1;	int cnt = 0;	int pagesize = mtd->oobblock + mtd->oobsize;	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;	/* Do not allow reads past end of device */	if ((from + len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_raw: Attempt read beyond end of device\n");		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_device (this, mtd , FL_READING);	this->select_chip (mtd, chip);	/* Add requested oob length */	len += ooblen;	while (len) {		if (sndcmd)			this->cmdfunc (mtd, NAND_CMD_READ0, 0, page & this->pagemask);		sndcmd = 0;		this->read_buf (mtd, &buf[cnt], pagesize);		len -= pagesize;		cnt += pagesize;		page++;		if (!this->dev_ready)			udelay (this->chip_delay);		else			nand_wait_ready(mtd);		/* Check, if the chip supports auto page increment */		if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))			sndcmd = 1;	}	/* Deselect and wake up anyone waiting on the device */	nand_release_device(mtd);	return 0;}/** * nand_prepare_oobbuf - [GENERIC] Prepare the out of band buffer * @mtd:	MTD device structure * @fsbuf:	buffer given by fs driver * @oobsel:	out of band selection structre * @autoplace:	1 = place given buffer into the oob bytes * @numpages:	number of pages to prepare * * Return: * 1. Filesystem buffer available and autoplacement is off, *    return filesystem buffer * 2. No filesystem buffer or autoplace is off, return internal *    buffer * 3. Filesystem buffer is given and autoplace selected *    put data from fs buffer into internal buffer and *    retrun internal buffer * * Note: The internal buffer is filled with 0xff. This must * be done only once, when no autoplacement happens * Autoplacement sets the buffer dirty flag, which * forces the 0xff fill before using the buffer again. **/static u_char * nand_prepare_oobbuf (struct mtd_info *mtd, u_char *fsbuf, struct nand_oobinfo *oobsel,		int autoplace, int numpages){	struct nand_chip *this = mtd->priv;	int i, len, ofs;	/* Zero copy fs supplied buffer */	if (fsbuf && !autoplace)		return fsbuf;	/* Check, if the buffer must be filled with ff again */	if (this->oobdirty) {		memset (this->oob_buf, 0xff,			mtd->oobsize << (this->phys_erase_shift - this->page_shift));		this->oobdirty = 0;	}	/* If we have no autoplacement or no fs buffer use the internal one */	if (!autoplace || !fsbuf)		return this->oob_buf;	/* Walk through the pages and place the data */	this->oobdirty = 1;	ofs = 0;	while (numpages--) {		for (i = 0, len = 0; len < mtd->oobavail; i++) {			int to = ofs + oobsel->oobfree[i][0];			int num = oobsel->oobfree[i][1];			memcpy (&this->oob_buf[to], fsbuf, num);			len += num;			fsbuf += num;		}		ofs += mtd->oobavail;	}	return this->oob_buf;}#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0/** * nand_write - [MTD Interface] compability function for nand_write_ecc * @mtd:	MTD device structure * @to:		offset to write to * @len:	number of bytes to write * @retlen:	pointer to variable to store the number of written bytes * @buf:	the data to write * * This function simply calls nand_write_ecc with oob buffer and oobsel = NULL **/static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){	return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL));}/** * nand_write_ecc - [MTD Interface] NAND write with ECC * @mtd:	MTD device structure * @to:		offset to write to * @len:	number of bytes to write * @retlen:	pointer to variable to store the number of written bytes * @buf:	the data to write * @eccbuf:	filesystem supplied oob data buffer * @oobsel:	oob selection structure * * NAND write with ECC */static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,			   size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel){	int startpage, page, ret = -EIO, oob = 0, written = 0, chipnr;	int autoplace = 0, numpages, totalpages;	struct nand_chip *this = mtd->priv;	u_char *oobbuf, *bufstart;	int	ppblock = (1 << (this->phys_erase_shift - this->page_shift));	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);	/* Initialize retlen, in case of early exit */	*retlen = 0;	/* Do not allow write past end of device */	if ((to + len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n");		return -EINVAL;	}	/* reject writes, which are not page aligned */	if (NOTALIGNED (to) || NOTALIGNED(len)) {		printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n");		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_device (this, mtd, FL_WRITING);	/* Calculate chipnr */	chipnr = (int)(to >> this->chip_shift);	/* Select the NAND device */	this->select_chip(mtd, chipnr);	/* Check, if it is write protected */	if (nand_check_wp(mtd))		goto out;	/* if oobsel is NULL, use chip defaults */	if (oobsel == NULL)		oobsel = &mtd->oobinfo;	/* Autoplace of oob data ? Use the default placement scheme */	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) {		oobsel = this->autooob;		autoplace = 1;	}	if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)		autoplace = 1;	/* Setup variables and oob buffer */	totalpages = len >> this->page_shift;	page = (int) (to >> this->page_shift);	/* Invalidate the page cache, if we write to the cached page */	if (page <= this->pagebuf && this->pagebuf < (page + totalpages))		this->pagebuf = -1;	/* Set it relative to chip */	page &= this->pagemask;	startpage = page;	/* Calc number of pages we can write in one go */	numpages = min (ppblock - (startpage  & (ppblock - 1)), totalpages);	oobbuf = nand_prepare_oobbuf (mtd, eccbuf, oobsel, autoplace, numpages);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -