add_mtd_partitions的最后调用add_mtd_device(&slave->mtd);把每个分区加进了mtd_table。这个函数在mtdcore.c中,前面提到的如果不分区,你可以直接把主分区做为参数加到mtd_table中。
Mtdcore.c如其名,它叫core是有原因的:它不调用mtd驱动各层次的任何外部函数(除了注册的回调函数)而只是输出函数,它管理着mtd_table。底层通过add_mtd_device和del_mtd_device来添加和删除原始设备(分区)。上层字符设备和块设备部分通过get_mtd_device和put_mtd_device来申请和释放分区等等。
int add_mtd_device(struct mtd_info *mtd)
{
int i;
down(&mtd_table_mutex);
for (i=0; i < MAX_MTD_DEVICES; i++)
if (!mtd_table[i]) {
struct list_head *this;
mtd_table[i] = mtd;
mtd->index = i;
mtd->usecount = 0;
DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
/* No need to get a refcount on the module containing
the notifier, since we hold the mtd_table_mutex */
list_for_each(this, &mtd_notifiers) {
struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);
not->add(mtd);//我的观点是如果你不打算动态增加和删除设备的话这一
//部分是没有必要的。系统初始化mtd设备时,这个链表也是空的。
}
up(&mtd_table_mutex);
/* We _know_ we aren't being removed, because
our caller is still holding us here. So none
of this try_ nonsense, and no bitching about it
either. :) */
__module_get(THIS_MODULE);
return 0;
}
up(&mtd_table_mutex);
return 1;
}
整个函数比较简单,在mtd_table中选择一个空位置放置你的分区的mtd_info。红色部分是比较难懂一点的:这个mtd_notifiers链表起什么作用?看看谁在这个链表中加了东西。register_mtd_user是唯一向这个链表添加了成员的,谁调了?看一下下面的程序
void register_mtd_user (struct mtd_notifier *new)
{
int i;
down(&mtd_table_mutex);
list_add(&new->list, &mtd_notifiers);
__module_get(THIS_MODULE);
for (i=0; i< MAX_MTD_DEVICES; i++)
if (mtd_table[i])
new->add(mtd_table[i]);
up(&mtd_table_mutex);
}
static inline void mtdchar_devfs_init(void)
{
devfs_mk_dir("mtd");
register_mtd_user(¬ifier);
}
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);
。。。。。省略n行
return 0;
}
看来这个链表里面通常就只有两个成员。作用是当删除或添加一个mtd分区时告诉建立在其上的字符设备和块设备驱动。干什么?
当创建mtd字符设备时会调用mtdchar_devfs_init,他的notifier是这样的:
static struct mtd_notifier notifier = {
.add = mtd_notify_add,
.remove = mtd_notify_remove,
};
static void mtd_notify_add(struct mtd_info* mtd)
{
if (!mtd)
return;
devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
}
这个devfs_mk_cdev应该就是自动创建devfs的节点吧,是不是就是不用再mknod了?我真的是linux新手,如果有人知道请不吝赐教,我只是从名字上猜测的。
总结一下: