不懂mtd设备,学习之。
第一个找到的函数是init_mtdblock。调用了register_mtd_blktrans函数,传入参数是一个mtd_blktrans_ops类型的结构。
static struct mtd_blktrans_ops mtdblock_tr = {
.name = "mtdblock",
.major = 31,
.part_bits = 0,
.blksize = 512,
.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,
};
static int __init init_mtdblock(void)
{
printk(KERN_EMERG" yw init_mtdblock /n");
return register_mtd_blktrans(&mtdblock_tr);
}
在register_mtd_blktrans中初始化了 mtd_blktrans_ops的blkcore_priv成员。
之后注册了一个块设备,该块设备的主设备号就是31.
blkcore_priv成员的结构如下
struct mtd_blkcore_priv {
struct task_struct *thread; 起了线程mtd_blktrans_thread用来读写,传入参数也是mtd_blktrans_ops
struct request_queue *rq; 这个queue的data又是 mtd_blktrans_ops
spinlock_t queue_lock;
};
这个里面就是一个块设备要使用到的I/O queue 和 这处理这个queue的线程。
在线程mtd_blktrans_thread中,会去读取这个queue,根据queue上的任务调用不同的函数处理。
在函数的最后,根据mtd_table中的值,add_mtd。 暂时不知道这个是做什么的。
但是知道mtd_table是一个mtd_info结构的指针数组。 接下来研究什么时候初始化这个mtd_table的。
========================================================
经过一番搜索我找到了add_mtd_partitions函数,而且发现确实这个函数被调用了。 那就来看看吧。
代码比较少,就全部贴上。
int add_mtd_partitions(struct mtd_info *master, //这个是主的mtd_info 好像一个flash对应一个
const struct mtd_partition *parts, //parts指向了一个数组的第一个,这个整个flash的分区情况
int nbparts) //这个是整个flash分成了几个区
{
struct mtd_part *slave; //注意这个是mtd_part结构,觉得这个是保存在内存中的。
uint64_t cur_offset = 0; // 开始的 offset 是 0
int i;
// 从打印的消息可以看到,nbpart表示了要分多少个区
printk(KERN_NOTICE "Creating %d MTD partitions on /"%s/"/n", nbparts, master->name);
for (i = 0; i < nbparts; i++) {
slave = add_one_partition(master, parts + i, i, cur_offset);
if (!slave)
return -ENOMEM;
cur_offset = slave->offset + slave->mtd.size; // 分好一个区后,cur_offset会向后移动
}
return 0;
}
接下来就看看 add_one_partition函数做了点什么。太长了,截取一些。
static struct mtd_part *add_one_partition(struct mtd_info *master,
const struct mtd_partition *part, int partno,
uint64_t cur_offset)
{
struct mtd_part *slave;
/* allocate the partition structure */
slave = kzalloc(sizeof(*slave), GFP_KERNEL);
list_add(&slave->list, &mtd_partitions);// 把slave加到了一个list中。
slave->mtd.size = part->size; // 大小是part中决定的。
add_mtd_device(&slave->mtd); // 一般会调用add_mtd_device()注册,slave->mtd是mtd_info结构。
}
得,还得看看add_mtd_device()。
int add_mtd_device(struct mtd_info *mtd)
{
int i;
mutex_lock(&mtd_table_mutex); // 锁住
for (i=0; i < MAX_MTD_DEVICES; i++)
if (!mtd_table[i]) {// 在mtd_table中找空的,终于看到这个mtd_table了。那这么看的话,mtd_table对应的是每个partition
mtd_table[i] = mtd;
mtd->index = i;
mtd->usecount = 0;
/* Caller should have set dev.parent to match the
* physical device.
*/
mtd->dev.type = &mtd_devtype;
mtd->dev.class = mtd_class;
mtd->dev.devt = MTD_DEVT(i);
dev_set_name(&mtd->dev, "mtd%d", i); // 设置名称
if (device_register(&mtd->dev) != 0) { // 注册
mtd_table[i] = NULL;
break;
}
if (MTD_DEVT(i))
device_create(mtd_class, mtd->dev.parent, // create?
MTD_DEVT(i) + 1, // 这个create后,会调用到mtdblock_add_mtd,神奇 ,有点晕
NULL, "mtd%dro", i);
mutex_unlock(&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;
}
mutex_unlock(&mtd_table_mutex); // 解锁
return 1;
}
========================================================
好,上面的算告一段落,再来看看mtdblock_add_mtd传入的参数是从哪里来的吧。
这个partition是手工写的。。。