我们可以先跟着代码走,我把函数间关系和主要代码列出来。
上来是一个mtd选择的过程,cfi部分将会走下面个过程:(我们假设我们cpu是s3c2410,以后都是)
第一个过程:
mtd_dev_init() [mtdcore.c] -> mtd_init() [s3c2410_flash.c] -> cfi_init()[s3c2410_flash.c]
前面两个函数是mtd的公共函数。
static int cfi_init(void) { s3c2410_map.buswidth = FLASH_BUSWIDTH;
s3c2410_map.size = FLASH_SIZE;
s3c2410_map.set_vpp = set_vpp;
mymtd = do_map_probe("cfi_probe", &s3c2410_map); if (!mymtd) return -ENXIO;
return 0; }
|
首先对s3c2410_map结构体的初始化。
s3c2410_map是一个map_info结构体全局变量,前面已经做了标记化结构初始化(对于这个初始化解释可以看http://blog.chinaunix.net/u2/66435/showart.php?id=1299732)
static struct map_info s3c2410_map = { name: "S3C2410 flash", read8: s3c2410_read8, read16: s3c2410_read16, read32: s3c2410_read32, copy_from: s3c2410_copy_from, write8: s3c2410_write8, write16: s3c2410_write16, write32: s3c2410_write32, copy_to: s3c2410_copy_to,
map_priv_1: WINDOW_ADDR, map_priv_2: -1, };
|
然后调用do_map_probe函数,获得一个mtd_info结构体。
第二个过程:
do_map_probe()[chipreg.c]->get_mtd_chip_driver()[chipreg.c]->cfi_probe()[cfi_probe.c]->mtd_do_chip_probe()[gen_probe.c]
前面两个函数是norflash的公共函数,针对cfi和amd分别调用不同函数。
cfi_probe函数
struct mtd_info *cfi_probe(struct map_info *map) { return mtd_do_chip_probe(map, &cfi_chip_probe); }
|
cfi_probe函数传了两个参数map_info前面已经说了,cfi_chip_probe这个参数是struct chip_probe,初始化如下:
static struct chip_probe cfi_chip_probe = { name: "CFI", probe_chip: cfi_probe_chip };
|
其实就是给mtd_do_chip_probe一个函数指针cfi_probe_chip[cfi_probe.c],这个函数后面会用来嗅探芯片类型
我们来好好看看这个函数:
struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp) { struct mtd_info *mtd = NULL; struct cfi_private *cfi;
cfi = genprobe_ident_chips(map, cp); if (!cfi) return NULL;
map->fldrv_priv = cfi;
mtd = check_cmd_set(map, 1); /* First the primary cmdset */ if (!mtd) mtd = check_cmd_set(map, 0); /* Then the secondary */ if (mtd) return mtd;
return NULL; } |
这个函数主要做了两件事:
1、调用genprobe_ident_chips得到struct cfi_private结构,这个结构保存芯片cfi的信息,在结构体那篇我讲了他们的关系。
2、调用check_cmd_set得到一个信息齐全的mtd_info结构体,这也是我们最终想要的。
第三个过程:genprobe_ident_chips()[gen_probe.c]->genprobe_new_chip()[gen_probe.c]
genprobe_new_chip()函数中:
switch (map->buswidth) {
case CFIDEV_BUSWIDTH_1:
cfi->interleave = CFIDEV_INTERLEAVE_1;
cfi->device_type = CFI_DEVICETYPE_X8;
if (cp->probe_chip(map, 0, NULL, cfi))
return 1; cfi->device_type = CFI_DEVICETYPE_X16; if (cp->probe_chip(map, 0, NULL, cfi)) return 1; break;
|
上面就是genprobe_new_chip函数所要做的事情的一个case
根据buswidth来猜测interleave和device_type的类型,然后调用cfi_probe_chip[cfi_probe.c]函数来嗅探,失败则会把剩下的可能都嗅探一遍,成功则cfi被适当的赋值了,返回1,如果都失败了,返回0
cfi_probe_chip在这次调用主要作用是调用cfi_chip_setup[cfi_probe.c]来读取芯片的cfi信息,然后填进struct cfi_private结构的struct cfi_ident结构中去。我们会发现在cfi_probe_chip中是通过cfi->numchips来判断是不是首次调用。
我们这样直到genprobe_new_chip的作用就是得到芯片的cfi信息,然后填到struct cfi_ident中去。
接着genprobe_ident_chips在做必要struct cfi_private结构初始化,而且在根据interleave,多次调用cfi_probe_chip,这次cfi_probe_chip函数主要作用是确定每块芯片的存在,然后在struct flchip中填写每块芯片的start地址。
最后我们得到了主要的芯片cfi信息,和每块芯片的一些必要信息,如start地址。
第四个过程:check_cmd_set()[gen_probe.c]->cfi_cmdset_0001()[cfi_cmdset_0001.c]
check_cmd_set函数先通过cfi信息中的P_ID或者A_ID决定调用什么cmdset,vivi中只支持0001,也就是intel命令集。
cfi_cmdset_0001主要就两件事,首先或者cfi接口的额外信息如intel的用结构体struct cfi_pri_intelext表示,amd里面用struct cfi_pri_amdstd表示(vivi中没有cfi_cmdset_0002(),所以这个结构也不存在),然后就是mtd的进一步初始化,主要有像写,读,擦等操作的函数。
这个时候关于cfi的mtd_info就生成了。以后对flash的操作就可以通过他来了,而不要关心底层的实现了。
btw:vivi对cfi里面支持不是很好,比如只支持intel类型的,amd类型的不支持,sst这种怪胎的cfi那就更不支持了,还需要修改很多。不过vivi好像很早出现,以后没人维护了。。
阅读(2783) | 评论(0) | 转发(0) |