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 };
發佈了1 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章