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

📄 nand_base.c

📁 老版本的mtd-snap
💻 C
📖 第 1 页 / 共 5 页
字号:
	}			if (getchip) {		/* Deselect and wake up anyone waiting on the device */		nand_release_device(mtd);	}			return res;}/** * nand_default_block_markbad - [DEFAULT] mark a block bad * @mtd:	MTD device structure * @ofs:	offset from device start * * This is the default implementation, which can be overridden by * a hardware specific driver.*/static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs){	struct nand_chip *this = mtd->priv;	u_char buf[2] = {0, 0};	size_t	retlen;	int block;		/* Get block number */	block = ((int) ofs) >> this->bbt_erase_shift;	if (this->bbt)		this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);	/* Do we have a flash based bad block table ? */	if (this->options & NAND_USE_FLASH_BBT)		return nand_update_bbt (mtd, ofs);			/* We write two bytes, so we dont have to mess with 16 bit access */	ofs += mtd->oobsize + (this->badblockpos & ~0x01);	return nand_write_oob (mtd, ofs , 2, &retlen, buf);}/**  * nand_check_wp - [GENERIC] check if the chip is write protected * @mtd:	MTD device structure * Check, if the device is write protected  * * The function expects, that the device is already selected  */static int nand_check_wp (struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	/* Check the WP bit */	this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; }/** * nand_block_checkbad - [GENERIC] Check if a block is marked bad * @mtd:	MTD device structure * @ofs:	offset from device start * @getchip:	0, if the chip is already selected * @allowbbt:	1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. */static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, int allowbbt){	struct nand_chip *this = mtd->priv;		if (!this->bbt)		return this->block_bad(mtd, ofs, getchip);		/* Return info from the table */	return nand_isbad_bbt (mtd, ofs, allowbbt);}/*  * Wait for the ready pin, after a command * The timeout is catched later. */static void nand_wait_ready(struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	unsigned long	timeo = jiffies + 2;	/* wait until command is processed or timeout occures */	do {		if (this->dev_ready(mtd))			return;	} while (time_before(jiffies, timeo));	}/** * nand_command - [DEFAULT] Send command to NAND device * @mtd:	MTD device structure * @command:	the command to be sent * @column:	the column address for this command, -1 if none * @page_addr:	the page address for this command, -1 if none * * Send command to NAND device. This function is used for small page * devices (256/512 Bytes per page) */static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr){	register struct nand_chip *this = mtd->priv;	/* Begin command latch cycle */	this->hwcontrol(mtd, NAND_CTL_SETCLE);	/*	 * Write out the command to the device.	 */	if (command == NAND_CMD_SEQIN) {		int readcmd;		if (column >= mtd->oobblock) {			/* OOB area */			column -= mtd->oobblock;			readcmd = NAND_CMD_READOOB;		} else if (column < 256) {			/* First 256 bytes --> READ0 */			readcmd = NAND_CMD_READ0;		} else {			column -= 256;			readcmd = NAND_CMD_READ1;		}		this->write_byte(mtd, readcmd);	}	this->write_byte(mtd, command);	/* Set ALE and clear CLE to start address cycle */	this->hwcontrol(mtd, NAND_CTL_CLRCLE);	if (column != -1 || page_addr != -1) {		this->hwcontrol(mtd, NAND_CTL_SETALE);		/* Serially input address */		if (column != -1) {			/* Adjust columns for 16 bit buswidth */			if (this->options & NAND_BUSWIDTH_16)				column >>= 1;			this->write_byte(mtd, column);		}		if (page_addr != -1) {			this->write_byte(mtd, (unsigned char) (page_addr & 0xff));			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));			/* One more address cycle for devices > 32MiB */			if (this->chipsize > (32 << 20))				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));		}		/* Latch in address */		this->hwcontrol(mtd, NAND_CTL_CLRALE);	}		/* 	 * program and erase have their own busy handlers 	 * status and sequential in needs no delay	*/	switch (command) {				case NAND_CMD_PAGEPROG:	case NAND_CMD_ERASE1:	case NAND_CMD_ERASE2:	case NAND_CMD_SEQIN:	case NAND_CMD_STATUS:		return;	case NAND_CMD_RESET:		if (this->dev_ready)				break;		udelay(this->chip_delay);		this->hwcontrol(mtd, NAND_CTL_SETCLE);		this->write_byte(mtd, NAND_CMD_STATUS);		this->hwcontrol(mtd, NAND_CTL_CLRCLE);		while ( !(this->read_byte(mtd) & NAND_STATUS_READY));		return;	/* This applies to read commands */		default:		/* 		 * If we don't have access to the busy pin, we apply the given		 * command delay		*/		if (!this->dev_ready) {			udelay (this->chip_delay);			return;		}		}	/* Apply this short delay always to ensure that we do wait tWB in	 * any case on any machine. */	ndelay (100);	nand_wait_ready(mtd);}/** * nand_command_lp - [DEFAULT] Send command to NAND large page device * @mtd:	MTD device structure * @command:	the command to be sent * @column:	the column address for this command, -1 if none * @page_addr:	the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page devices * We dont have the seperate regions as we have in the small page devices. * We must emulate NAND_CMD_READOOB to keep the code compatible. * */static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, int page_addr){	register struct nand_chip *this = mtd->priv;	/* Emulate NAND_CMD_READOOB */	if (command == NAND_CMD_READOOB) {		column += mtd->oobblock;		command = NAND_CMD_READ0;	}				/* Begin command latch cycle */	this->hwcontrol(mtd, NAND_CTL_SETCLE);	/* Write out the command to the device. */	this->write_byte(mtd, (command & 0xff));	/* End command latch cycle */	this->hwcontrol(mtd, NAND_CTL_CLRCLE);	if (column != -1 || page_addr != -1) {		this->hwcontrol(mtd, NAND_CTL_SETALE);		/* Serially input address */		if (column != -1) {			/* Adjust columns for 16 bit buswidth */			if (this->options & NAND_BUSWIDTH_16)				column >>= 1;			this->write_byte(mtd, column & 0xff);			this->write_byte(mtd, column >> 8);		}			if (page_addr != -1) {			this->write_byte(mtd, (unsigned char) (page_addr & 0xff));			this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));			/* One more address cycle for devices > 128MiB */			if (this->chipsize > (128 << 20))				this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0xff));		}		/* Latch in address */		this->hwcontrol(mtd, NAND_CTL_CLRALE);	}		/* 	 * program and erase have their own busy handlers 	 * status, sequential in, and deplete1 need no delay	 */	switch (command) {				case NAND_CMD_CACHEDPROG:	case NAND_CMD_PAGEPROG:	case NAND_CMD_ERASE1:	case NAND_CMD_ERASE2:	case NAND_CMD_SEQIN:	case NAND_CMD_STATUS:	case NAND_CMD_DEPLETE1:		return;	/* 	 * read error status commands require only a short delay	 */	case NAND_CMD_STATUS_ERROR:	case NAND_CMD_STATUS_ERROR0:	case NAND_CMD_STATUS_ERROR1:	case NAND_CMD_STATUS_ERROR2:	case NAND_CMD_STATUS_ERROR3:		udelay(this->chip_delay);		return;	case NAND_CMD_RESET:		if (this->dev_ready)				break;		udelay(this->chip_delay);		this->hwcontrol(mtd, NAND_CTL_SETCLE);		this->write_byte(mtd, NAND_CMD_STATUS);		this->hwcontrol(mtd, NAND_CTL_CLRCLE);		while ( !(this->read_byte(mtd) & NAND_STATUS_READY));		return;	case NAND_CMD_READ0:		/* Begin command latch cycle */		this->hwcontrol(mtd, NAND_CTL_SETCLE);		/* Write out the start read command */		this->write_byte(mtd, NAND_CMD_READSTART);		/* End command latch cycle */		this->hwcontrol(mtd, NAND_CTL_CLRCLE);		/* Fall through into ready check */			/* This applies to read commands */		default:		/* 		 * If we don't have access to the busy pin, we apply the given		 * command delay		*/		if (!this->dev_ready) {			udelay (this->chip_delay);			return;		}		}	/* Apply this short delay always to ensure that we do wait tWB in	 * any case on any machine. */	ndelay (100);	nand_wait_ready(mtd);}/** * nand_get_device - [GENERIC] Get chip for selected access * @this:	the nand chip descriptor * @mtd:	MTD device structure * @new_state:	the state which is requested  * * Get the device and lock it for exclusive access */static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state){	struct nand_chip *active;	spinlock_t *lock;	wait_queue_head_t *wq;	DECLARE_WAITQUEUE (wait, current);	lock = (this->controller) ? &this->controller->lock : &this->chip_lock;	wq = (this->controller) ? &this->controller->wq : &this->wq;retry:	active = this;	spin_lock(lock);	/* Hardware controller shared among independend devices */	if (this->controller) {		if (this->controller->active)			active = this->controller->active;		else			this->controller->active = this;	}	if (active == this && this->state == FL_READY) {		this->state = new_state;		spin_unlock(lock);		return;	}	set_current_state(TASK_UNINTERRUPTIBLE);	add_wait_queue(wq, &wait);	spin_unlock(lock);	schedule();	remove_wait_queue(wq, &wait);	goto retry;}/** * nand_wait - [DEFAULT]  wait until the command is done * @mtd:	MTD device structure * @this:	NAND chip structure * @state:	state to select the max. timeout value * * Wait for command done. This applies to erase and program only * Erase can take up to 400ms and program up to 20ms according to  * general NAND and SmartMedia specs **/static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state){	unsigned long	timeo = jiffies;	int	status;		if (state == FL_ERASING)		 timeo += (HZ * 400) / 1000;	else		 timeo += (HZ * 20) / 1000;	/* Apply this short delay always to ensure that we do wait tWB in	 * any case on any machine. */	ndelay (100);	if ((state == FL_ERASING) && (this->options & NAND_IS_AND))		this->cmdfunc (mtd, NAND_CMD_STATUS_MULTI, -1, -1);	else			this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);	while (time_before(jiffies, timeo)) {				/* Check, if we were interrupted */		if (this->state != state)			return 0;		if (this->dev_ready) {			if (this->dev_ready(mtd))				break;			} else {			if (this->read_byte(mtd) & NAND_STATUS_READY)				break;		}		cond_resched();	}	status = (int) this->read_byte(mtd);	return status;}/** * nand_write_page - [GENERIC] write one page * @mtd:	MTD device structure * @this:	NAND chip structure * @page: 	startpage inside the chip, must be called with (page & this->pagemask) * @oob_buf:	out of band data buffer * @oobsel:	out of band selecttion structre * @cached:	1 = enable cached programming if supported by chip * * Nand_page_program function is used for write and writev ! * This function will always program a full page of data * If you call it with a non page aligned buffer, you're lost :) * * Cached programming is not supported yet. */static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, 	u_char *oob_buf,  struct nand_oobinfo *oobsel, int cached){	int 	i, status;	u_char	ecc_code[32];	int	eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;	int  	*oob_config = oobsel->eccpos;	int	datidx = 0, eccidx = 0, eccsteps = this->eccsteps;	int	eccbytes = 0;		/* FIXME: Enable cached programming */	cached = 0;		/* Send command to begin auto page programming */	this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);	/* Write out complete page of data, take care of eccmode */	switch (eccmode) {	/* No ecc, write all */	case NAND_ECC_NONE:		printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");		this->write_buf(mtd, this->data_poi, mtd->oobblock);		break;			/* Software ecc 3/256, write all */	case NAND_ECC_SOFT:

⌨️ 快捷键说明

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