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

📄 nand_base.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
					roffs -= free->length;					continue;				}				boffs = free->offset + roffs;				bytes = min_t(size_t, len,					      (free->length - roffs));				roffs = 0;			} else {				bytes = min_t(size_t, len, free->length);				boffs = free->offset;			}			memcpy(oob, chip->oob_poi + boffs, bytes);			oob += bytes;		}		return oob;	}	default:		BUG();	}	return NULL;}/** * nand_do_read_ops - [Internal] Read data with ECC * * @mtd:	MTD device structure * @from:	offset to read from * @ops:	oob ops structure * * Internal function. Called with chip held. */static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,			    struct mtd_oob_ops *ops){	int chipnr, page, realpage, col, bytes, aligned;	struct nand_chip *chip = mtd->priv;	struct mtd_ecc_stats stats;	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;	int sndcmd = 1;	int ret = 0;	uint32_t readlen = ops->len;	uint32_t oobreadlen = ops->ooblen;	uint8_t *bufpoi, *oob, *buf;	stats = mtd->ecc_stats;	chipnr = (int)(from >> chip->chip_shift);	chip->select_chip(mtd, chipnr);	realpage = (int)(from >> chip->page_shift);	page = realpage & chip->pagemask;	col = (int)(from & (mtd->writesize - 1));	buf = ops->datbuf;	oob = ops->oobbuf;	while(1) {		bytes = min(mtd->writesize - col, readlen);		aligned = (bytes == mtd->writesize);		/* Is the current page in the buffer ? */		if (realpage != chip->pagebuf || oob) {			bufpoi = aligned ? buf : chip->buffers->databuf;			if (likely(sndcmd)) {				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);				sndcmd = 0;			}			/* Now read the page into the buffer */			if (unlikely(ops->mode == MTD_OOB_RAW))				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);			else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)				ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);			else				ret = chip->ecc.read_page(mtd, chip, bufpoi);			if (ret < 0)				break;			/* Transfer not aligned data */			if (!aligned) {				if (!NAND_SUBPAGE_READ(chip) && !oob)					chip->pagebuf = realpage;				memcpy(buf, chip->buffers->databuf + col, bytes);			}			buf += bytes;			if (unlikely(oob)) {				/* Raw mode does data:oob:data:oob */				if (ops->mode != MTD_OOB_RAW) {					int toread = min(oobreadlen,						chip->ecc.layout->oobavail);					if (toread) {						oob = nand_transfer_oob(chip,							oob, ops, toread);						oobreadlen -= toread;					}				} else					buf = nand_transfer_oob(chip,						buf, ops, mtd->oobsize);			}			if (!(chip->options & NAND_NO_READRDY)) {				/*				 * 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 (!chip->dev_ready)					udelay(chip->chip_delay);				else					nand_wait_ready(mtd);			}		} else {			memcpy(buf, chip->buffers->databuf + col, bytes);			buf += bytes;		}		readlen -= bytes;		if (!readlen)			break;		/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		realpage++;		page = realpage & chip->pagemask;		/* Check, if we cross a chip boundary */		if (!page) {			chipnr++;			chip->select_chip(mtd, -1);			chip->select_chip(mtd, chipnr);		}		/* Check, if the chip supports auto page increment		 * or if we have hit a block boundary.		 */		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))			sndcmd = 1;	}	ops->retlen = ops->len - (size_t) readlen;	if (oob)		ops->oobretlen = ops->ooblen - oobreadlen;	if (ret)		return ret;	if (mtd->ecc_stats.failed - stats.failed)		return -EBADMSG;	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;}/** * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc * @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 * * Get hold of the chip and call nand_do_read */static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,		     size_t *retlen, uint8_t *buf){	struct nand_chip *chip = mtd->priv;	int ret;	/* Do not allow reads past end of device */	if ((from + len) > mtd->size)		return -EINVAL;	if (!len)		return 0;	nand_get_device(chip, mtd, FL_READING);	chip->ops.len = len;	chip->ops.datbuf = buf;	chip->ops.oobbuf = NULL;	ret = nand_do_read_ops(mtd, from, &chip->ops);	*retlen = chip->ops.retlen;	nand_release_device(mtd);	return ret;}/** * nand_read_oob_std - [REPLACABLE] the most common OOB data read function * @mtd:	mtd info structure * @chip:	nand chip info structure * @page:	page number to read * @sndcmd:	flag whether to issue read command or not */static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,			     int page, int sndcmd){	if (sndcmd) {		chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);		sndcmd = 0;	}	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);	return sndcmd;}/** * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC *			    with syndromes * @mtd:	mtd info structure * @chip:	nand chip info structure * @page:	page number to read * @sndcmd:	flag whether to issue read command or not */static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,				  int page, int sndcmd){	uint8_t *buf = chip->oob_poi;	int length = mtd->oobsize;	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;	int eccsize = chip->ecc.size;	uint8_t *bufpoi = buf;	int i, toread, sndrnd = 0, pos;	chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);	for (i = 0; i < chip->ecc.steps; i++) {		if (sndrnd) {			pos = eccsize + i * (eccsize + chunk);			if (mtd->writesize > 512)				chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);			else				chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);		} else			sndrnd = 1;		toread = min_t(int, length, chunk);		chip->read_buf(mtd, bufpoi, toread);		bufpoi += toread;		length -= toread;	}	if (length > 0)		chip->read_buf(mtd, bufpoi, length);	return 1;}/** * nand_write_oob_std - [REPLACABLE] the most common OOB data write function * @mtd:	mtd info structure * @chip:	nand chip info structure * @page:	page number to write */static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,			      int page){	int status = 0;	const uint8_t *buf = chip->oob_poi;	int length = mtd->oobsize;	chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);	chip->write_buf(mtd, buf, length);	/* Send command to program the OOB data */	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);	status = chip->waitfunc(mtd, chip);	return status & NAND_STATUS_FAIL ? -EIO : 0;}/** * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC *			     with syndrome - only for large page flash ! * @mtd:	mtd info structure * @chip:	nand chip info structure * @page:	page number to write */static int nand_write_oob_syndrome(struct mtd_info *mtd,				   struct nand_chip *chip, int page){	int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;	int eccsize = chip->ecc.size, length = mtd->oobsize;	int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;	const uint8_t *bufpoi = chip->oob_poi;	/*	 * data-ecc-data-ecc ... ecc-oob	 * or	 * data-pad-ecc-pad-data-pad .... ecc-pad-oob	 */	if (!chip->ecc.prepad && !chip->ecc.postpad) {		pos = steps * (eccsize + chunk);		steps = 0;	} else		pos = eccsize;	chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);	for (i = 0; i < steps; i++) {		if (sndcmd) {			if (mtd->writesize <= 512) {				uint32_t fill = 0xFFFFFFFF;				len = eccsize;				while (len > 0) {					int num = min_t(int, len, 4);					chip->write_buf(mtd, (uint8_t *)&fill,							num);					len -= num;				}			} else {				pos = eccsize + i * (eccsize + chunk);				chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);			}		} else			sndcmd = 1;		len = min_t(int, length, chunk);		chip->write_buf(mtd, bufpoi, len);		bufpoi += len;		length -= len;	}	if (length > 0)		chip->write_buf(mtd, bufpoi, length);	chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);	status = chip->waitfunc(mtd, chip);	return status & NAND_STATUS_FAIL ? -EIO : 0;}/** * nand_do_read_oob - [Intern] NAND read out-of-band * @mtd:	MTD device structure * @from:	offset to read from * @ops:	oob operations description structure * * NAND read out-of-band data from the spare area */static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,			    struct mtd_oob_ops *ops){	int page, realpage, chipnr, sndcmd = 1;	struct nand_chip *chip = mtd->priv;	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;	int readlen = ops->ooblen;	int len;	uint8_t *buf = ops->oobbuf;	DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",	      (unsigned long long)from, readlen);	if (ops->mode == MTD_OOB_AUTO)		len = chip->ecc.layout->oobavail;	else		len = mtd->oobsize;	if (unlikely(ops->ooboffs >= len)) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "			"Attempt to start read outside oob\n");		return -EINVAL;	}	/* Do not allow reads past end of device */	if (unlikely(from >= mtd->size ||		     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -					(from >> chip->page_shift)) * len)) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "			"Attempt read beyond end of device\n");		return -EINVAL;	}	chipnr = (int)(from >> chip->chip_shift);	chip->select_chip(mtd, chipnr);	/* Shift to get page */	realpage = (int)(from >> chip->page_shift);	page = realpage & chip->pagemask;	while(1) {		sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);		len = min(len, readlen);		buf = nand_transfer_oob(chip, buf, ops, len);		if (!(chip->options & NAND_NO_READRDY)) {			/*			 * 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 (!chip->dev_ready)				udelay(chip->chip_delay);			else				nand_wait_ready(mtd);		}		readlen -= len;		if (!readlen)			break;		/* Increment page address */		realpage++;		page = realpage & chip->pagemask;		/* Check, if we cross a chip boundary */		if (!page) {			chipnr++;			chip->select_chip(mtd, -1);			chip->select_chip(mtd, chipnr);		}		/* Check, if the chip supports auto page increment		 * or if we have hit a block boundary.		 */		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))			sndcmd = 1;	}	ops->oobretlen = ops->ooblen;	return 0;}/** * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band * @mtd:	MTD device structure * @from:	offset to read from * @ops:	oob operation description structure * * NAND read data and/or out-of-band data */static int nand_read_oob(struct mtd_info *mtd, loff_t from,			 struct mtd_oob_ops *ops){	struct nand_chip *chip = mtd->priv;	int ret = -ENOTSUPP;	ops->retlen = 0;	/* Do not allow reads past end of device */	if (ops->datbuf && (from + ops->len) > mtd->size) {		DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "		      "Attempt read beyond end of device\n");		return -EINVAL;	}	nand_get_device(chip, mtd, FL_READING);	switch(ops->mode) {	case MTD_OOB_PLACE:	case MTD_OOB_AUTO:	case MTD_OOB_RAW:		break;	default:		goto out;	}	if (!ops->datbuf)		ret = nand_do_read_oob(mtd, from, ops);	else		ret = nand_do_read_ops(mtd, from, ops); out:	nand_release_device(mtd);	return ret;}/** * nand_write_page_raw - [Intern] raw page write function * @mtd:	mtd info structure * @chip:	nand chip info structure * @buf:	data buffer */static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,				const uint8_t *buf){	chip->write_buf(mtd, buf, mtd->writesize);	chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);}/** * nand_write_page_swecc - [REPLACABLE] software ecc based page write function * @mtd:	mtd info structure * @chip:	nand chip info structure * @buf:	data buffer */static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,				  const uint8_t *buf){	int i, eccsize = chip->ecc.size;	int eccbytes = chip->ecc.bytes;	int eccsteps = chip->ecc.steps;	uint8_t *ecc_calc = chip->buffers->ecccalc;	const uint8_t *p = buf;

⌨️ 快捷键说明

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