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 + -
显示快捷键?