由前面的说明可知,我们在要对NAND 芯片进行实际操作前已经为struct mtd_info 、struct mtd_partition 和struct nand_chip 这三个结构体分配好了内存,接下来就要为它们做一些初始化工作。 其中,我们需要为struct mtd_info 所做的初始化工作并不多,因为MTD Core 会在稍后为它做很多初始化工作(这些工作在nand_scan_tail这个函数的后半部分来填充),但是有一点必须由我们来做,那就是把指向struct nand_chip 结构体的指针赋给struct mtd_info 的priv 成员变量,因为MTD Core 中很多函数之间的调用都只传递struct mtd_info ,它需要通过priv 成员变量得到struct nand_chip 。如下,在s3c_nand.c中:
struct mtd_info *s3c_mtd = NULL; //mtd_info结构体指针
struct nand_chip *nand; //nand_chip结构体指针
/* allocate memory for MTD device structure and private data */
s3c_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); //一起分内存
nand = (struct nand_chip *) (&s3c_mtd[1]); //得到划分的内存
memset((char *) s3c_mtd, 0, sizeof(struct mtd_info)); //初始化0
memset((char *) nand, 0, sizeof(struct nand_chip));
s3c_mtd->priv = nand;
所以,为struct nand_chip 的初始化,才是我们在probe 函数中的主要工作。其实这里所谓的初始化,主要就是为struct nand_chip 结构体中的众多函数指针赋值。现在假定你定义好了所有需要的与NAND 芯片交互的函数,并已经把它们赋给了struct nand_chip 结构体中的函数指针。当然,此时你还不能保证这些函数一定能正确工作,但是没有关系,probe 函数在接下来的工作中会调用到几乎所有的这些函数,你可以依次来验证和调试。当你的probe 函数能顺利通过后,那么这些函数也就基本没什么问题了,你的NAND 驱动也就已经完成了80 %了。
接下来,probe 函数就会开始与NAND 芯片进行交互了,它要做的事情主要包括这几个方面:读取NAND 芯片的ID ,然后查表得到这片NAND 芯片的如厂商,page size ,erase size 以及chip size 等信息,接着,根据struct nand_chip 中options 的值的不同,或者在NAND 芯片中的特定位置查找bad block table ,或者scan 整个NAND 芯片,并在内存中建立bad block table 。说起来复杂,但其实所有的这些动作,都可以在MTD 提供的一个叫做nand_scan 的函数中完成。
关于nand_scan 函数,在使用时我想有一个地方值得一提。nand_scan 函数主要有两个两个函数组成,即nand_scan_ident 函数和nand_scan_tail 函数。其中nand_scan_ident 函数会读取NAND 芯片的ID,而nand_scan_tail 函数则会查找或者建立bbt (bad block table) 。
在一般情况下,我们可以直接调用nand_scan 函数来完成所要做的工作,然而却并不总是如此,在有些情况下,我们必须分别调用nand_scan_ident 函数和nand_scan_tail 函数,因为在这两者之间,我们还需要做一些额外的工作。在《基于MTD 的NAND 驱动开发( 一) 》中介绍过一个叫做struct nand_ecclayout 的结构体,它用来定义ecc 在oob 中的布局。对于small page( 每页512 Byte) 和big page( 每页2048 Byte) 的两种NAND 芯片,它们的ecc 在oob 中的布局不尽相同。如果你的driver 中对这两种芯片的ecc 布局与MTD 中定义的default 的布局一致,那么就很方便,直接调用nand_scan 函数即可。
但如果不是,那你就需要为这两种不同的NAND 芯片分别定义你的ecc 布局。于是问题来了,因为我们在调用nand_scan_ident 函数之前,是不知道系统中的NAND 芯片是small page 类型的,还是big page 类型,然而在调用nand_scan_tail 函数之前,却必须确定NAND 芯片的oob 布局( 包括ecc 布局和坏块信息pattern) ,因为nand_scan_tail 函数在读取oob 以及处理ecc 时需要这个信息。所以在这种情况下,我们就需要首先调用nand_scan_ident 函数,它会调用一个叫做nand_get_flash_type 的函数,MTD 就是在这个函数中读取NAND 芯片的ID ,然后就能查表( 即全局变量nand_flash_ids) 知道这片NAND 芯片的类型( 即writesize 的大小) 了。接下来,你就可以在你的NAND 驱动中,根据writesize 的大小来区分ecc 的布局了。最后,我们就可以顺利地调用nand_scan_tail 函数了。
参考原文:http://blog.csdn.net/leibniz_zsu/archive/2009/12/10/4977853.aspx