/*
* NAND read
* 参数: mtd : mtd_info结构
* from : 读取地址(从nand中的这个位置开始读)
* len : 读取长度
* retlen : 记录读了多少个字节的数据
* buf : 读出数据到buf中
* 返回值 : 0 读成功 。retlen
*/
static int
nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
{
int j, col, page, state;
struct nand_chip *this = mtd->priv;
DEBUG(MTD_DEBUG_LEVEL3,
__FUNCTION__"(): from = 0x%08lx, len = %i\n",
(unsigned int)from, (int)len);
/* Do not allow reads past end of device */
if ((from + len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0,
__FUNCTION__"(): Attempt read beyond end of device\n");
*retlen = 0;
return -EINVAL;
}
// 下面计算列地址与页地址
/* First we calculate the starting page */
page = from >> this->page_shift;
/* Get raw starting column */
col = from & (mtd->oobblock - 1);
/* State machine for devices having pages larger than 256 bytes */
state = (col < mtd->eccsize) ? 0 : 1;
/* Calculate column address within ECC block context */
col = (col >= mtd->eccsize) ? (col - mtd->eccsize) : col;
/* Initialize return value */
*retlen = 0;
/* Select the NAND device */
nand_select();
/* Loop until all data read */
while (*retlen < len) {
/* Send the read command 根据state来选择读哪个半页。程序在对于页半及起始地址上的判断便利程序的适用性更强。而不必从页始开始读。*/
if (!state)
nand_command(mtd, NAND_CMD_READ0, col, page);
else
nand_command(mtd, NAND_CMD_READ1, col, page);
this->wait_for_ready();
/* Read the data directly into the return buffer */
if ((*retlen + (mtd->eccsize - col)) >= len) {
while (*retlen < len)
buf[(*retlen)++] = this->read_data();
/* We're done */
continue;
} else {
for (j = col; j < mtd->eccsize; j++)
buf[(*retlen)++] = this->read_data();
}
/*
* If the amount of data to be read is greater than
* (256 - col), then all subsequent reads will take
* place on page or half-page (in the case of 512 byte
* page devices) aligned boundaries and the column
* address will be zero. Setting the column address to
* zero after the first read allows us to simplify
* the reading of data and the if/else statements above.
*/
if (col)
col = 0x00;
//这块芯片为8位宽,因而每页宽需为512列。若16位宽的芯片,则只需256列,则它就不用分半页了
/* Increment page address */
if ((mtd->oobblock == 256) || state)
page++;
/* Toggle state machine */
if (mtd->oobblock == 512)
state = state ? 0 : 1;
}
/* De-select the NAND device */
nand_deselect();
/* Return happy */
return 0;
}
|