MTD 设备学习的笔记

不懂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是手工写的。。。


版权声明:本文为RichardYSteven原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。