对技术执着
分类: 嵌入式
2015-03-14 15:22:46
原文地址:NAND FLASH内核驱动框架分析 作者:会笑的北极星
NAND FLASH在linux-2.6.32中的驱动框架
module_init(s3c2410_nand_init);
static int __init s3c2410_nand_init(void)
{
..................
return platform_driver_register(&s3c24xx_nand_driver);
}
static struct platform_driver s3c24xx_nand_driver = {
.probe = s3c24xx_nand_probe,
.remove = s3c24xx_nand_remove,
.suspend = s3c24xx_nand_suspend,
.resume = s3c24xx_nand_resume,
.id_table = s3c24xx_driver_ids,
.driver = {
.name = "s3c24xx-nand",
.owner = THIS_MODULE,
},
};
static int s3c24xx_nand_probe(struct platform_device *pdev)
{
cpu_type = platform_get_device_id(pdev)->driver_data; // cpu_type = pdev->id_entry->driver_data;
platform_set_drvdata(pdev, info); // pdev->dev->p->driver_data = info;
info->cpu_type = cpu_type;
s3c2410_nand_inithw(info); // writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
s3c2410_nand_init_chip(info, nmtd, sets);
nmtd->scan_res = nand_scan_ident(&nmtd->mtd,(sets) ? sets->nr_chips : 1);
/* Set the default functions */
nand_set_defaults(chip, busw);
/* Read the flash type */
nand_get_flash_type(mtd, chip, busw, &nand_maf_id);
nand_scan_tail(&nmtd->mtd);
s3c2410_nand_add_partition(info, nmtd, sets);
add_mtd_device(&mtd->mtd);
device_create(&mtd_class, mtd->dev.parent, MTD_DEVT(i) + 1, NULL, "mtd%dro", i);
// 在mtdcore.c的初始化函数中class_register(&mtd_class);创建类
list_for_each_entry(not, &mtd_notifiers, list)
not->add(mtd);
问. mtd_notifiers在哪里设置?
答. 在void register_mtd_user (struct mtd_notifier *new)函数调用list_add(&new->list, &mtd_notifiers);添加到链表中
在mtd_blkdevs.c中的int register_mtd_blktrans(struct mtd_blktrans_ops *tr)函数调用register_mtd_user(&blktrans_notifier),还调用了
static struct mtd_notifier blktrans_notifier = {
.add = blktrans_notify_add,
.remove = blktrans_notify_remove,
};
static void blktrans_notify_add(struct mtd_info *mtd)
{
struct mtd_blktrans_ops *tr;
list_for_each_entry(tr, &blktrans_majors, list)
tr->add_mtd(tr, mtd);
问. blktrans_majors在哪里设置?
答. 在int register_mtd_blktrans(struct mtd_blktrans_ops *tr)函数中调用了list_add(&tr->list, &blktrans_majors);
函数int register_mtd_blktrans(struct mtd_blktrans_ops *tr)又在/linux/mtd/mtdblock.c文件和mtdblock_ro.c文件的初始化函数中调用 register_mtd_blktrans(&mtdblock_tr);
在/linux/mtd/mtdblock.c文件中:
static struct mtd_blktrans_ops mtdblock_tr = {
........
.add_mtd = mtdblock_add_mtd,
........
};
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
add_mtd_blktrans_dev(dev);
}
int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
{
gd = alloc_disk(1 << tr->part_bits);
gd->major = tr->major;
gd->first_minor = (new->devnum) << tr->part_bits;
gd->fops = &mtd_blktrans_ops;
set_capacity(gd, (new->size * tr->blksize) >> 9);
gd->queue = tr->blkcore_priv->rq;
add_disk(gd);
}
问. 队列tr->blkcore_priv->rq在哪里设置的?
答. 在mtd_blkdevs.c文件的int register_mtd_blktrans(struct mtd_blktrans_ops *tr)函数中调用tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock)初始化一个队列
在/linux/mtd/mtdblock_ro.c文件中:
static struct mtd_blktrans_ops mtdblock_tr = {
........
.add_mtd = mtdblock_add_mtd,
........
};
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
add_mtd_blktrans_dev(dev);
}