歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> MTD 設備驅動 和 NAND Flash 驅動程序分析

MTD 設備驅動 和 NAND Flash 驅動程序分析

日期:2017/3/1 10:23:42   编辑:Linux編程

硬件環境: 飛凌OK6410,256MB DDR,2GB NAND Flash、 NAND Flash 型號:K9G8G08U9A 、 分析源碼:Linux 2.6.36.2 內核源碼。

一、 MTD 設備驅動。

1、先來簡單介紹一下MTD

在Linux 系統中, 提供了MTD(Memory Technology Device , 內存技術設備)系統來建立 Flash 針對 Linux 的系統、抽象的接口, MTD 將文件系統 與 底層的Flash

存儲器進行了隔離, 使 Flash 驅動工程師 無需關心Flash 作為字符設備和 塊 設備與 LInux內核的接口。

2、在引入MTD 後Linux 系統中的Flash 設備及接口可分為4層, 從上到下依次是:設備節點、MTD 設備層、MTD原始設備層 和 硬件驅動層。 這 4 層的作用定義如下:

1-> 硬件驅動層: Flash 硬件驅動層負責 Flash 硬件設備的讀、寫、擦除, LInux MTD 設備的 NOR Flash 芯片驅動位於 drivers/mtd/chips 子目錄下, NAND Flash

的驅動程序則 位於 drivers/mtd/nand 子目錄下。

2->MTD 原始設備層: MTD原始設備層由兩部分組成, 一部分是MTD 原始設備的通用代碼, 另一部分是各個特定 Flash 的數據,例如分區。

3->MTD設備層: 基於MTD 原始設備,Linux 系統可以定義出 MTD 的塊設備的結構(主設備號 31) 和 字符設備 (設備號 90) ,構成MTD 設備層, MTD 字符設備定義

在mtdchar.c 中實現,MTD 塊設備則是定義在一個描述MTD 塊設備的結構 mtdblk_dev ,並聲明了一個名為 mtdblks 的指針數組,這個數組 中的每個mtdblk_dev

和 mtd_table 中的每一個mtd_info 一一對應。

4->設備節點: 通過mknod 在/dev 子目錄下建立MTD字符設備節點 和 塊設備節點,用戶通過訪問此此設備節點即可訪問 MTD 字符設備和塊設備。

3、分析Linux MTD 系統接口 mtd_info 結構體代碼分析 此結構體定義在 ./include/linux/mtd/mtd.h 中

關鍵詞詞解析:

XIP :XIP eXecute In Place,即芯片內執行,指應用程序可以直接在flash閃存內運行,不必再把代碼讀到系統RAM中。flash內執行

是指nor flash 不需要初始化,可以直接在flash內執行代碼。但往往只執行部分代碼,比如初始化RAM.

OOB :Out Of Brower 傳輸層協議使用帶外數據(out-of-band,OOB)來發送一些重要的數據,如果通信一方有重要的數據需要通知對方時,協議能夠將這些數據

快速地發送到對方.為了發送這些數據

iovec-base : iovec 結構體基礎。struct iovec定義了一個向量元素。通常,這個結構用作一個多元素的數組。對於每一個傳輸的元素,指針成員iov_base指向

一個緩沖區,這個緩沖區是存放的是readv所接收的數據或是writev將要發送的數據。成員iov_len在各種情況下分別確定了接收的最大長度以及實際寫入的長度。

