1、CFI mode:
①、注册 cfi_chipdrv :
static int __init cfi_probe_init(void)
{
register_mtd_chip_driver(&cfi_chipdrv);
return 0;
}
/* linux-3.4.2\drivers\mtd\chips\cfi_probe.c */
在cfi_probe_init函数中调用register_mtd_chip_driver函数,将cfi_chipdrv 添加到chip_drvs_list中去:
void register_mtd_chip_driver(struct mtd_chip_driver *drv)
{
spin_lock(&chip_drvs_lock);
list_add(&drv->list, &chip_drvs_list);
spin_unlock(&chip_drvs_lock);
}
/* linux-3.4.2\drivers\mtd\chips\chipreg.c */
其中,cfi_chipdrv 结构体变量定义如下:
static struct mtd_chip_driver cfi_chipdrv = {
.probe = cfi_probe,
.name = "cfi_probe",
.module = THIS_MODULE
};
/* linux-3.4.2\drivers\mtd\chips\cfi_probe.c */
②、do_map_probe执行过程:
在do_map_probe函数中调用get_mtd_chip_driver函数 :
struct mtd_info *do_map_probe(const char *name, struct map_info *map)
{
struct mtd_chip_driver *drv;
struct mtd_info *ret;
drv = get_mtd_chip_driver(name);
...
}
/* linux-3.4.2\drivers\mtd\chips\chipreg.c */
依次列举chip_drvs_list中的mtd_chip_driver 项,将每一项的成员name和传入参数name做比较,返回name相同的mtd_chip_driver 项,返回值ret = &cfi_chipdrv给do_map_probe函数中的drv:
static struct mtd_chip_driver *get_mtd_chip_driver (const char *name)
{
struct list_head *pos;
struct mtd_chip_driver *ret = NULL, *this;
spin_lock(&chip_drvs_lock);
list_for_each(pos, &chip_drvs_list) {
this = list_entry(pos, typeof(*this), list);
if (!strcmp(this->name, name)) {
ret = this;
break;
}
}
if (ret && !try_module_get(ret->module))
ret = NULL;
spin_unlock(&chip_drvs_lock);
return ret; //ret = &cfi_chipdrv
}
/* linux-3.4.2\drivers\mtd\chips\chipreg.c */
再由mtd_chip_driver返回do_map_probe执行drv->probe(map):
struct mtd_info *do_map_probe(const char *name, struct map_info *map)
{
struct mtd_chip_driver *drv;
struct mtd_info *ret;
...
ret = drv->probe(map); //drv = &cfi_chipdrv
...
return ret;
}
/* linux-3.4.2\drivers\mtd\chips\chipreg.c */
由于drv = &cfi_chipdrv,执行执行drv->probe即相当于执行cfi_chipdrv.probe = cfi_probe:
struct mtd_info *cfi_probe(struct map_info *map)
{
/*
* Just use the generic probe stuff to call our CFI-specific
* chip_probe routine in all the possible permutations, etc.
*/
return mtd_do_chip_probe(map, &cfi_chip_probe);
}
/* linux-3.4.2\drivers\mtd\chips\cfi_probe.c */
其中,cfi_chip_probe如下定义:
static struct chip_probe cfi_chip_probe = {
.name = "CFI",
.probe_chip = cfi_probe_chip
};
/* linux-3.4.2\drivers\mtd\chips\cfi_probe.c */
cfi_probe ->mtd_do_chip_probe:
struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
{
struct mtd_info *mtd = NULL;
struct cfi_private *cfi;
/* First probe the map to see if we have CFI stuff there. */
cfi = genprobe_ident_chips(map, cp); //cp = &cfi_chip_probe
...
}
/* linux-3.4.2\drivers\mtd\chips\gen_probe.c */
mtd_do_chip_probe->genprobe_ident_chips:
static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
{
struct cfi_private cfi;
struct cfi_private *retcfi;
unsigned long *chip_map;
int i, j, mapsize;
int max_chips;
memset(&cfi, 0, sizeof(cfi));
/* Call the probetype-specific code with all permutations of
interleave and device type, etc. */
if (!genprobe_new_chip(map, cp, &cfi)) {
/* The probe didn't like it */
pr_debug("%s: Found no %s device at location zero\n",
cp->name, map->name);
return NULL;
}
...
}
/* linux-3.4.2\drivers\mtd\chips\gen_probe.c */
genprobe_ident_chips->genprobe_new_chip执行cp->probe_chip:
static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
struct cfi_private *cfi)
{
int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
int max_chips = map_bankwidth(map); /* And minimum 1 */
int nr_chips, type;
for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
...
for (; type <= CFI_DEVICETYPE_X32; type<<=1) {
...
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
}
}
return 0;
}
/* linux-3.4.2\drivers\mtd\chips\gen_probe.c */
由于cp = &cfi_chip_probe 所以执行执行cp->probe_chip相当于执行cfi_chip_probe.probe_chip = cfi_probe_chip。
2、JEDEC mode:
①、注册jedec_chipdrv :
static int __init jedec_probe_init(void)
{
register_mtd_chip_driver(&jedec_chipdrv);
return 0;
}
在jedec_probe_init函数中调用register_mtd_chip_driver函数,将jedec_chipdrv 添加到chip_drvs_list中去:
void register_mtd_chip_driver(struct mtd_chip_driver *drv)
{
spin_lock(&chip_drvs_lock);
list_add(&drv->list, &chip_drvs_list);
spin_unlock(&chip_drvs_lock);
}
其中,jedec_chipdrv 定义如下:
static struct mtd_chip_driver jedec_chipdrv = {
.probe = jedec_probe,
.name = "jedec_probe",
.module = THIS_MODULE
};
②、do_map_probe执行过程:
在do_map_probe函数中调用get_mtd_chip_driver函数 :
struct mtd_info *do_map_probe(const char *name, struct map_info *map)
{
struct mtd_chip_driver *drv;
struct mtd_info *ret;
drv = get_mtd_chip_driver(name);
...
}
/* linux-3.4.2\drivers\mtd\chips\chipreg.c */
依次列举chip_drvs_list中的mtd_chip_driver 项,将每一项的成员name和传入参数name做比较,返回name相同的mtd_chip_driver 项,返回值ret = &jedec_chipdrv 给do_map_probe函数中的drv:
static struct mtd_chip_driver *get_mtd_chip_driver (const char *name)
{
struct list_head *pos;
struct mtd_chip_driver *ret = NULL, *this;
spin_lock(&chip_drvs_lock);
list_for_each(pos, &chip_drvs_list) {
this = list_entry(pos, typeof(*this), list);
if (!strcmp(this->name, name)) {
ret = this;
break;
}
}
if (ret && !try_module_get(ret->module))
ret = NULL;
spin_unlock(&chip_drvs_lock);
return ret; //ret = &jedec_chipdrv
}
/* linux-3.4.2\drivers\mtd\chips\chipreg.c */
再由mtd_chip_driver返回do_map_probe执行drv->probe(map):
struct mtd_info *do_map_probe(const char *name, struct map_info *map)
{
struct mtd_chip_driver *drv;
struct mtd_info *ret;
...
ret = drv->probe(map); //drv = &jedec_chipdrv
...
return ret;
}
/* linux-3.4.2\drivers\mtd\chips\chipreg.c */
由于drv = &jedec_chipdrv ,执行执行drv->probe即相当于执行jedec_chipdrv .probe = jedec_probe:
static struct mtd_info *jedec_probe(struct map_info *map)
{
/*
* Just use the generic probe stuff to call our CFI-specific
* chip_probe routine in all the possible permutations, etc.
*/
return mtd_do_chip_probe(map, &jedec_chip_probe);
}
/* linux-3.4.2\drivers\mtd\chips\jedec_probe.c */
其中,jedec_chip_probe 定义如下:
static struct chip_probe jedec_chip_probe = {
.name = "JEDEC",
.probe_chip = jedec_probe_chip
};
/* linux-3.4.2\drivers\mtd\chips\jedec_probe.c */
jedec_probe->mtd_do_chip_probe:
struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
{
struct mtd_info *mtd = NULL;
struct cfi_private *cfi;
/* First probe the map to see if we have CFI stuff there. */
cfi = genprobe_ident_chips(map, cp); //cp = &cfi_chip_probe
...
}
/* linux-3.4.2\drivers\mtd\chips\gen_probe.c */
mtd_do_chip_probe->genprobe_ident_chips:
static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp)
{
struct cfi_private cfi;
struct cfi_private *retcfi;
unsigned long *chip_map;
int i, j, mapsize;
int max_chips;
memset(&cfi, 0, sizeof(cfi));
/* Call the probetype-specific code with all permutations of
interleave and device type, etc. */
if (!genprobe_new_chip(map, cp, &cfi)) {
/* The probe didn't like it */
pr_debug("%s: Found no %s device at location zero\n",
cp->name, map->name);
return NULL;
}
...
}
/* linux-3.4.2\drivers\mtd\chips\gen_probe.c */
genprobe_ident_chips->genprobe_new_chip执行cp->probe_chip:
static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
struct cfi_private *cfi)
{
int min_chips = (map_bankwidth(map)/4?:1); /* At most 4-bytes wide. */
int max_chips = map_bankwidth(map); /* And minimum 1 */
int nr_chips, type;
for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
...
for (; type <= CFI_DEVICETYPE_X32; type<<=1) {
...
if (cp->probe_chip(map, 0, NULL, cfi))
return 1;
}
}
return 0;
}
/* linux-3.4.2\drivers\mtd\chips\gen_probe.c */
由于cp = &jedec_chip_probe,所以执行执行cp->probe_chip相当于执行jedec_chip_probe.probe_chip =jedec_probe_chip 。