日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux MTD系统剖析【转】

發布時間:2025/3/21 linux 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux MTD系统剖析【转】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://blog.csdn.net/lwj103862095/article/details/21545791

?

版權聲明:本文為博主原創文章,未經博主允許不得轉載。

MTD,Memory Technology Device即內存技術設備,在Linux內核中,引入MTD層為NOR FLASH和NAND FLASH設備提供統一接口。MTD將文件系統與底層FLASH存儲器進行了隔離。

如上圖所示,MTD設備通常可分為四層,從上到下依次是:設備節點、MTD設備層、MTD原始設備層、硬件驅動層。

Flash硬件驅動層:Flash硬件驅動層負責對Flash硬件的讀、寫和擦除操作。MTD設備的Nand Flash芯片的驅動則drivers/mtd/nand/子目錄下,Nor Flash芯片驅動位于drivers/mtd/chips/子目錄下。

MTD原始設備層:用于描述MTD原始設備的數據結構是mtd_info,它定義了大量的關于MTD的數據和操作函數。其中mtdcore.c: ?MTD原始設備接口相關實現,mtdpart.c?: ?MTD分區接口相關實現。

MTD設備層:基于MTD原始設備,linux系統可以定義出MTD的塊設備(主設備號31)字符設備(設備號90)。其中mtdchar.c?: ?MTD字符設備接口相關實現,mtdblock.c?: MTD塊設備接口相關實現。

設備節點:通過mknod在/dev子目錄下建立MTD塊設備節點(主設備號為31)MTD字符設備節點(主設備號為90)。通過訪問此設備節點即可訪問MTD字符設備和塊設備?

MTD數據結構:

1.Linux內核使用mtd_info結構體表示MTD原始設備,這其中定義了大量關于MTD的數據和操作函數(后面將會看到),所有的mtd_info結構體存放在mtd_table結構體數據里。在/drivers/mtd/mtdcore.c里:

?

