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

📄 onenand_base.c

📁 老版本的mtd-snap
💻 C
📖 第 1 页 / 共 3 页
字号:
			spin_unlock(&this->chip_lock);			break;		}		set_current_state(TASK_UNINTERRUPTIBLE);		add_wait_queue(&this->wq, &wait);		spin_unlock(&this->chip_lock);		schedule();		remove_wait_queue(&this->wq, &wait);	}}/** * onenand_release_device - [GENERIC] release chip * @param mtd		MTD device structure * * Deselect, release chip lock and wake up anyone waiting on the device */static void onenand_release_device(struct mtd_info *mtd){	struct onenand_chip *this = mtd->priv;	/* Release the chip */	spin_lock(&this->chip_lock);	this->state = FL_READY;	wake_up(&this->wq);	spin_unlock(&this->chip_lock);}/** * onenand_read_ecc - [MTD Interface] Read data with ECC * @param mtd		MTD device structure * @param from		offset to read from * @param len		number of bytes to read * @param retlen	pointer to variable to store the number of read bytes * @param buf		the databuffer to put data * @param oob_buf	filesystem supplied oob data buffer * @param oobsel	oob selection structure * * OneNAND read with ECC */static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,	size_t *retlen, u_char *buf,	u_char *oob_buf, struct nand_oobinfo *oobsel){	struct onenand_chip *this = mtd->priv;	int read = 0, column;	int thislen;	int ret = 0;	DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);	/* Do not allow reads past end of device */	if ((from + len) > mtd->size) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: Attempt read beyond end of device\n");		*retlen = 0;		return -EINVAL;	}	/* Grab the lock and see if the device is available */	onenand_get_device(mtd, FL_READING);	/* TODO handling oob */	while (read < len) {		thislen = min_t(int, mtd->oobblock, len - read);		column = from & (mtd->oobblock - 1);		if (column + thislen > mtd->oobblock)			thislen = mtd->oobblock - column;		if (!onenand_check_bufferram(mtd, from)) {			this->command(mtd, ONENAND_CMD_READ, from, mtd->oobblock);			ret = this->wait(mtd, FL_READING);			/* First copy data and check return value for ECC handling */			onenand_update_bufferram(mtd, from, 1);		}		this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);		read += thislen;		if (read == len)			break;		if (ret) {			DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_ecc: read failed = %d\n", ret);			goto out;		}		from += thislen;		buf += thislen;	}out:	/* Deselect and wake up anyone waiting on the device */	onenand_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 ret;}/** * onenand_read - [MTD Interface] MTD compability function for onenand_read_ecc * @param mtd		MTD device structure * @param from		offset to read from * @param len		number of bytes to read * @param retlen	pointer to variable to store the number of read bytes * @param buf		the databuffer to put data * * This function simply calls onenand_read_ecc with oob buffer and oobsel = NULL*/static int onenand_read(struct mtd_info *mtd, loff_t from, size_t len,	size_t *retlen, u_char *buf){	return onenand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);}/** * onenand_read_oob - [MTD Interface] OneNAND read out-of-band * @param mtd		MTD device structure * @param from		offset to read from * @param len		number of bytes to read * @param retlen	pointer to variable to store the number of read bytes * @param buf		the databuffer to put data * * OneNAND read out-of-band data from the spare area */static int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,	size_t *retlen, u_char *buf){	struct onenand_chip *this = mtd->priv;	int read = 0, thislen, column;	int ret = 0;	DEBUG(MTD_DEBUG_LEVEL3, "onenand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);	/* Initialize return length value */	*retlen = 0;	/* Do not allow reads past end of device */	if (unlikely((from + len) > mtd->size)) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: Attempt read beyond end of device\n");		return -EINVAL;	}	/* Grab the lock and see if the device is available */	onenand_get_device(mtd, FL_READING);	column = from & (mtd->oobsize - 1);	while (read < len) {		thislen = mtd->oobsize - column;		thislen = min_t(int, thislen, len);		this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);		onenand_update_bufferram(mtd, from, 0);		ret = this->wait(mtd, FL_READING);		/* First copy data and check return value for ECC handling */		this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);		read += thislen;		if (read == len)			break;		if (ret) {			DEBUG(MTD_DEBUG_LEVEL0, "onenand_read_oob: read failed = %d\n", ret);			goto out;		}		buf += thislen;		/* Read more? */		if (read < len) {			/* Page size */			from += mtd->oobblock;			column = 0;		}	}out:	/* Deselect and wake up anyone waiting on the device */	onenand_release_device(mtd);	*retlen = read;	return ret;}#ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE/** * onenand_verify_page - [GENERIC] verify the chip contents after a write * @param mtd		MTD device structure * @param buf		the databuffer to verify * @param block		block address * @param page		page address * * Check DataRAM area directly */static int onenand_verify_page(struct mtd_info *mtd, u_char *buf,	loff_t addr, int block, int page){	struct onenand_chip *this = mtd->priv;	void __iomem *dataram0, *dataram1;	int ret = 0;	this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock);	ret = this->wait(mtd, FL_READING);	if (ret)		return ret;	onenand_update_bufferram(mtd, addr, 1);	/* Check, if the two dataram areas are same */	dataram0 = this->base + ONENAND_DATARAM;	dataram1 = dataram0 + mtd->oobblock;	if (memcmp(dataram0, dataram1, mtd->oobblock))		return -EBADMSG;		return 0;}#else#define onenand_verify_page(...)	(0)#endif#define NOTALIGNED(x)	((x & (mtd->oobblock - 1)) != 0)/** * onenand_write_ecc - [MTD Interface] OneNAND write with ECC * @param mtd		MTD device structure * @param to		offset to write to * @param len		number of bytes to write * @param retlen	pointer to variable to store the number of written bytes * @param buf		the data to write * @param eccbuf	filesystem supplied oob data buffer * @param oobsel	oob selection structure * * OneNAND write with ECC */static int onenand_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){	struct onenand_chip *this = mtd->priv;	int written = 0;	int ret = 0;	DEBUG(MTD_DEBUG_LEVEL3, "onenand_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 writes past end of device */	if (unlikely((to + len) > mtd->size)) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt write to past end of device\n");		return -EINVAL;	}	/* Reject writes, which are not page aligned */        if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(len))) {                DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: Attempt to write not page aligned data\n");                return -EINVAL;        }	/* Grab the lock and see if the device is available */	onenand_get_device(mtd, FL_WRITING);	/* Loop until all data write */	while (written < len) {		int thislen = min_t(int, mtd->oobblock, len - written);		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock);		this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen);		this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);		this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock);		onenand_update_bufferram(mtd, to, 1);		ret = this->wait(mtd, FL_WRITING);		if (ret) {			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: write filaed %d\n", ret);			goto out;		}		written += thislen;		/* Only check verify write turn on */		ret = onenand_verify_page(mtd, (u_char *) buf, to, block, page);		if (ret) {			DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_ecc: verify failed %d\n", ret);			goto out;		}		if (written == len)			break;		to += thislen;		buf += thislen;	}out:	/* Deselect and wake up anyone waiting on the device */	onenand_release_device(mtd);	*retlen = written;		return ret;}/** * onenand_write - [MTD Interface] compability function for onenand_write_ecc * @param mtd		MTD device structure * @param to		offset to write to * @param len		number of bytes to write * @param retlen	pointer to variable to store the number of written bytes * @param buf		the data to write * * This function simply calls onenand_write_ecc * with oob buffer and oobsel = NULL */static int onenand_write(struct mtd_info *mtd, loff_t to, size_t len,	size_t *retlen, const u_char *buf){	return onenand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);}/** * onenand_write_oob - [MTD Interface] OneNAND write out-of-band * @param mtd		MTD device structure * @param to		offset to write to * @param len		number of bytes to write * @param retlen	pointer to variable to store the number of written bytes * @param buf		the data to write * * OneNAND write out-of-band */static int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,	size_t *retlen, const u_char *buf){	struct onenand_chip *this = mtd->priv;	int column, status;	int written = 0;	DEBUG(MTD_DEBUG_LEVEL3, "onenand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);	/* Initialize retlen, in case of early exit */	*retlen = 0;	/* Do not allow writes past end of device */	if (unlikely((to + len) > mtd->size)) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_write_oob: Attempt write to past end of device\n");		return -EINVAL;	}	/* Grab the lock and see if the device is available */	onenand_get_device(mtd, FL_WRITING);	/* Loop until all data write */	while (written < len) {		int thislen = min_t(int, mtd->oobsize, len - written);		column = to & (mtd->oobsize - 1);		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobsize);		this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0, mtd->oobsize);		this->write_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen);		this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);		onenand_update_bufferram(mtd, to, 0);		status = this->wait(mtd, FL_WRITING);		if (status)			goto out;		written += thislen;		if (written == len)			break;		to += thislen;		buf += thislen;	}out:	/* Deselect and wake up anyone waiting on the device */	onenand_release_device(mtd);	*retlen = written;		return 0;}/** * onenand_writev_ecc - [MTD Interface] write with iovec with ecc * @param mtd		MTD device structure * @param vecs		the iovectors to write * @param count		number of vectors * @param to		offset to write to * @param retlen	pointer to variable to store the number of written bytes * @param eccbuf	filesystem supplied oob data buffer * @param oobsel	oob selection structure * * OneNAND write with iovec with ecc */static int onenand_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,	unsigned long count, loff_t to, size_t *retlen,	u_char *eccbuf, struct nand_oobinfo *oobsel){	struct onenand_chip *this = mtd->priv;	unsigned char buffer[mtd->oobblock], *pbuf;	size_t total_len, len;	int i, written = 0;	int ret = 0;	/* Preset written len for early exit */	*retlen = 0;	/* Calculate total length of data */	total_len = 0;	for (i = 0; i < count; i++)		total_len += vecs[i].iov_len;	DEBUG(MTD_DEBUG_LEVEL3, "onenand_writev_ecc: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count);	/* Do not allow write past end of the device */	if (unlikely((to + total_len) > mtd->size)) {		DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempted write past end of device\n");		return -EINVAL;	}	/* Reject writes, which are not page aligned */        if (unlikely(NOTALIGNED(to)) || unlikely(NOTALIGNED(total_len))) {                DEBUG(MTD_DEBUG_LEVEL0, "onenand_writev_ecc: Attempt to write not page aligned data\n");                return -EINVAL;        }	/* Grab the lock and see if the device is available */	onenand_get_device(mtd, FL_WRITING);	/* TODO handling oob */		/* Loop until all keve's data has been written */	len = 0;	while (count) {		pbuf = buffer;		/* 		 * If the given tuple is >= pagesize then		 * write it out from the iov		 */		if ((vecs->iov_len - len) >= mtd->oobblock) {			pbuf = vecs->iov_base + len;			len += mtd->oobblock;			/* Check, if we have to switch to the next tuple */			if (len >= (int) vecs->iov_len) {				vecs++;				len = 0;				count--;			}		} else {			int cnt = 0, thislen;			while (cnt < mtd->oobblock) {				thislen = min_t(int, mtd->oobblock - cnt, vecs->iov_len - len);				memcpy(buffer + cnt, vecs->iov_base + len, thislen);				cnt += thislen;				len += thislen;				/* Check, if we have to switch to the next tuple */				if (len >= (int) vecs->iov_len) {					vecs++;					len = 0;					count--;				}

⌨️ 快捷键说明

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