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

📄 nand.c

📁 linux嵌入式课程实践中的一个关于声卡驱动程序 。
💻 C
📖 第 1 页 / 共 3 页
字号:
	this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	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 */	this->cmdfunc (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 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 */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	if (!(readb (this->IO_ADDR_R) & 0x80)) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");		instr->state = MTD_ERASE_FAILED;		goto erase_exit;	}	/* 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 ! */			this->cmdfunc (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 */		this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);		this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);		spin_unlock_bh (&this->chip_lock);		status = this->waitfunc (mtd, this, FL_ERASING);		/* Get spinlock, in case we exit */		spin_lock_bh (&this->chip_lock);		/* 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;		}				/* Check, if we were interupted */		if (this->state == FL_ERASING) {			/* 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:		spin_lock_bh (&this->chip_lock);		/* Check the state and sleep if it changed */		if (this->state == FL_ERASING || this->state == FL_READY) {			/* Select the NAND device again, if we were interrupted */			this->state = FL_ERASING;			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:	/* De-select the NAND device */	nand_deselect ();	spin_unlock_bh (&this->chip_lock);	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;	/* check for proper chip_delay setup, set 20us if not */	if (!this->chip_delay)		this->chip_delay = 20;	/* check, if a user supplied command function given */	if (this->cmdfunc == NULL)		this->cmdfunc = nand_command;	/* check, if a user supplied wait function given */	if (this->waitfunc == NULL)		this->waitfunc = nand_wait;	/* Select the device */	nand_select ();	/* Send the command for reading device ID */	this->cmdfunc (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 + -