LINUX MTD 驱动

MTD(memory technology device 内存技术设备)是用于访问memory 设备(ROM、flash)的Linux的子系统。
MTD 的主要目的是为了使新的memory 设备的驱动更加简单,为此它在硬件和上层之间提供了一个抽象的接口。
MTD 的所有源代码在/drivers/mtd 子目录下。

概念:

CFI:    Common Flash Interface,通用Flash 接口,Intel 发起的一个Flash 的接口标准
OOB:     out of band,某些内存技术支持out-of-band 数据—--如NAND 每512字节的块有16 个字节的extra data,用于纠错或元数据。
ECC:     error correction,某些硬件不仅允许对flash 的访问,也有ecc 功能,所有flash器件都受位交换现象的困扰。在某些情况下,一个比特位会发生反转或被报告反转了,就要采用ECC 算法。
erasesize:     一个 erase 命令可以擦除的最小块的尺寸
buswidth:    MTD 设备的接口总线宽度
interleave:    交错数,几块芯片平行连接成一块,使 buswidth 变大!!!
devicetype:    芯片类型,x8、x16 或者x32
Wear out:    Flash 的擦除次数有限制,一般在100!!!


mtd_info结构是MTD原始设备层的一个重要结构,该结构定义了大量的关于MTD的数据和操作,定义在include/linux/mtd/mtd.h头文件。mtd_info结构成员主要由数据成员和操作函数两部分组成。


struct mtd_part {
    struct mtd_info mtd;
    struct mtd_info *master;
    uint64_t offset;
    struct list_head list;
};







总结
两种注册方式:
1)直接注册整个flash设备(MTD Device)到MTD。
    ret = add_mtd_device(mtd);

2)分partion添加到mtd_table,并将每个partion当成一个mtd设备注册到MTD。
    if (!(partitions && num_part > 0) )
        ret = add_mtd_partitions(mtd, parts, num_part);



----------------------------------------------------------------------------

mtd_read:
直接直接调用mtd_info 的read 函数,因此,字符设备接口跳过了patition 这一层。
当count>0 时{
    裁减本次操作大小len 至min(MAX_KMALLOC_SIZE,count),
    申请一块大小为MAX_KMALLOC_SIZE 的内核空间kbuf,
    调用mtd_info->read 将MTD 设备中的数据读入kbuf,
    将kbuf 中的数据拷贝到用户空间buf,
    count 自减
    释放kbuf
}

----------------------------------------------------------------------------

Mtd_write
mtd_write 直接直接调用mtd_info 的write 函数,因此,字符设备接口跳过了patition 这一层。
当count>0 时{
    裁减本次操作大小len 至min(MAX_KMALLOC_SIZE,count),
    申请一块大小为MAX_KMALLOC_SIZE 的内核空间kbuf,
    将用户空间buf 中的数据拷贝到kbuf,
    调用mtd_info->write 将kbuf 中的数据读入MTD 设备,
    count 自减
    释放kbuf
}

主要原理是将Flash 的erase block 中的数据在内存中建立映射,然后对其进行修改,最后擦除Flash 上的block,将内存中的映射块写入Flash 块。整个过程被称为read/modify/erase/rewrite 周期。但是,这样做是不安全的,当下列操作序列发生时,read/modify/erase/poweroff,就会丢失这个block 块的数据。块设备模拟驱动按照block 号和偏移量来定位文件,因此在Flash 上除了文件数据,基本没有额外的控制数据。

----------------------------------------------------------------------------


Linux内核在MTD的下层实现了通用的NAND 驱动( 主要通过drivers/mtd/nand/nand_base.c 文件实现),因此芯片级的NAND 驱动不再需要实现mtd_info中的read()、write()、read_oob()、write_oob()等成员函数,而主体转移到了nand_chip数据结构

----------------------------------------------------------------------------


1. 如果Flash要分区,
    则定义mtd_partition数组,将实际电路板中Flash分区信息记录于其中。
2. 在模块加载时分配和nand_chip的内存,根据目标板NAND 控制器的特殊情况初始化nand_chip 中的hwcontrol()、dev_ready()、calculate_ecc()、correct_data()、read_byte()、write_byte()等成员函数(如果不赋值会使用nand_base.c中的默认函数),注意将mtd_info的priv置为nand_chip。
3. 以mtd_info为参数调用nand_scan()函数探测NAND Flash的存在。
4. 如果要分区,
    则以mtd_info和mtd_partition为参数调用add_mtd_partitions()添加分区信息。

----------------------------------------------------------------------------


gpmi_nfc_probe
    gpmi_nfc_mil_init
    初始化nandchip
        nand->cmd_ctrl     = mil_cmd_ctrl;
        nand->dev_ready   = mil_dev_ready;
        nand->select_chip = mil_select_chip;
        nand->read_byte = mil_read_byte;
        nand->read_buf  = mil_read_buf;
        nand->write_buf = mil_write_buf;
        ……
    nand_scan探测
    mil_partitions_init
        add_mtd_device/add_mtd_partitions


----------------------------------------------------------------------------





754     if (mtd_has_cmdlinepart()) {
755         static const char *probes[] __initconst = {
756             "cmdlinepart", NULL
757         };
758
759         mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes,
760                             &mtd_parts, 0);        //-->aa
761     }
762
763     if (mtd_parts_nb <= 0) {
764         mtd_parts = pdata->parts;
765         mtd_parts_nb = pdata->nr_parts;
766     }
767
768     /* Register any partitions */
769     if (mtd_parts_nb > 0) {
770         ret = mtd_device_register(&info->mtd, mtd_parts,
771                       mtd_parts_nb);
772         if (ret == 0)
773             info->partitioned = true;
774     }




-->aa

715 int parse_mtd_partitions(struct mtd_info *master, const char **types,
716              struct mtd_partition **pparts, unsigned long origin)
717 {
718     struct mtd_part_parser *parser;
719     int ret = 0;
720         
721     for ( ; ret <= 0 && *types; types++) {
722         parser = get_partition_parser(*types);
723         if (!parser && !request_module("%s", *types))
724                 parser = get_partition_parser(*types);    //-->bb
725         if (!parser)
726             continue;
727         ret = (*parser->parse_fn)(master, pparts, origin);
728         if (ret > 0) {
729             printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
730                    ret, parser->name, master->name);
731         }
732         put_partition_parser(parser);
733     }
734     return ret;
735 }



-->bb
获得该名字的分析器
679 static struct mtd_part_parser *get_partition_parser(const char *name)    //"cmdlinepart"
680 {
681     struct mtd_part_parser *p, *ret = NULL;
682
683     spin_lock(&part_parser_lock);
684
685     list_for_each_entry(p, &part_parsers, list)    //在链表上找到匹配的
686         if (!strcmp(p->name, name) && try_module_get(p->owner)) {
687             ret = p;
688             break;
689         }
690
691     spin_unlock(&part_parser_lock);
692
693     return ret;
694 }




-- drivers/mtd/cmdlinepart.c --

380 static struct mtd_part_parser cmdline_parser = {
381     .owner = THIS_MODULE,
382     .parse_fn = parse_cmdline_partitions,
383     .name = "cmdlinepart",
384 };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值