[cpp]?view plaincopy? print?
  • struct?mtd_info?*mtd_table[MAX_MTD_DEVICES];??
  • 2.Linux內核使用mtd_part結構體表示分區,其中mtd_info結構體成員用于描述該分區,大部分成員由其主分區mtd_part->master決定,各種函數也指向主分區的相應函數。

    ?

    ?

    [cpp]?view plaincopy? print?
  • struct?mtd_part?{??
  • ????struct?mtd_info?mtd;????????/*?分區信息,?大部分由master決定?*/??
  • ????struct?mtd_info?*master;????/*?分區的主分區?*/??
  • ????uint64_t?offset;????????????/*?分區的偏移地址?*/??
  • ????int?index;??????????????????/*?分區號?(Linux3.0后不存在該字段)?*/??
  • ????struct?list_head?list;??????/*?將mtd_part鏈成一個鏈表mtd_partitons?*/??
  • ????int?registered;??
  • };??
  • mtd_info結構體主要成員,為了便于觀察,將重要的數據放在前面,不大重要的編寫在后面。

    ?

    ?

    [cpp]?view plaincopy? print?
  • struct?mtd_info?{??
  • ????u_char?type;?????????/*?MTD類型,包括MTD_NORFLASH,MTD_NANDFLASH等(可參考mtd-abi.h)?*/??
  • ????uint32_t?flags;??????/*?MTD屬性標志,MTD_WRITEABLE,MTD_NO_ERASE等(可參考mtd-abi.h)?*/??
  • ????uint64_t?size;???????/*?mtd設備的大小?*/??
  • ????uint32_t?erasesize;??/*?MTD設備的擦除單元大小,對于NandFlash來說就是Block的大小?*/??
  • ????uint32_t?writesize;??/*?寫大小,?對于norFlash是字節,對nandFlash為一頁?*/??
  • ????uint32_t?oobsize;????/*?OOB字節數?*/??
  • ????uint32_t?oobavail;???/*?可用的OOB字節數?*/??
  • ????unsigned?int?erasesize_shift;???/*?默認為0,不重要?*/??
  • ????unsigned?int?writesize_shift;???/*?默認為0,不重要?*/??
  • ????unsigned?int?erasesize_mask;????/*?默認為1,不重要?*/??
  • ????unsigned?int?writesize_mask;????/*?默認為1,不重要?*/??
  • ????const?char?*name;???????????????/*?名字,???不重要*/??
  • ????int?index;??????????????????????/*?索引號,不重要?*/??
  • ????int?numeraseregions;????????????/*?通常為1?*/??
  • ????struct?mtd_erase_region_info?*eraseregions;?/*?可變擦除區域?*/??
  • ??????
  • ????void?*priv;?????/*?設備私有數據指針,對于NandFlash來說指nand_chip結構體?*/??
  • ????struct?module?*owner;???/*?一般設置為THIS_MODULE?*/??
  • ??????
  • ????/*?擦除函數?*/??
  • ????int?(*erase)?(struct?mtd_info?*mtd,?struct?erase_info?*instr);??
  • ??
  • ????/*?讀寫flash函數?*/??
  • ????int?(*read)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*retlen,?u_char?*buf);??
  • ????int?(*write)?(struct?mtd_info?*mtd,?loff_t?to,?size_t?len,?size_t?*retlen,?const?u_char?*buf);??
  • ??
  • ????/*?帶oob讀寫Flash函數?*/??
  • ????int?(*read_oob)?(struct?mtd_info?*mtd,?loff_t?from,??
  • ?????????????struct?mtd_oob_ops?*ops);??
  • ????int?(*write_oob)?(struct?mtd_info?*mtd,?loff_t?to,??
  • ?????????????struct?mtd_oob_ops?*ops);??
  • ??
  • ????int?(*get_fact_prot_info)?(struct?mtd_info?*mtd,?struct?otp_info?*buf,?size_t?len);??
  • ????int?(*read_fact_prot_reg)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*retlen,?u_char?*buf);??
  • ????int?(*get_user_prot_info)?(struct?mtd_info?*mtd,?struct?otp_info?*buf,?size_t?len);??
  • ????int?(*read_user_prot_reg)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*retlen,?u_char?*buf);??
  • ????int?(*write_user_prot_reg)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*retlen,?u_char?*buf);??
  • ????int?(*lock_user_prot_reg)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len);??
  • ??
  • ????int?(*writev)?(struct?mtd_info?*mtd,?const?struct?kvec?*vecs,?unsigned?long?count,?loff_t?to,?size_t?*retlen);??
  • ????int?(*panic_write)?(struct?mtd_info?*mtd,?loff_t?to,?size_t?len,?size_t?*retlen,?const?u_char?*buf);??
  • ????/*?Sync?*/??
  • ????void?(*sync)?(struct?mtd_info?*mtd);??
  • ??
  • ????/*?Chip-supported?device?locking?*/??
  • ????int?(*lock)?(struct?mtd_info?*mtd,?loff_t?ofs,?uint64_t?len);??
  • ????int?(*unlock)?(struct?mtd_info?*mtd,?loff_t?ofs,?uint64_t?len);??
  • ??
  • ????/*?電源管理函數?*/??
  • ????int?(*suspend)?(struct?mtd_info?*mtd);??
  • ????void?(*resume)?(struct?mtd_info?*mtd);??
  • ??
  • ????/*?壞塊管理函數?*/??
  • ????int?(*block_isbad)?(struct?mtd_info?*mtd,?loff_t?ofs);??
  • ????int?(*block_markbad)?(struct?mtd_info?*mtd,?loff_t?ofs);??
  • ??
  • ????void?(*unpoint)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len);??
  • ????unsigned?long?(*get_unmapped_area)?(struct?mtd_info?*mtd,??
  • ????????????????????????unsigned?long?len,??
  • ????????????????????????unsigned?long?offset,??
  • ????????????????????????unsigned?long?flags);??
  • ????struct?backing_dev_info?*backing_dev_info;??
  • ????struct?notifier_block?reboot_notifier;??/*?default?mode?before?reboot?*/??
  • ??
  • ????/*?ECC?status?information?*/??
  • ????struct?mtd_ecc_stats?ecc_stats;??
  • ????int?subpage_sft;??
  • ????struct?device?dev;??
  • ????int?usecount;??
  • ????int?(*get_device)?(struct?mtd_info?*mtd);??
  • ????void?(*put_device)?(struct?mtd_info?*mtd);??
  • };??
  • mtd_info結構體中的read()、write()、read_oob()、write_oob()、erase()是MTD設備驅動要實現的主要函數,幸運的是Linux大牛已經幫我們實現了一套適合大部分FLASH設備的mtd_info成員函數。

    ?

    如果MTD設備只有一個分區,那么使用下面兩個函數注冊和注銷MTD設備。

    ?

    [cpp]?view plaincopy? print?
  • int?add_mtd_device(struct?mtd_info?*mtd)??
  • int?del_mtd_device?(struct?mtd_info?*mtd)??
  • 如果MTD設備存在其他分區,那么使用下面兩個函數注冊和注銷MTD設備。
    [cpp]?view plaincopy? print?
  • int?add_mtd_partitions(struct?mtd_info?*master,const?struct?mtd_partition?*parts,int?nbparts)??
  • int?del_mtd_partitions(struct?mtd_info?*master)??
  • 其中mtd_partition結構體表示分區的信息

    ?

    ?

    [cpp]?view plaincopy? print?
  • struct?mtd_partition?{??
  • ????char?*name;?????????????/*?分區名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2?*/??
  • ????uint64_t?size;??????????/*?分區大小?*/??
  • ????uint64_t?offset;????????/*?分區偏移值?*/??
  • ????uint32_t?mask_flags;????/*?掩碼標識,不重要?*/??
  • ????struct?nand_ecclayout?*ecclayout;???/*?OOB布局?*/??
  • ????struct?mtd_info?**mtdp;?????/*?pointer?to?store?the?MTD?object?*/??
  • };??
  • 其中nand_ecclayout結構體:??
  • struct?nand_ecclayout?{??
  • ????__u32?eccbytes;?????/*?ECC字節數?*/??
  • ????__u32?eccpos[64];???/*?ECC校驗碼在OOB區域存放位置?*/??
  • ????__u32?oobavail;???????
  • ????/*?除了ECC校驗碼之外可用的OOB字節數?*/??
  • ????struct?nand_oobfree?oobfree[MTD_MAX_OOBFREE_ENTRIES];??
  • };??
  • 關于nand_ecclayout結構體實例,更多可參考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64實例。
    MTD設備層:

    ?

    mtd字符設備接口:

    /drivers/mtd/mtdchar.c文件實現了MTD字符設備接口,通過它,可以直接訪問Flash設備,與前面的字符驅動一樣,通過file_operations結構體里面的open()、read()、write()、ioctl()可以讀寫Flash,通過一系列IOCTL 命令可以獲取Flash 設備信息、擦除Flash、讀寫NAND 的OOB、獲取OOB layout 及檢查NAND 壞塊等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL)?

    mtd塊設備接口:

    /drivers/mtd/mtdblock.c文件實現了MTD塊設備接口,主要原理是將Flash的erase block 中的數據在內存中建立映射,然后對其進行修改,最后擦除Flash 上的block,將內存中的映射塊寫入Flash 塊。整個過程被稱為read/modify/erase/rewrite 周期。?但是,這樣做是不安全的,當下列操作序列發生時,read/modify/erase/poweroff,就會丟失這個block 塊的數據。
    MTD硬件驅動層:

    Linux內核再MTD層下實現了通用的NAND驅動(/driver/mtd/nand/nand_base.c),因此芯片級的NAND驅動不再需要實現mtd_info結構體中的read()、write()、read_oob()、write_oob()等成員函數。

    MTD使用nand_chip來表示一個NAND FLASH芯片, 該結構體包含了關于Nand Flash的地址信息,讀寫方法,ECC模式,硬件控制等一系列底層機制。

    ?

    [cpp]?view plaincopy? print?
  • struct?nand_chip?{??
  • ????void??__iomem???*IO_ADDR_R;?????/*?讀8位I/O線地址?*/??
  • ????void??__iomem???*IO_ADDR_W;?????/*?寫8位I/O線地址?*/??
  • ??
  • ????/*?從芯片中讀一個字節?*/??
  • ????uint8_t?(*read_byte)(struct?mtd_info?*mtd);???????
  • ????/*?從芯片中讀一個字?*/??
  • ????u16?????(*read_word)(struct?mtd_info?*mtd);???????
  • ????/*?將緩沖區內容寫入芯片?*/??
  • ????void????(*write_buf)(struct?mtd_info?*mtd,?const?uint8_t?*buf,?int?len);??????
  • ????/*?讀芯片讀取內容至緩沖區/?*/??
  • ????void????(*read_buf)(struct?mtd_info?*mtd,?uint8_t?*buf,?int?len);??
  • ????/*?驗證芯片和寫入緩沖區中的數據?*/??
  • ????int?????(*verify_buf)(struct?mtd_info?*mtd,?const?uint8_t?*buf,?int?len);??
  • ????/*?選中芯片?*/??
  • ????void????(*select_chip)(struct?mtd_info?*mtd,?int?chip);??
  • ????/*?檢測是否有壞塊?*/??
  • ????int?????(*block_bad)(struct?mtd_info?*mtd,?loff_t?ofs,?int?getchip);??
  • ????/*?標記壞塊?*/??
  • ????int?????(*block_markbad)(struct?mtd_info?*mtd,?loff_t?ofs);??
  • ????/*?命令、地址、數據控制函數?*/??
  • ????void????(*cmd_ctrl)(struct?mtd_info?*mtd,?int?dat,unsigned?int?ctrl);??
  • ????/*?設備是否就緒?*/??
  • ????int?????(*dev_ready)(struct?mtd_info?*mtd);??
  • ????/*?實現命令發送?*/??
  • ????void????(*cmdfunc)(struct?mtd_info?*mtd,?unsigned?command,?int?column,?int?page_addr);??
  • ????int?????(*waitfunc)(struct?mtd_info?*mtd,?struct?nand_chip?*this);??
  • ????/*?擦除命令的處理?*/??
  • ????void????(*erase_cmd)(struct?mtd_info?*mtd,?int?page);??
  • ????/*?掃描壞塊?*/??
  • ????int?????(*scan_bbt)(struct?mtd_info?*mtd);??
  • ????int?????(*errstat)(struct?mtd_info?*mtd,?struct?nand_chip?*this,?int?state,?int?status,?int?page);??
  • ????/*?寫一頁?*/??
  • ????int?????(*write_page)(struct?mtd_info?*mtd,?struct?nand_chip?*chip,??
  • ??????????????????????const?uint8_t?*buf,?int?page,?int?cached,?int?raw);??
  • ??
  • ????int?????chip_delay;?????????/*?由板決定的延遲時間?*/??
  • ????/*?與具體的NAND芯片相關的一些選項,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等?*/??
  • ????unsigned?int????options;??????
  • ??
  • ????/*?用位表示的NAND芯片的page大小,如某片NAND芯片?
  • ?????*?的一個page有512個字節,那么page_shift就是9??
  • ?????*/??
  • ????int??????page_shift;??
  • ????/*?用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可?
  • ?????*?擦除16K字節(通常就是一個block的大小),那么phys_erase_shift就是14?
  • ?????*/??
  • ????int??????phys_erase_shift;??
  • ????/*?用位表示的bad?block?table的大小,通常一個bbt占用一個block,?
  • ?????*?所以bbt_erase_shift通常與phys_erase_shift相等?
  • ?????*/??
  • ????int??????bbt_erase_shift;??
  • ????/*?用位表示的NAND芯片的容量?*/??
  • ????int??????chip_shift;??
  • ????/*?NADN?FLASH芯片的數量?*/??
  • ????int??????numchips;??
  • ????/*?NAND芯片的大小?*/??
  • ????uint64_t?chipsize;??
  • ????int??????pagemask;??
  • ????int??????pagebuf;??
  • ????int??????subpagesize;??
  • ????uint8_t??cellinfo;??
  • ????int??????badblockpos;??
  • ????nand_state_t????state;??
  • ????uint8_t?????*oob_poi;??
  • ????struct?nand_hw_control??*controller;??
  • ????struct?nand_ecclayout???*ecclayout;?/*?ECC布局?*/??
  • ??????
  • ????struct?nand_ecc_ctrl?ecc;???/*?ECC校驗結構體,里面有大量的函數進行ECC校驗?*/??
  • ????struct?nand_buffers?*buffers;??
  • ????struct?nand_hw_control?hwcontrol;??
  • ????struct?mtd_oob_ops?ops;??
  • ????uint8_t?????*bbt;??
  • ????struct?nand_bbt_descr???*bbt_td;??
  • ????struct?nand_bbt_descr???*bbt_md;??
  • ????struct?nand_bbt_descr???*badblock_pattern;??
  • ????void????????*priv;??
  • };??
  • 最后,我們來用圖表的形式來總結一下,MTD設備層、MTD原始設備層、FLASH硬件驅動層之間的聯系。

    ?

    ?

    ?

    ?

    版權聲明:本文為博主原創文章,未經博主允許不得轉載。

    MTD,Memory Technology Device即內存技術設備,在Linux內核中,引入MTD層為NOR FLASH和NAND FLASH設備提供統一接口。MTD將文件系統與底層FLASH存儲器進行了隔離。

    如上圖所示,MTD設備通常可分為四層,從上到下依次是:設備節點、MTD設備層、MTD原始設備層、硬件驅動層。

    Flash硬件驅動層:Flash硬件驅動層負責對Flash硬件的讀、寫和擦除操作。MTD設備的Nand Flash芯片的驅動則drivers/mtd/nand/子目錄下,Nor Flash芯片驅動位于drivers/mtd/chips/子目錄下。

    MTD原始設備層:用于描述MTD原始設備的數據結構是mtd_info,它定義了大量的關于MTD的數據和操作函數。其中mtdcore.c: ?MTD原始設備接口相關實現,mtdpart.c?: ?MTD分區接口相關實現。

    MTD設備層:基于MTD原始設備,linux系統可以定義出MTD的塊設備(主設備號31)字符設備(設備號90)。其中mtdchar.c?: ?MTD字符設備接口相關實現,mtdblock.c?: MTD塊設備接口相關實現。

    設備節點:通過mknod在/dev子目錄下建立MTD塊設備節點(主設備號為31)MTD字符設備節點(主設備號為90)。通過訪問此設備節點即可訪問MTD字符設備和塊設備?

    MTD數據結構:

    1.Linux內核使用mtd_info結構體表示MTD原始設備,這其中定義了大量關于MTD的數據和操作函數(后面將會看到),所有的mtd_info結構體存放在mtd_table結構體數據里。在/drivers/mtd/mtdcore.c里:

    ?

    [cpp]?view plaincopy? print?
  • struct?mtd_info?*mtd_table[MAX_MTD_DEVICES];??
  • 2.Linux內核使用mtd_part結構體表示分區,其中mtd_info結構體成員用于描述該分區,大部分成員由其主分區mtd_part->master決定,各種函數也指向主分區的相應函數。

    ?

    ?

    [cpp]?view plaincopy? print?
  • struct?mtd_part?{??
  • ????struct?mtd_info?mtd;????????/*?分區信息,?大部分由master決定?*/??
  • ????struct?mtd_info?*master;????/*?分區的主分區?*/??
  • ????uint64_t?offset;????????????/*?分區的偏移地址?*/??
  • ????int?index;??????????????????/*?分區號?(Linux3.0后不存在該字段)?*/??
  • ????struct?list_head?list;??????/*?將mtd_part鏈成一個鏈表mtd_partitons?*/??
  • ????int?registered;??
  • };??
  • mtd_info結構體主要成員,為了便于觀察,將重要的數據放在前面,不大重要的編寫在后面。

    ?

    ?

    [cpp]?view plaincopy? print?
  • struct?mtd_info?{??
  • ????u_char?type;?????????/*?MTD類型,包括MTD_NORFLASH,MTD_NANDFLASH等(可參考mtd-abi.h)?*/??
  • ????uint32_t?flags;??????/*?MTD屬性標志,MTD_WRITEABLE,MTD_NO_ERASE等(可參考mtd-abi.h)?*/??
  • ????uint64_t?size;???????/*?mtd設備的大小?*/??
  • ????uint32_t?erasesize;??/*?MTD設備的擦除單元大小,對于NandFlash來說就是Block的大小?*/??
  • ????uint32_t?writesize;??/*?寫大小,?對于norFlash是字節,對nandFlash為一頁?*/??
  • ????uint32_t?oobsize;????/*?OOB字節數?*/??
  • ????uint32_t?oobavail;???/*?可用的OOB字節數?*/??
  • ????unsigned?int?erasesize_shift;???/*?默認為0,不重要?*/??
  • ????unsigned?int?writesize_shift;???/*?默認為0,不重要?*/??
  • ????unsigned?int?erasesize_mask;????/*?默認為1,不重要?*/??
  • ????unsigned?int?writesize_mask;????/*?默認為1,不重要?*/??
  • ????const?char?*name;???????????????/*?名字,???不重要*/??
  • ????int?index;??????????????????????/*?索引號,不重要?*/??
  • ????int?numeraseregions;????????????/*?通常為1?*/??
  • ????struct?mtd_erase_region_info?*eraseregions;?/*?可變擦除區域?*/??
  • ??????
  • ????void?*priv;?????/*?設備私有數據指針,對于NandFlash來說指nand_chip結構體?*/??
  • ????struct?module?*owner;???/*?一般設置為THIS_MODULE?*/??
  • ??????
  • ????/*?擦除函數?*/??
  • ????int?(*erase)?(struct?mtd_info?*mtd,?struct?erase_info?*instr);??
  • ??
  • ????/*?讀寫flash函數?*/??
  • ????int?(*read)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*retlen,?u_char?*buf);??
  • ????int?(*write)?(struct?mtd_info?*mtd,?loff_t?to,?size_t?len,?size_t?*retlen,?const?u_char?*buf);??
  • ??
  • ????/*?帶oob讀寫Flash函數?*/??
  • ????int?(*read_oob)?(struct?mtd_info?*mtd,?loff_t?from,??
  • ?????????????struct?mtd_oob_ops?*ops);??
  • ????int?(*write_oob)?(struct?mtd_info?*mtd,?loff_t?to,??
  • ?????????????struct?mtd_oob_ops?*ops);??
  • ??
  • ????int?(*get_fact_prot_info)?(struct?mtd_info?*mtd,?struct?otp_info?*buf,?size_t?len);??
  • ????int?(*read_fact_prot_reg)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*retlen,?u_char?*buf);??
  • ????int?(*get_user_prot_info)?(struct?mtd_info?*mtd,?struct?otp_info?*buf,?size_t?len);??
  • ????int?(*read_user_prot_reg)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*retlen,?u_char?*buf);??
  • ????int?(*write_user_prot_reg)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len,?size_t?*retlen,?u_char?*buf);??
  • ????int?(*lock_user_prot_reg)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len);??
  • ??
  • ????int?(*writev)?(struct?mtd_info?*mtd,?const?struct?kvec?*vecs,?unsigned?long?count,?loff_t?to,?size_t?*retlen);??
  • ????int?(*panic_write)?(struct?mtd_info?*mtd,?loff_t?to,?size_t?len,?size_t?*retlen,?const?u_char?*buf);??
  • ????/*?Sync?*/??
  • ????void?(*sync)?(struct?mtd_info?*mtd);??
  • ??
  • ????/*?Chip-supported?device?locking?*/??
  • ????int?(*lock)?(struct?mtd_info?*mtd,?loff_t?ofs,?uint64_t?len);??
  • ????int?(*unlock)?(struct?mtd_info?*mtd,?loff_t?ofs,?uint64_t?len);??
  • ??
  • ????/*?電源管理函數?*/??
  • ????int?(*suspend)?(struct?mtd_info?*mtd);??
  • ????void?(*resume)?(struct?mtd_info?*mtd);??
  • ??
  • ????/*?壞塊管理函數?*/??
  • ????int?(*block_isbad)?(struct?mtd_info?*mtd,?loff_t?ofs);??
  • ????int?(*block_markbad)?(struct?mtd_info?*mtd,?loff_t?ofs);??
  • ??
  • ????void?(*unpoint)?(struct?mtd_info?*mtd,?loff_t?from,?size_t?len);??
  • ????unsigned?long?(*get_unmapped_area)?(struct?mtd_info?*mtd,??
  • ????????????????????????unsigned?long?len,??
  • ????????????????????????unsigned?long?offset,??
  • ????????????????????????unsigned?long?flags);??
  • ????struct?backing_dev_info?*backing_dev_info;??
  • ????struct?notifier_block?reboot_notifier;??/*?default?mode?before?reboot?*/??
  • ??
  • ????/*?ECC?status?information?*/??
  • ????struct?mtd_ecc_stats?ecc_stats;??
  • ????int?subpage_sft;??
  • ????struct?device?dev;??
  • ????int?usecount;??
  • ????int?(*get_device)?(struct?mtd_info?*mtd);??
  • ????void?(*put_device)?(struct?mtd_info?*mtd);??
  • };??
  • mtd_info結構體中的read()、write()、read_oob()、write_oob()、erase()是MTD設備驅動要實現的主要函數,幸運的是Linux大牛已經幫我們實現了一套適合大部分FLASH設備的mtd_info成員函數。

    ?

    如果MTD設備只有一個分區,那么使用下面兩個函數注冊和注銷MTD設備。

    ?

    [cpp]?view plaincopy? print?
  • int?add_mtd_device(struct?mtd_info?*mtd)??
  • int?del_mtd_device?(struct?mtd_info?*mtd)??
  • 如果MTD設備存在其他分區,那么使用下面兩個函數注冊和注銷MTD設備。
    [cpp]?view plaincopy? print?
  • int?add_mtd_partitions(struct?mtd_info?*master,const?struct?mtd_partition?*parts,int?nbparts)??
  • int?del_mtd_partitions(struct?mtd_info?*master)??
  • 其中mtd_partition結構體表示分區的信息

    ?

    ?

    [cpp]?view plaincopy? print?
  • struct?mtd_partition?{??
  • ????char?*name;?????????????/*?分區名,如TQ2440_Board_uboot、TQ2440_Board_kernel、TQ2440_Board_yaffs2?*/??
  • ????uint64_t?size;??????????/*?分區大小?*/??
  • ????uint64_t?offset;????????/*?分區偏移值?*/??
  • ????uint32_t?mask_flags;????/*?掩碼標識,不重要?*/??
  • ????struct?nand_ecclayout?*ecclayout;???/*?OOB布局?*/??
  • ????struct?mtd_info?**mtdp;?????/*?pointer?to?store?the?MTD?object?*/??
  • };??
  • 其中nand_ecclayout結構體:??
  • struct?nand_ecclayout?{??
  • ????__u32?eccbytes;?????/*?ECC字節數?*/??
  • ????__u32?eccpos[64];???/*?ECC校驗碼在OOB區域存放位置?*/??
  • ????__u32?oobavail;???????
  • ????/*?除了ECC校驗碼之外可用的OOB字節數?*/??
  • ????struct?nand_oobfree?oobfree[MTD_MAX_OOBFREE_ENTRIES];??
  • };??
  • 關于nand_ecclayout結構體實例,更多可參考drivers/mtd/nand/nand_base.c下的nand_oob_8、nand_oob_16、nand_oob_64實例。
    MTD設備層:

    ?

    mtd字符設備接口:

    /drivers/mtd/mtdchar.c文件實現了MTD字符設備接口,通過它,可以直接訪問Flash設備,與前面的字符驅動一樣,通過file_operations結構體里面的open()、read()、write()、ioctl()可以讀寫Flash,通過一系列IOCTL 命令可以獲取Flash 設備信息、擦除Flash、讀寫NAND 的OOB、獲取OOB layout 及檢查NAND 壞塊等(MEMGETINFO、MEMERASE、MEMREADOOB、MEMWRITEOOB、MEMGETBADBLOCK IOCRL)?

    mtd塊設備接口:

    /drivers/mtd/mtdblock.c文件實現了MTD塊設備接口,主要原理是將Flash的erase block 中的數據在內存中建立映射,然后對其進行修改,最后擦除Flash 上的block,將內存中的映射塊寫入Flash 塊。整個過程被稱為read/modify/erase/rewrite 周期。?但是,這樣做是不安全的,當下列操作序列發生時,read/modify/erase/poweroff,就會丟失這個block 塊的數據。
    MTD硬件驅動層:

    Linux內核再MTD層下實現了通用的NAND驅動(/driver/mtd/nand/nand_base.c),因此芯片級的NAND驅動不再需要實現mtd_info結構體中的read()、write()、read_oob()、write_oob()等成員函數。

    MTD使用nand_chip來表示一個NAND FLASH芯片, 該結構體包含了關于Nand Flash的地址信息,讀寫方法,ECC模式,硬件控制等一系列底層機制。

    ?

    [cpp]?view plaincopy? print?
  • struct?nand_chip?{??
  • ????void??__iomem???*IO_ADDR_R;?????/*?讀8位I/O線地址?*/??
  • ????void??__iomem???*IO_ADDR_W;?????/*?寫8位I/O線地址?*/??
  • ??
  • ????/*?從芯片中讀一個字節?*/??
  • ????uint8_t?(*read_byte)(struct?mtd_info?*mtd);???????
  • ????/*?從芯片中讀一個字?*/??
  • ????u16?????(*read_word)(struct?mtd_info?*mtd);???????
  • ????/*?將緩沖區內容寫入芯片?*/??
  • ????void????(*write_buf)(struct?mtd_info?*mtd,?const?uint8_t?*buf,?int?len);??????
  • ????/*?讀芯片讀取內容至緩沖區/?*/??
  • ????void????(*read_buf)(struct?mtd_info?*mtd,?uint8_t?*buf,?int?len);??
  • ????/*?驗證芯片和寫入緩沖區中的數據?*/??
  • ????int?????(*verify_buf)(struct?mtd_info?*mtd,?const?uint8_t?*buf,?int?len);??
  • ????/*?選中芯片?*/??
  • ????void????(*select_chip)(struct?mtd_info?*mtd,?int?chip);??
  • ????/*?檢測是否有壞塊?*/??
  • ????int?????(*block_bad)(struct?mtd_info?*mtd,?loff_t?ofs,?int?getchip);??
  • ????/*?標記壞塊?*/??
  • ????int?????(*block_markbad)(struct?mtd_info?*mtd,?loff_t?ofs);??
  • ????/*?命令、地址、數據控制函數?*/??
  • ????void????(*cmd_ctrl)(struct?mtd_info?*mtd,?int?dat,unsigned?int?ctrl);??
  • ????/*?設備是否就緒?*/??
  • ????int?????(*dev_ready)(struct?mtd_info?*mtd);??
  • ????/*?實現命令發送?*/??
  • ????void????(*cmdfunc)(struct?mtd_info?*mtd,?unsigned?command,?int?column,?int?page_addr);??
  • ????int?????(*waitfunc)(struct?mtd_info?*mtd,?struct?nand_chip?*this);??
  • ????/*?擦除命令的處理?*/??
  • ????void????(*erase_cmd)(struct?mtd_info?*mtd,?int?page);??
  • ????/*?掃描壞塊?*/??
  • ????int?????(*scan_bbt)(struct?mtd_info?*mtd);??
  • ????int?????(*errstat)(struct?mtd_info?*mtd,?struct?nand_chip?*this,?int?state,?int?status,?int?page);??
  • ????/*?寫一頁?*/??
  • ????int?????(*write_page)(struct?mtd_info?*mtd,?struct?nand_chip?*chip,??
  • ??????????????????????const?uint8_t?*buf,?int?page,?int?cached,?int?raw);??
  • ??
  • ????int?????chip_delay;?????????/*?由板決定的延遲時間?*/??
  • ????/*?與具體的NAND芯片相關的一些選項,如NAND_NO_AUTOINCR,NAND_BUSWIDTH_16等?*/??
  • ????unsigned?int????options;??????
  • ??
  • ????/*?用位表示的NAND芯片的page大小,如某片NAND芯片?
  • ?????*?的一個page有512個字節,那么page_shift就是9??
  • ?????*/??
  • ????int??????page_shift;??
  • ????/*?用位表示的NAND芯片的每次可擦除的大小,如某片NAND芯片每次可?
  • ?????*?擦除16K字節(通常就是一個block的大小),那么phys_erase_shift就是14?
  • ?????*/??
  • ????int??????phys_erase_shift;??
  • ????/*?用位表示的bad?block?table的大小,通常一個bbt占用一個block,?
  • ?????*?所以bbt_erase_shift通常與phys_erase_shift相等?
  • ?????*/??
  • ????int??????bbt_erase_shift;??
  • ????/*?用位表示的NAND芯片的容量?*/??
  • ????int??????chip_shift;??
  • ????/*?NADN?FLASH芯片的數量?*/??
  • ????int??????numchips;??
  • ????/*?NAND芯片的大小?*/??
  • ????uint64_t?chipsize;??
  • ????int??????pagemask;??
  • ????int??????pagebuf;??
  • ????int??????subpagesize;??
  • ????uint8_t??cellinfo;??
  • ????int??????badblockpos;??
  • ????nand_state_t????state;??
  • ????uint8_t?????*oob_poi;??
  • ????struct?nand_hw_control??*controller;??
  • ????struct?nand_ecclayout???*ecclayout;?/*?ECC布局?*/??
  • ??????
  • ????struct?nand_ecc_ctrl?ecc;???/*?ECC校驗結構體,里面有大量的函數進行ECC校驗?*/??
  • ????struct?nand_buffers?*buffers;??
  • ????struct?nand_hw_control?hwcontrol;??
  • ????struct?mtd_oob_ops?ops;??
  • ????uint8_t?????*bbt;??
  • ????struct?nand_bbt_descr???*bbt_td;??
  • ????struct?nand_bbt_descr???*bbt_md;??
  • ????struct?nand_bbt_descr???*badblock_pattern;??
  • ????void????????*priv;??
  • };??
  • 最后,我們來用圖表的形式來總結一下,MTD設備層、MTD原始設備層、FLASH硬件驅動層之間的聯系。

    ?

    ?













    本文轉自張昺華-sky博客園博客,原文鏈接:http://www.cnblogs.com/sky-heaven/p/5825580.html,如需轉載請自行聯系原作者


    總結

    以上是生活随笔為你收集整理的Linux MTD系统剖析【转】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。