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

📄 nand.c

📁 linux嵌入式课程实践中的一个关于声卡驱动程序 。
💻 C
📖 第 1 页 / 共 3 页
字号:
#else	return nand_read_ecc (mtd, from, len, retlen, buf, NULL);#endif}/* * NAND read with ECC */static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,			  size_t * retlen, u_char * buf, u_char * ecc_code){	int j, col, page;	int erase_state = 0;	int ecc_status = 0, ecc_failed = 0;	struct nand_chip *this = mtd->priv;	u_char *data_poi;#ifdef CONFIG_MTD_NAND_ECC	u_char ecc_calc[6];#endif	DEBUG (MTD_DEBUG_LEVEL3, "nand_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, "nand_read_ecc: Attempt read beyond end of device\n");		*retlen = 0;		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_chip (this, FL_READING, &erase_state);	/* First we calculate the starting page */	page = from >> this->page_shift;	/* Get raw starting column */	col = from & (mtd->oobblock - 1);	/* Initialize return value */	*retlen = 0;	/* Select the NAND device */	nand_select ();	/* Loop until all data read */	while (*retlen < len) {#ifdef CONFIG_MTD_NAND_ECC		/* Do we have this page in cache ? */		if (this->cache_page == page)			goto readdata;		/* Send the read command */		this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);		/* Read in a page + oob data */		for (j = 0; j < mtd->oobblock + mtd->oobsize; j++)			this->data_buf[j] = readb (this->IO_ADDR_R);		this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);		/* copy data into cache, for read out of cache and if ecc fails */		if (this->data_cache)			memcpy (this->data_cache, this->data_buf, mtd->oobblock + mtd->oobsize);		/* Pick the ECC bytes out of the oob data */		for (j = 0; j < 6; j++)			ecc_code[j] = this->data_buf[(mtd->oobblock + oob_config.ecc_pos[j])];		/* Calculate the ECC and verify it */		/* If block was not written with ECC, skip ECC */		if (oob_config.eccvalid_pos != -1 &&		    (this->data_buf[mtd->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) {			nand_calculate_ecc (&this->data_buf[0], &ecc_calc[0]);			switch (nand_correct_data (&this->data_buf[0], &ecc_code[0], &ecc_calc[0])) {			case -1:				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);				ecc_failed++;				break;			case 1:			case 2:	/* transfer ECC corrected data to cache */				memcpy (this->data_cache, this->data_buf, 256);				break;			}		}		if (oob_config.eccvalid_pos != -1 &&		    mtd->oobblock == 512 && (this->data_buf[mtd->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) {			nand_calculate_ecc (&this->data_buf[256], &ecc_calc[3]);			switch (nand_correct_data (&this->data_buf[256], &ecc_code[3], &ecc_calc[3])) {			case -1:				DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);				ecc_failed++;				break;			case 1:			case 2:	/* transfer ECC corrected data to cache */				if (this->data_cache)					memcpy (&this->data_cache[256], &this->data_buf[256], 256);				break;			}		}readdata:		/* Read the data from ECC data buffer into return buffer */		data_poi = (this->data_cache) ? this->data_cache : this->data_buf;		data_poi += col;		if ((*retlen + (mtd->oobblock - col)) >= len) {			while (*retlen < len)				buf[(*retlen)++] = *data_poi++;		} else {			for (j = col; j < mtd->oobblock; j++)				buf[(*retlen)++] = *data_poi++;		}		/* Set cache page address, invalidate, if ecc_failed */		this->cache_page = (this->data_cache && !ecc_failed) ? page : -1;		ecc_status += ecc_failed;		ecc_failed = 0;#else		/* Send the read command */		this->cmdfunc (mtd, NAND_CMD_READ0, col, page);		/* Read the data directly into the return buffer */		if ((*retlen + (mtd->oobblock - col)) >= len) {			while (*retlen < len)				buf[(*retlen)++] = readb (this->IO_ADDR_R);			/* We're done */			continue;		} else			for (j = col; j < mtd->oobblock; j++)				buf[(*retlen)++] = readb (this->IO_ADDR_R);#endif		/* For subsequent reads align to page boundary. */		col = 0;		/* Increment page address */		page++;	}	/* De-select the NAND device */	nand_deselect ();	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	/*	 * Return success, if no ECC failures, else -EIO	 * fs driver will take care of that, because	 * retlen == desired len and result == -EIO	 */	return ecc_status ? -EIO : 0;}/* * NAND read out-of-band */static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){	int i, col, page;	int erase_state = 0;	struct nand_chip *this = mtd->priv;	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);	/* Shift to get page */	page = ((int) from) >> this->page_shift;	/* Mask to get column */	col = from & 0x0f;	/* Initialize return length value */	*retlen = 0;	/* Do not allow reads past end of device */	if ((from + len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n");		*retlen = 0;		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_chip (this, FL_READING, &erase_state);	/* can we read out of cache ? */	if (this->cache_page == page && (col + len <= mtd->oobsize)) {		/* Read the data */		memcpy (buf, &this->data_cache[mtd->oobblock + col], len);	} else {		/* Select the NAND device */		nand_select ();		/* Send the read command */		this->cmdfunc (mtd, NAND_CMD_READOOB, col, page);		/* 		 * Read the data, if we read more than one page		 * oob data, let the device transfer the data !		 */		for (i = 0; i < len; i++) {			buf[i] = readb (this->IO_ADDR_R);			if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1))				udelay (this->chip_delay);		}		/* De-select the NAND device */		nand_deselect ();	}	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	/* Return happy */	*retlen = len;	return 0;}/* * NAND write */static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){#ifdef CONFIG_MTD_NAND_ECC	struct nand_chip *this = mtd->priv;	return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf);#else	return nand_write_ecc (mtd, to, len, retlen, buf, NULL);#endif}/* * 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 * ecc_code){	int i, page, col, cnt, ret = 0;	struct nand_chip *this = mtd->priv;	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);	/* Do not allow write past end of device */	if ((to + len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_chip (this, FL_WRITING, NULL);	/* Shift to get page */	page = ((int) to) >> this->page_shift;	/* Get the starting column */	col = to & (mtd->oobblock - 1);	/* Initialize return length value */	*retlen = 0;	/* Select the NAND device */	nand_select ();	/* Check the WP bit */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	if (!(readb (this->IO_ADDR_R) & 0x80)) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n");		ret = -EIO;		goto out;	}	/* Loop until all data is written */	while (*retlen < len) {		/* Invalidate cache, if we write to this page */		if (this->cache_page == page)			this->cache_page = -1;		/* Write data into buffer */		if ((col + len) >= mtd->oobblock)			for (i = col, cnt = 0; i < mtd->oobblock; i++, cnt++)				this->data_buf[i] = buf[(*retlen + cnt)];		else			for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++)				this->data_buf[i] = buf[(*retlen + cnt)];		/* We use the same function for write and writev !) */		ret = nand_write_page (mtd, this, page, col, i, ecc_code);		if (ret)			goto out;		/* Next data start at page boundary */		col = 0;		/* Update written bytes count */		*retlen += cnt;		/* Increment page address */		page++;	}	/* Return happy */	*retlen = len;out:	/* De-select the NAND device */	nand_deselect ();	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	return ret;}/* * NAND write out-of-band */static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf){	int i, column, page, status, ret = 0;	struct nand_chip *this = mtd->priv;	DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len);	/* Shift to get page */	page = ((int) to) >> this->page_shift;	/* Mask to get column */	column = to & 0x1f;	/* Initialize return length value */	*retlen = 0;	/* Do not allow write past end of page */	if ((column + len) > mtd->oobsize) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n");		return -EINVAL;	}	/* Grab the lock and see if the device is available */	nand_get_chip (this, FL_WRITING, NULL);	/* Select the NAND device */	nand_select ();	/* Check the WP bit */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	if (!(readb (this->IO_ADDR_R) & 0x80)) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n");		ret = -EIO;		goto out;	}	/* Invalidate cache, if we write to this page */	if (this->cache_page == page)		this->cache_page = -1;	/* Write ones for partial page programming */	for (i = mtd->oobblock; i < (mtd->oobblock + mtd->oobsize); i++)		this->data_buf[i] = 0xff;	/* Transfer data */	for (i = 0; i < len; i++)		this->data_buf[i + mtd->oobblock + column] = buf[i];	/* Write out desired data */	this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page);	for (i = 0; i < mtd->oobsize; i++)		writeb (this->data_buf[i + mtd->oobblock], this->IO_ADDR_W);	/* Send command to program the OOB data */	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);	status = this->waitfunc (mtd, this, FL_WRITING);	/* See if device thinks it succeeded */	if (status & 0x01) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);		ret = -EIO;		goto out;	}#ifdef CONFIG_MTD_NAND_VERIFY_WRITE	/* Send command to read back the data */	this->cmdfunc (mtd, NAND_CMD_READOOB, column, page);	/* Loop through and verify the data */	for (i = 0; i < len; i++) {		if (buf[i] != readb (this->IO_ADDR_R)) {			DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page);			ret = -EIO;			goto out;		}	}#endif	/* Return happy */	*retlen = len;out:	/* De-select the NAND device */	nand_deselect ();	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);

⌨️ 快捷键说明

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