smc.c

来自「上传linux-jx2410的源代码」· C语言 代码 · 共 1,404 行 · 第 1/3 页

C
1,404
字号
    /* Wake up anyone waiting on the device */    spin_lock_bh (&this->chip_lock);    if (erase_state)      this->state = FL_ERASING;    else      this->state = FL_READY;    wake_up (&this->wq);    spin_unlock_bh (&this->chip_lock);    return ret;}/* * NAND read out-of-band */static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len,				size_t *retlen, u_char *buf){	int i, offset, page;	int erase_state = 0;	struct nand_chip *this = mtd->priv;	DECLARE_WAITQUEUE(wait, current);		DEBUG (MTD_DEBUG_LEVEL3,	       __FUNCTION__ ": from = 0x%08x, len = %i\n", (unsigned int) from,	       (int) len);	/* Shift to get page */	page = ((int) from) >> this->page_shift;	/* Mask to get column */	offset = from & 0x0f;	/* Initialize return length value */	*retlen = 0;	/* Do not allow read past end of page */	if ((offset + len) > mtd->oobsize) {		DEBUG (MTD_DEBUG_LEVEL0,			__FUNCTION__ ": Attempt read past end of page " \			"0x%08x, column %i, length %i\n", page, offset, len);		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_READING;		spin_unlock_bh (&this->chip_lock);		break;	case FL_ERASING:		this->state = FL_READING;		erase_state = 1;		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 ();	/* Send the read command */	nand_command (mtd, NAND_CMD_READOOB, offset, page);		this->wait_for_ready();	/* Read the data */	for (i = 0 ; i < len ; i++)		buf[i] = this->read_data();	/* De-select the NAND device */	nand_deselect ();	/* Wake up anyone waiting on the device */	spin_lock_bh (&this->chip_lock);	if (erase_state)		this->state = FL_ERASING;	else		this->state = FL_READY;	wake_up (&this->wq);	spin_unlock_bh (&this->chip_lock);	/* Return happy */	*retlen = len;	return 0;}/* * NAND write */static int nand_write (struct mtd_info *mtd, loff_t to, size_t len,		       size_t *retlen, const u_char *buf){    int i, page, col, cnt, status;    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);    /* Do not allow write past end of page */    if ((to + len) > mtd->size) {      DEBUG (MTD_DEBUG_LEVEL0,	     __FUNCTION__ ": Attempted write 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_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;    };    /* 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);    this->wait_for_ready();    if (!(this->read_data () & SMC_STAT_NOT_WP)) {      DEBUG (MTD_DEBUG_LEVEL0,	     __FUNCTION__ ": Device is write protected!!!\n");      i = -EPERM;      goto nand_write_exit;    }    /* Loop until all data is written */    while (*retlen < len) {      /* Write data into buffer */      if ((col + len) >= mtd->oobblock)	for(i=col, cnt=0 ; i < mtd->oobblock ; i++, cnt++)	  this->data_buf[i] = buf[(*retlen + cnt)];      else	for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++)	  this->data_buf[i] = buf[(*retlen + cnt)];      /* Write ones for partial page programming */      for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++)	this->data_buf[i] = 0xff;      /* Write pre-padding bytes into buffer */      for (i=0 ; i < col ; i++)	this->data_buf[i] = 0xff;      /* Write post-padding bytes into buffer */      if ((col + (len - *retlen)) < mtd->oobblock) {	for(i=(col + cnt) ; i < mtd->oobblock ; i++)	  this->data_buf[i] = 0xff;      }      /* Send command to begin auto page programming */      nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);      /* Write out complete page of data */      this->hwcontrol(NAND_CTL_DAT_OUT);      for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++)	this->write_data (this->data_buf[i]);      this->hwcontrol(NAND_CTL_DAT_IN);      /* Send command to actually program the 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);	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, " \	       "%6i bytes were succesful\n", page, *retlen);	i = -EIO;	goto nand_write_exit;      }#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);      this->wait_for_ready();      /* Loop through and verify the data */      for (i=col ; i < cnt ; i++) {	if (this->data_buf[i] != this->read_data ()) {	  DEBUG (MTD_DEBUG_LEVEL0,		 __FUNCTION__ ": Failed write verify, page 0x%08x, " \		 "%6i bytes were succesful\n",		 page, *retlen);	  i = -EIO;	  goto nand_write_exit;	}      }#endif      /*       * If we are writing a large amount of data and/or it       * crosses page or half-page boundaries, we set the       * the column to zero. It simplifies the program logic.       */      if (col)	col = 0x00;      /* Update written bytes count */      *retlen += cnt;      /* Increment page address */      page++;    }    /* Return happy */    *retlen = len;    i = 0; nand_write_exit:    /* 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 i;}/* * NAND write with ECC, but only 1 sector! */static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,		       size_t *retlen, const u_char *buf, u_char *ecc_code){    int i, page, cnt, status, ret;    struct nand_chip *this = mtd->priv;    DECLARE_WAITQUEUE(wait, current);    unsigned int sector_size, page_size, oob_size;    DEBUG (MTD_DEBUG_LEVEL3,	   __FUNCTION__ ": to = 0x%08x, len = %i\n", (unsigned int) to,	   (int) len);    sector_size = this->dev->szS;    page_size = mtd->oobblock;    oob_size = mtd->oobsize;    if (to & (sector_size - 1)) {      DEBUG (MTD_DEBUG_LEVEL0,	     __FUNCTION__ ": Not Sector aligned\n");      return -EINVAL;    }    if (len != sector_size) {      DEBUG (MTD_DEBUG_LEVEL0,	     __FUNCTION__ ": Only 1 Sector!\n");      return -EINVAL;    }    /* Do not allow write past end of page */    if ((to + len) > mtd->size) {      DEBUG (MTD_DEBUG_LEVEL0,	     __FUNCTION__ ": Attempted write 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_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;    };    /* Shift to get page */    page = ((int) to) >> this->page_shift;    /* Initialize return length value */    *retlen = 0;    /* 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_err;    }    /* Loop until all data is written */    while (*retlen < len) {      /* Send command to begin auto page programming */      nand_command (mtd, NAND_CMD_SEQIN, 0x00, page);      this->hwcontrol(NAND_CTL_DAT_OUT);      /* Write out complete page of data */      for(i=0, cnt=0; i < page_size; i++, cnt++)	this->write_data (buf[(*retlen) + cnt]);      /* Write ones for partial page programming */      for (i=0; i < oob_size; i++) {#ifdef USE_256BYTE_NAND_FLASH	if (*retlen & (sector_size - 1))	  this->write_data (ecc_code[SMC_OOB256_SIZE + i]);	else#endif	  this->write_data (ecc_code[i]);      }          this->hwcontrol(NAND_CTL_DAT_IN);      /* Send command to actually program the 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);	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, " \	       "%6i bytes were succesful\n", page, *retlen);	ret = -EIO;	goto nand_write_err;      }#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 */#ifdef USE_256BYTE_NAND_FLASH      if (*retlen & (sector_size - 1))	nand_command (mtd, NAND_CMD_READ0, 0x00, page + 1);      else#endif	nand_command (mtd, NAND_CMD_READ0, 0x00, page);      this->wait_for_ready();      /* Loop through and verify the data */      for (i=0; i < page_size; i++) {	if (this->data_buf[i] != this->read_data ()) {	  DEBUG (MTD_DEBUG_LEVEL0,		 __FUNCTION__ ": Failed write verify, page 0x%08x, " \		 "%6i bytes were succesful\n",		 page, *retlen);	  ret = -EIO;	  goto nand_write_err;	}      }#endif      /* Update written bytes count */      *retlen += cnt;      /* Increment page address */      page++;

⌨️ 快捷键说明

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