smc.c

来自「移植到2410开发板上的源代码」· C语言 代码 · 共 1,405 行 · 第 1/3 页

C
1,405
字号
    *retlen = len;    ret = 0; nand_write_err:    /* 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, offset, page, status, ret;    struct nand_chip *this = mtd->priv;    DECLARE_WAITQUEUE(wait, current);    DEBUG (MTD_DEBUG_LEVEL3,	   __FUNCTION__ ": 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 */    offset = to & 0x1f;    /* Initialize return length value */    *retlen = 0;    /* Do not allow write past end of page */    if ((offset + len) > mtd->oobsize) {      DEBUG (MTD_DEBUG_LEVEL0,	     __FUNCTION__": Attempt to write past end of page\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_WRITING;      spin_unlock_bh (&this->chip_lock);      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;    };    /* Select the NAND device */    nand_select ();    /* Check the WP bit */    nand_command (mtd, NAND_CMD_STATUS, -1, -1);    this->wait_for_ready();    if (!(this->read_data () & SMC_STAT_NOT_WP)) {      DEBUG (MTD_DEBUG_LEVEL0,	     __FUNCTION__ ": Device is write protected!!!\n");      ret = -EPERM;      goto nand_write_oob_err;    }    /* Write out desired data */    nand_command (mtd, NAND_CMD_SEQIN, offset + mtd->oobblock, page);    this->hwcontrol(NAND_CTL_DAT_OUT);    for (i=0 ; i<len ; i++)      this->write_data (buf[i]);    this->hwcontrol(NAND_CTL_DAT_IN);    /* Send command to program the OOB data */    nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1);    this->wait_for_ready();     /*     * 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);      this->wait_for_ready();      status = (int) this->read_data ();      if (status & SMC_STAT_READY)	break;    }    /* See if device thinks it succeeded */    if (status & SMC_STAT_WRITE_ERR) {      DEBUG (MTD_DEBUG_LEVEL0,	     __FUNCTION__ ": Failed write, page 0x%08x\n", page);      ret = -EIO;      goto nand_write_oob_err;    }#ifdef CONFIG_MTD_NAND_VERIFY_WRITE    /* Send command to read back the data */    nand_command (mtd, NAND_CMD_READOOB, offset, page);    this->wait_for_ready();    /* Loop through and verify the data */    for (i=0 ; i<len ; i++) {      if (buf[i] != this->read_data ()) {	DEBUG (MTD_DEBUG_LEVEL0,	       __FUNCTION__ ": Failed write verify, page 0x%08x\n", page);	ret = -EIO;	goto nand_write_oob_err;      }    }#endif    /* Return happy */    *retlen = len;    ret = 0; nand_write_oob_err:    /* 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 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,		__FUNCTION__ ": 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,			__FUNCTION__ ": Unaligned address\n");		return -EINVAL;	}	/* Length must align on block boundary */	if (instr->len & (mtd->erasesize - 1)) {		DEBUG (MTD_DEBUG_LEVEL0,			__FUNCTION__ ": 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,			__FUNCTION__ ": 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);	this->wait_for_ready();	if (!(this->read_data () & SMC_STAT_NOT_WP)) {		DEBUG (MTD_DEBUG_LEVEL0,			__FUNCTION__ ": 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);		this->wait_for_ready();		/*		 * 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);			this->wait_for_ready();			status = (int) this->read_data ();			if (status & SMC_STAT_READY)				break;		}		/* See if block erase succeeded */		if (status & SMC_STAT_WRITE_ERR) {			DEBUG (MTD_DEBUG_LEVEL0, __FUNCTION__ \				": Failed erase, page 0x%08x\n", page);			nand_deselect ();			instr->state = MTD_ERASE_FAILED;			if (instr->callback)			  instr->callback (instr);			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 */	instr->state = MTD_ERASE_DONE;	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, __FUNCTION__ ": 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 SMC device */int smc_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);	this->wait_for_ready();	/* Read manufacturer and device IDs */	nand_maf_id = this->read_data ();	nand_dev_id = this->read_data ();	/* 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) {#ifdef USE_256BYTE_NAND_FLASH			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;				}				this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];			}#else			if (!(mtd->size) && !(nand_flash_ids[i].page256)) {			  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;			  mtd->oobblock = 512;			  mtd->oobsize = 16;			  this->page_shift = 9;			  this->dev = &nand_smc_info[GET_DI_NUM(nand_flash_ids[i].chipshift)];			}#endif			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);	init_waitqueue_head(&(this->wq));	/* 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 = NULL;	mtd->sync = nand_sync;	mtd->lock = NULL;	mtd->unlock = NULL;	mtd->suspend = NULL;	mtd->resume = NULL;	/* Return happy */	return 0;}EXPORT_SYMBOL(smc_scan);MODULE_LICENSE("GPL");MODULE_AUTHOR("Yong-iL Joh <tolkien@mizi.com>");MODULE_DESCRIPTION("S3C2410 NAND Flash");

⌨️ 快捷键说明

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