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

📄 nand.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	return ret;}/* * NAND write with iovec */static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs,				unsigned long count, loff_t to, size_t *retlen){	int i, page, col, cnt, len, total_len, ret = 0;	struct nand_chip *this = mtd->priv;	/* Calculate total length of data */	total_len = 0;	for (i=0 ; i < count ; i++)		total_len += (int) vecs[i].iov_len;	DEBUG (MTD_DEBUG_LEVEL3,		"nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to,			(unsigned int) total_len, count);	/* Do not allow write past end of page */	if ((to + total_len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0,			"nand_writev: Attempted write past end of device\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_writev: Device is write protected!!!\n");		ret = -EIO;		goto out;	}	/* Loop until all iovecs' data has been written */	cnt = col;	len = 0;	while (count) {		/* Invalidate cache, if we write to this page */		if (this->cache_page == page)			this->cache_page = -1;			/* Do any need pre-fill for partial page programming */		for (i=0 ; i < cnt ; i++)			this->data_buf[i] = 0xff;		/*		 * Read data out of each tuple until we have a full page		 * to write or we've read all the tuples.		 */		 		while ((cnt < mtd->oobblock) && count) {			if (vecs->iov_base!=NULL && vecs->iov_len) {				this->data_buf[cnt++] = 					((u_char *) vecs->iov_base)[len++];			}			if (len >= (int) vecs->iov_len) {				vecs++;				len = 0;				count--;			}		}				/* We use the same function for write and writev !) */		ret = nand_write_page(mtd,this,page,col,cnt,this->ecc_code_buf);		if (ret)			goto out;		/* Update written bytes count */		*retlen += (cnt - col);		/* Reset written byte counter and column */		col = cnt = 0;		/* Increment page address */		page++;	}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 happy */	return ret;}/* * NAND erase a block */static int nand_erase (struct mtd_info *mtd, struct erase_info *instr){	int i, page, len, status, pages_per_block, ret;	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;	}	/* Grab the lock and see if the device is available */	nand_get_chip(this,FL_ERASING,NULL);	/* 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_R) & 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;		instr->state = MTD_ERASING;	while (len) {		if (oob_config.badblock_pos != -1) {			/* Check if we have a bad block, we do not erase bad blocks !*/			nand_command (mtd, NAND_CMD_READOOB, oob_config.badblock_pos, page);			if ( readb(this->IO_ADDR_R) != 0xff) {				printk(KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n",page);				instr->state = MTD_ERASE_FAILED;				goto erase_exit;			}		}						/* 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 */			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 block erase succeeded */		if (status & 0x01) {			DEBUG (MTD_DEBUG_LEVEL0,				"nand_erase: " \				"Failed erase, page 0x%08x\n", page);			instr->state = MTD_ERASE_FAILED;			goto erase_exit;		}			/* Invalidate cache, if last_page is inside erase-block */		if (this->cache_page >= page && this->cache_page < (page + pages_per_block) ) 			this->cache_page = -1;		/* 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) {			/* Select the NAND device again, if we were interrupted*/			nand_select ();			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;		}	} 	instr->state = MTD_ERASE_DONE;	erase_exit:		spin_unlock_bh (&this->chip_lock);	/* De-select the NAND device */	nand_deselect ();	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;;	/* Do call back function */	if (!ret && 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 more or less happy */	return ret;}/* * 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_R);	nand_dev_id = readb (this->IO_ADDR_R);	/* 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, waitqueue and spinlock */	this->state = FL_READY;	init_waitqueue_head(&this->wq);	spin_lock_init(&this->chip_lock);	/* De-select the device */	nand_deselect ();	/* 	 * Preset out of band configuration	*/#ifdef CONFIG_MTD_NAND_ECC_JFFS2	oob_config.ecc_pos[0] = NAND_JFFS2_OOB_ECCPOS0;	oob_config.ecc_pos[1] = NAND_JFFS2_OOB_ECCPOS1;	oob_config.ecc_pos[2] = NAND_JFFS2_OOB_ECCPOS2;	oob_config.ecc_pos[3] = NAND_JFFS2_OOB_ECCPOS3;	oob_config.ecc_pos[4] = NAND_JFFS2_OOB_ECCPOS4;	oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5;	oob_config.badblock_pos = 5;	oob_config.eccvalid_pos = 4;#else	oob_config.ecc_pos[0] = NAND_NOOB_ECCPOS0;	oob_config.ecc_pos[1] = NAND_NOOB_ECCPOS1;	oob_config.ecc_pos[2] = NAND_NOOB_ECCPOS2;	oob_config.ecc_pos[3] = NAND_NOOB_ECCPOS3;	oob_config.ecc_pos[4] = NAND_NOOB_ECCPOS4;	oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5;	oob_config.badblock_pos = NAND_NOOB_BADBPOS; 	oob_config.eccvalid_pos = NAND_NOOB_ECCVPOS;#endif	/* 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 + -