三 初始化
这里我们先说一下几个重要的全局变量:
/drivers/mtd/mtdcore.c
struct mtd_info *mtd_table[MAX_MTD_DEVICES];
该数组中保存了所有的MTD原始设备,
以学习报告001的编译配置为前提,该部分的初始化主要包括mtd部分的和nand部分的。我们要分析的就是前面提到的几个重要文件。至于如何看各个文件是否有初始化的接口,就按模块编写的方式查看有无module_init(init_func)的定义了。
/driver/mtd/mtdcore.c:
module_init(init_mtd);
module_exit(cleanup_mtd);
很明显init_mtd就是会在系统启动时被调用来初始化的函数。我们看这个函数:
/driver/mtd/mtdcore.c:
static int __init init_mtd(void)
{
#ifdef CONFIG_PROC_FS
if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
proc_mtd->read_proc = mtd_read_proc;
#endif
#ifdef CONFIG_PM
mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback);
#endif
return 0;
}
该函数首先在proc文件系统下创建一个保存所有mtd设备信息的目录, 接着注册一个read函数用来读取这个目录下的内容, 最后注册了一个电源管理方面的函数,因为跟分析MTD本身关系不是很到,我们略过。
mtdcore.c里主要export了很多函数, 如add_mtd_device(), del_mtd_device()等, 我们会看到别的部分是如何使用这些export的函数.
接着看mtdpart.c,里面并没有初始化函数,也仅仅是export出来了很多的函数接口, 该文件主要提供了
操作分区方面的API。我们在调用这些函数的时候再来分析他们.
在看mtdchar.c:
/driver/mtd/mtdchar.c:
module_init(init_mtdchar);
module_exit(cleanup_mtdchar);
初始化函数为: init_mtdchar
/driver/mtd/mtdchar.c:
static int __init init_mtdchar(void)
{
if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {
printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices./n",
MTD_CHAR_MAJOR);
return -EAGAIN;
}
mtdchar_devfs_init();
return 0;
}
很简单就是先注册一个字符设备的驱动程序, 让系统记住: 主设备号为MTD_CHAR_MAJOR的字符设备文件对应的文件操作集为mtd_fops。字符设备文件将在系统检测到flash设备时创建。
/driver/mtd/mtdchar.c:
static struct file_operations mtd_fops = {
.owner = THIS_MODULE,
.llseek = mtd_lseek,
.read = mtd_read,
.write = mtd_write,
.ioctl = mtd_ioctl,
.open = mtd_open,
.release = mtd_close,
};
由此可以知道当用户在用户层通过系统调用read函数时将会传递到这里注册的mtd_read函数。
接着调用mtdchar_devfs_init()来在devfs下创建mtdchar。
/driver/mtd/mtdchar.c:
static inline void mtdchar_devfs_init(void)
{
devfs_mk_dir("mtd"); /*创建一个mtd的目录*/
register_mtd_user(¬ifier); /*注册一个notify机器*/
}
接着看一下register_mtd_user()函数:
/driver/mtd/mtdchar.c:
void register_mtd_user (struct mtd_notifier *new)
{
int i;
down(&mtd_table_mutex);
list_add(&new->list, &mtd_notifiers); /*添加到mtd_notifiers列表中去*/
__module_get(THIS_MODULE);
/*对于每个已存在的mtd设备调用notify的add函数*/
for (i=0; i< MAX_MTD_DEVICES; i++)
if (mtd_table[i])
new->add(mtd_table[i]);
up(&mtd_table_mutex);
}
/driver/mtd/mtdchar.c:
static struct mtd_notifier notifier = {
.add = mtd_notify_add,
.remove = mtd_notify_remove,
};
随后我们会看到每当有新的mtd设备要注册时都会调用这些notifier的add函数, 以通知这些notifier有新的mtd设备注册了, 然后我们的notifier就可以为这个mtd做相应的初始化工作了.
OK, 我们重点看下mtd block部分,因为我们以s3c2410的flash为例, 一般nand flash都是block设备.
Drivers/mtd/mtdblock.c:
module_init(init_mtdblock);
/*初始化函数*/
static int __init init_mtdblock(void)
{
return register_mtd_blktrans(&mtdblock_tr);
}
该函数注册了一套操作函数集, 以后我们会看到是如何使用的, mtdblock_tr的定义如下
static struct mtd_blktrans_ops mtdblock_tr = {
.name = "mtdblock",
.major = 31,
.part_bits = 0,
.open = mtdblock_open,
.flush = mtdblock_flush,
.release = mtdblock_release,
.readsect = mtdblock_readsect,
.writesect = mtdblock_writesect,
.add_mtd = mtdblock_add_mtd,
.remove_dev = mtdblock_remove_dev,
.owner = THIS_MODULE,
};
Drivers/mtd/mtd_blkdevs.c:
int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
{
int ret, i;
/* Register the notifier if/when the first device type is
registered, to prevent the link/init ordering from fucking
us over. */
if (!blktrans_notifier.list.next)
register_mtd_user(&blktrans_notifier); /*注册一个notifyer, 跟char的一样,以后会用到*/
/*定义一个私有对象,用以保存信息*/
tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
if (!tr->blkcore_priv)
return -ENOMEM;
memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
down(&mtd_table_mutex);
ret = register_blkdev(tr->major, tr->name); /*注册一个block设备, 具体可参考block驱动的编写*/
if (ret) {
printk(KERN_WARNING "Unable to register %s block device on major %d: %d/n",
tr->name, tr->major, ret);
kfree(tr->blkcore_priv);
up(&mtd_table_mutex);
return ret;
}
/*做初始化工作, 这些都是block驱动必须的东西*/
spin_lock_init(&tr->blkcore_priv->queue_lock);
init_completion(&tr->blkcore_priv->thread_dead);
init_waitqueue_head(&tr->blkcore_priv->thread_wq);
tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);
if (!tr->blkcore_priv->rq) {
unregister_blkdev(tr->major, tr->name);
kfree(tr->blkcore_priv);
up(&mtd_table_mutex);
return -ENOMEM;
}
tr->blkcore_priv->rq->queuedata = tr;
/*创建一个线程, 用来处理用户层对block设备的各种请求*/
ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);
if (ret < 0) {
blk_cleanup_queue(tr->blkcore_priv->rq);
unregister_blkdev(tr->major, tr->name);
kfree(tr->blkcore_priv);
up(&mtd_table_mutex);
return ret;
}
devfs_mk_dir(tr->name);
INIT_LIST_HEAD(&tr->devs);
list_add(&tr->list, &blktrans_majors);
/*如果已有mtd设备存在, 则调用notifier的add回调函数*/
for (i=0; i<MAX_MTD_DEVICES; i++) {
if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT)
tr->add_mtd(tr, mtd_table[i]);
}
up(&mtd_table_mutex);
return 0;
}
blktrans_notifier为
static struct mtd_notifier blktrans_notifier = {
.add = blktrans_notify_add, /*当有新设备添加的时候调用这个函数*/
.remove = blktrans_notify_remove, /*当有设备移除的时候调用这个函数*/
};