Sync : 函數, 函數說明:此函數負責將系統緩沖區的內容寫回磁盤,以確保數據同步。

  1. struct mtd_info {
  2. u_char type; // 內存技術的類型
  3. uint32_t flags; // 標志位
  4. uint64_t size; // Total size of the MTD 、mtd 設備的大小
  5. /* "Major" erase size for the device. Na茂ve users may take this
  6. * to be the only erase size available, or may use the more detailed
  7. * information below if they desire
  8. */
  9. uint32_t erasesize; // 主要的擦除塊大小 erase size of main block
  10. /* Minimal writable flash unit size. In case of NOR flash it is 1 (even
  11. * though individual bits can be cleared), in case of NAND flash it is
  12. * one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
  13. * it is of ECC block size, etc. It is illegal to have writesize = 0.
  14. * Any driver registering a struct mtd_info must ensure a writesize of
  15. * 1 or larger.
  16. */
  17. uint32_t writesize; // 最小的可寫單元的字節數
  18. uint32_t oobsize; // Amount of OOB data per block (e.g. 16) OOB 字節數
  19. uint32_t oobavail; // Available OOB bytes per block 可用OBB 字節數
  20. /*
  21. * If erasesize is a power of 2 then the shift is stored in
  22. * erasesize_shift otherwise erasesize_shift is zero. Ditto writesize.
  23. */
  24. unsigned int erasesize_shift;
  25. unsigned int writesize_shift;
  26. /* Masks based on erasesize_shift and writesize_shift */
  27. unsigned int erasesize_mask;
  28. unsigned int writesize_mask;
  29. // Kernel-only stuff starts here.
  30. const char *name;
  31. int index;
  32. /* ecc layout structure pointer - read only ! */
  33. struct nand_ecclayout *ecclayout; // ECC 布局結構體指針
  34. /* Data for variable erase regions. If numeraseregions is zero,
  35. * it means that the whole device has erasesize as given above.
  36. */
  37. int numeraseregions; // 不同的erasesize 的區域 數目通常是1
  38. struct mtd_erase_region_info *eraseregions;
  39. /*
  40. * Erase is an asynchronous operation. Device drivers are supposed
  41. * to call instr->callback() whenever the operation completes, even
  42. * if it completes with a failure.
  43. * Callers are supposed to pass a callback function and wait for it
  44. * to be called before writing to the block.
  45. */
  46. int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
  47. /* This stuff for eXecute-In-Place */
  48. /* phys is optional and may be set to NULL */
  49. int (*point) (struct mtd_info *mtd, loff_t from, size_t len, // 針對 eXecute-In- Place
  50. size_t *retlen, void **virt, resource_size_t *phys);
  51. /* We probably shouldn't allow XIP if the unpoint isn't a NULL */
  52. void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len); // 如果unpoint 為空,不允許 XIP
  53. /* Allow NOMMU mmap() to directly map the device (if not NULL)
  54. * - return the address to which the offset maps
  55. * - return -ENOSYS to indicate refusal to do the mapping
  56. */
  57. unsigned long (*get_unmapped_area) (struct mtd_info *mtd,
  58. unsigned long len,
  59. unsigned long offset,
  60. unsigned long flags);
  61. /* Backing device capabilities for this device
  62. * - provides mmap capabilities
  63. */
  64. struct backing_dev_info *backing_dev_info;
  65. int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); // 讀 flash
  66. int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); // 寫 flash
  67. /* In blackbox flight recorder like scenarios we want to make successful
  68. writes in interrupt context. panic_write() is only intended to be
  69. called when its known the kernel is about to panic and we need the
  70. write to succeed. Since the kernel is not going to be running for much
  71. longer, this function can break locks and delay to ensure the write
  72. succeeds (but not sleep). */
  73. int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); // Kernel panic 時序讀寫
  74. int (*read_oob) (struct mtd_info *mtd, loff_t from, // 讀 out-of-band
  75. struct mtd_oob_ops *ops);
  76. int (*write_oob) (struct mtd_info *mtd, loff_t to, // 寫 out-of-band
  77. struct mtd_oob_ops *ops);
  78. /*
  79. * Methods to access the protection register area, present in some
  80. * flash devices. The user data is one time programmable but the
  81. * factory data is read only.
  82. */
  83. int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
  84. int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
  85. int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
  86. int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
  87. int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
  88. int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
  89. /* kvec-based read/write methods.
  90. NB: The 'count' parameter is the number of _vectors_, each of
  91. which contains an (ofs, len) tuple.
  92. */
  93. int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); // iovec-based 讀寫函數
  94. /* Sync */
  95. void (*sync) (struct mtd_info *mtd); // Sync
  96. /* Chip-supported device locking */
  97. int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); // 設備鎖
  98. int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
  99. int (*is_locked) (struct mtd_info *mtd, loff_t ofs, uint64_t len);
  100. /* Power Management functions */
  101. int (*suspend) (struct mtd_info *mtd); // 電源管理函數
  102. void (*resume) (struct mtd_info *mtd);
  103. /* Bad block management functions */
  104. int (*block_isbad) (struct mtd_info *mtd, loff_t ofs); // 壞塊管理函數
  105. int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
  106. struct notifier_block reboot_notifier; /* default mode before reboot */
  107. /* ECC status information */
  108. struct mtd_ecc_stats ecc_stats;
  109. /* Subpage shift (NAND) */
  110. int subpage_sft;
  111. void *priv; // 私有函數
  112. struct module *owner;
  113. struct device dev;
  114. int usecount;
  115. /* If the driver is something smart, like UBI, it may need to maintain
  116. * its own reference counting. The below functions are only for driver.
  117. * The driver may register its callbacks. These callbacks are not
  118. * supposed to be called by MTD users */
  119. int (*get_device) (struct mtd_info *mtd);
  120. void (*put_device) (struct mtd_info *mtd);
  121. };

mtd_info 中的 read(). write(). read_oob(). write_oob(). erase() 是 MTD 設備驅動主要實現的函數。在在後面我將要介紹的nand flahs 驅動中幾乎看不到mtd_info

的成員函數(也就是說這些函數對於Flash 芯片來說是透明的),這是因為在Linux MTD 下層實現了針對 NOR、NAND Flsh 的同游mtd_info 成員函數。

Flash 驅動中使用如下兩個函數來注冊 和注銷MTD 設備:

int add_mtd_device(struct mtd_info *mtd);

int del_mtd_device (struct mtd_info *mtd)

Copyright © Linux教程網 All Rights Reserved