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

📄 nand.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
			this->data_buf[cnt++] =				((u_char *) vecs->iov_base)[len++];			if (len >= (int) vecs->iov_len) {				vecs++;				len = 0;				count--;			}		}				/* Do any need post-fill for partial page programming */		for (i=cnt ; i < mtd->oobblock ; i++)			this->data_buf[i] = 0xff;#ifdef CONFIG_MTD_NAND_ECC		/* Zero out the ECC array */		for (i=0 ; i < 6 ; i++)			this->ecc_code_buf[i] = 0x00;		/* Calculate and write the first ECC */		if (col >= mtd->eccsize) {			nand_command (mtd, NAND_CMD_READ0, col, page);			for (i=0 ; i < col ; i++)				this->data_buf[i] = readb (this->IO_ADDR); 			nand_calculate_ecc (&this->data_buf[0],				&(this->ecc_code_buf[0]));			for (i=0 ; i<3 ; i++)				this->data_buf[(mtd->oobblock + i)] =					this->ecc_code_buf[i];		}		/* Calculate and write the second ECC */		if ((mtd->oobblock == 512) && (cnt == mtd->oobblock)) {			nand_calculate_ecc (&this->data_buf[256],				&(this->ecc_code_buf[3]));			for (i=3 ; i<6 ; i++)				this->data_buf[(mtd->oobblock + i)] =					this->ecc_code_buf[i];		}		/* Write ones for partial page programming */		for (i=ecc_bytes ; i < mtd->oobsize ; i++)			this->data_buf[(mtd->oobblock + i)] = 0xff;#else		/* Write ones for partial page programming */		for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)			this->data_buf[i] = 0xff;#endif		/* Send command to begin auto page programming */		nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);		/* Write out complete page of data */		for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)			writeb (this->data_buf[i], this->IO_ADDR);		/* Send command to actually program the 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 */			nand_command (mtd, NAND_CMD_STATUS, -1, -1);			status = (int) readb (this->IO_ADDR);			if (status & 0x40)				break;		}		/* See if device thinks it succeeded */		if (status & 0x01) {			DEBUG (MTD_DEBUG_LEVEL0,				"nand_writev: " \				"Failed write, page 0x%08x, " \				"%6i bytes were succesful\n", page, *retlen);			nand_deselect ();			spin_lock_bh (&this->chip_lock);			this->state = FL_READY;			wake_up (&this->wq);			spin_unlock_bh (&this->chip_lock);			return -EIO;		}#ifdef CONFIG_MTD_NAND_VERIFY_WRITE		/*		 * The NAND device assumes that it is always writing to		 * a cleanly erased page. Hence, it performs its internal		 * write verification only on bits that transitioned from		 * 1 to 0. The device does NOT verify the whole page on a		 * byte by byte basis. It is possible that the page was		 * not completely erased or the page is becoming unusable		 * due to wear. The read with ECC would catch the error		 * later when the ECC page check fails, but we would rather		 * catch it early in the page write stage. Better to write		 * no data than invalid data.		 */				/* Send command to read back the page */		if (col < mtd->eccsize)			nand_command (mtd, NAND_CMD_READ0, col, page);		else			nand_command (mtd, NAND_CMD_READ1, col - 256, page);		/* Loop through and verify the data */		for (i=col ; i < cnt ; i++) {			if (this->data_buf[i] != readb (this->IO_ADDR)) {				DEBUG (MTD_DEBUG_LEVEL0,					"nand_writev: " \					"Failed write verify, page 0x%08x, " \					"%6i bytes were succesful\n",					page, *retlen);				nand_deselect ();				spin_lock_bh (&this->chip_lock);				this->state = FL_READY;				wake_up (&this->wq);				spin_unlock_bh (&this->chip_lock);				return -EIO;			}		}#ifdef CONFIG_MTD_NAND_ECC		/*		 * We also want to check that the ECC bytes wrote		 * correctly for the same reasons stated above.		 */		nand_command (mtd, NAND_CMD_READOOB, 0x00, page);		for (i=0 ; i < ecc_bytes ; i++) {			if ((readb (this->IO_ADDR) != this->ecc_code_buf[i]) &&					this->ecc_code_buf[i]) {				DEBUG (MTD_DEBUG_LEVEL0,					"nand_writev: Failed ECC write " \					"verify, page 0x%08x, " \					"%6i bytes were succesful\n",					page, i);				nand_deselect ();				spin_lock_bh (&this->chip_lock);				this->state = FL_READY;				wake_up (&this->wq);				spin_unlock_bh (&this->chip_lock);				return -EIO;			}		}#endif#endif		/* Update written bytes count */		*retlen += (cnt - col);		/* Reset written byte counter and column */		col = cnt = 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 happy */	return 0;}/* * NAND erase a block */static int nand_erase (struct mtd_info *mtd, struct erase_info *instr){	int i, page, len, status, pages_per_block;	struct nand_chip *this = mtd->priv;	DECLARE_WAITQUEUE(wait, current);	DEBUG (MTD_DEBUG_LEVEL3,		"nand_erase: start = 0x%08x, len = %i\n",		(unsigned int) instr->addr, (unsigned int) instr->len);	/* Start address must align on block boundary */	if (instr->addr & (mtd->erasesize - 1)) {		DEBUG (MTD_DEBUG_LEVEL0,			"nand_erase: Unaligned address\n");		return -EINVAL;	}	/* Length must align on block boundary */	if (instr->len & (mtd->erasesize - 1)) {		DEBUG (MTD_DEBUG_LEVEL0,			"nand_erase: Length not block aligned\n");		return -EINVAL;	}	/* Do not allow erase past end of device */	if ((instr->len + instr->addr) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0,			"nand_erase: Erase past end of device\n");		return -EINVAL;	}retry:	/* Grab the lock and see if the device is available */	spin_lock_bh (&this->chip_lock);	switch (this->state) {	case FL_READY:		this->state = FL_ERASING;		break;	default:		set_current_state (TASK_UNINTERRUPTIBLE);		add_wait_queue (&this->wq, &wait);		spin_unlock_bh (&this->chip_lock);		schedule();		remove_wait_queue (&this->wq, &wait);		goto retry;	};	/* Shift to get first page */	page = (int) (instr->addr >> this->page_shift);	/* Calculate pages in each block */	pages_per_block = mtd->erasesize / mtd->oobblock;	/* Select the NAND device */	nand_select ();	/* Check the WP bit */	nand_command (mtd, NAND_CMD_STATUS, -1, -1);	if (!(readb (this->IO_ADDR) & 0x80)) {		DEBUG (MTD_DEBUG_LEVEL0,			"nand_erase: Device is write protected!!!\n");		nand_deselect ();		this->state = FL_READY;		spin_unlock_bh (&this->chip_lock);		return -EIO;	}	/* Loop through the pages */	len = instr->len;	while (len) {		/* Send commands to erase a page */		nand_command(mtd, NAND_CMD_ERASE1, -1, page);		nand_command(mtd, NAND_CMD_ERASE2, -1, -1);		/*		 * Wait for program operation to complete. This could		 * take up to 4000us (4ms) on some devices, so we try		 * and exit as quickly as possible.		 */		status = 0;		for (i=0 ; i<32 ; i++) {			/* Delay for 125us */			udelay (125);			/* Check the status */			nand_command (mtd, NAND_CMD_STATUS, -1, -1);			status = (int) readb (this->IO_ADDR);			if (status & 0x40)				break;		}		/* See if block erase succeeded */		if (status & 0x01) {			DEBUG (MTD_DEBUG_LEVEL0,				"nand_erase: " \				"Failed erase, page 0x%08x\n", page);			nand_deselect ();			this->state = FL_READY;			spin_unlock_bh (&this->chip_lock);			return -EIO;		}		/* Increment page address and decrement length */		len -= mtd->erasesize;		page += pages_per_block;		/* Release the spin lock */		spin_unlock_bh (&this->chip_lock);erase_retry:		/* Check the state and sleep if it changed */		spin_lock_bh (&this->chip_lock);		if (this->state == FL_ERASING) {			continue;		}		else {			set_current_state (TASK_UNINTERRUPTIBLE);			add_wait_queue (&this->wq, &wait);			spin_unlock_bh (&this->chip_lock);			schedule();			remove_wait_queue (&this->wq, &wait);			goto erase_retry;		}	}	spin_unlock_bh (&this->chip_lock);	/* De-select the NAND device */	nand_deselect ();	/* Do call back function */	if (instr->callback)		instr->callback (instr);	/* The device is ready */	spin_lock_bh (&this->chip_lock);	this->state = FL_READY;	spin_unlock_bh (&this->chip_lock);	/* Return happy */	return 0;}/* * NAND sync */static void nand_sync (struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	DECLARE_WAITQUEUE(wait, current);	DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n");retry:	/* Grab the spinlock */	spin_lock_bh(&this->chip_lock);	/* See what's going on */	switch(this->state) {	case FL_READY:	case FL_SYNCING:		this->state = FL_SYNCING;		spin_unlock_bh (&this->chip_lock);		break;	default:		/* Not an idle state */		add_wait_queue (&this->wq, &wait);		spin_unlock_bh (&this->chip_lock);		schedule ();		remove_wait_queue (&this->wq, &wait);		goto retry;	}        /* Lock the device */	spin_lock_bh (&this->chip_lock);	/* Set the device to be ready again */	if (this->state == FL_SYNCING) {		this->state = FL_READY;		wake_up (&this->wq);	}        /* Unlock the device */	spin_unlock_bh (&this->chip_lock);}/* * Scan for the NAND device */int nand_scan (struct mtd_info *mtd){	int i, nand_maf_id, nand_dev_id;	struct nand_chip *this = mtd->priv;	/* Select the device */	nand_select ();	/* Send the command for reading device ID */	nand_command (mtd, NAND_CMD_READID, 0x00, -1);	/* Read manufacturer and device IDs */	nand_maf_id = readb (this->IO_ADDR);	nand_dev_id = readb (this->IO_ADDR);	/* Print and store flash device information */	for (i = 0; nand_flash_ids[i].name != NULL; i++) {		if (nand_maf_id == nand_flash_ids[i].manufacture_id &&		    nand_dev_id == nand_flash_ids[i].model_id) {			if (!mtd->size) {				mtd->name = nand_flash_ids[i].name;				mtd->erasesize = nand_flash_ids[i].erasesize;				mtd->size = (1 << nand_flash_ids[i].chipshift);				mtd->eccsize = 256;				if (nand_flash_ids[i].page256) {					mtd->oobblock = 256;					mtd->oobsize = 8;					this->page_shift = 8;				}				else {					mtd->oobblock = 512;					mtd->oobsize = 16;					this->page_shift = 9;				}			}			printk (KERN_INFO "NAND device: Manufacture ID:" \				" 0x%02x, Chip ID: 0x%02x (%s)\n",			       nand_maf_id, nand_dev_id, mtd->name);			break;		}	}	/* Initialize state and spinlock */	this->state = FL_READY;	spin_lock_init(&this->chip_lock);	/* De-select the device */	nand_deselect ();	/* Print warning message for no device */	if (!mtd->size) {		printk (KERN_WARNING "No NAND device found!!!\n");		return 1;	}	/* Fill in remaining MTD driver data */	mtd->type = MTD_NANDFLASH;	mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC;	mtd->module = THIS_MODULE;	mtd->ecctype = MTD_ECC_SW;	mtd->erase = nand_erase;	mtd->point = NULL;	mtd->unpoint = NULL;	mtd->read = nand_read;	mtd->write = nand_write;	mtd->read_ecc = nand_read_ecc;	mtd->write_ecc = nand_write_ecc;	mtd->read_oob = nand_read_oob;	mtd->write_oob = nand_write_oob;	mtd->readv = NULL;	mtd->writev = nand_writev;	mtd->sync = nand_sync;	mtd->lock = NULL;	mtd->unlock = NULL;	mtd->suspend = NULL;	mtd->resume = NULL;	/* Return happy */	return 0;}EXPORT_SYMBOL(nand_scan);MODULE_LICENSE("GPL");MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");MODULE_DESCRIPTION("Generic NAND flash driver code");

⌨️ 快捷键说明

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