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

📄 nand.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	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 */		nand_command (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);		nand_command (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 */		nand_command (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);	if (erase_state)		this->state = FL_ERASING;	else		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 */		nand_command (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);	if (erase_state)		this->state = FL_ERASING;	else		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 */	nand_command (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 */	nand_command (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 */	nand_command (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 */	nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);	/*	 * Wait for program operation to complete. This could	 * take up to 3000us (3ms) on some devices, so we try	 * and exit as quickly as possible.	 */	status = 0;	for (i=0 ; i<24 ; i++) {		/* Delay for 125us */		udelay (125);		/* Check the status */		if (this->dev_ready) 			if (!this->dev_ready())				continue;		/* Check the status */		nand_command (mtd, NAND_CMD_STATUS, -1, -1);		status = (int) readb (this->IO_ADDR_R);		if (status & 0x40)			break;	}	/* 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 */	nand_command (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);	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);

⌨️ 快捷键说明

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