基于MTD的NAND驅動開發(二)

基于MTD的NAND驅動開發(二)

基于MTD的NAND驅動開發(三)

http://blog.csdn.net/leibniz_zsu/article/details/4977853

http://blog.csdn.net/leibniz_zsu/article/details/4977869

四、基于MTD的NAND 驅動架構
?
1platform_deviceplatform_driver 的定義和注冊
對于我們的NAND driver ,以下是一個典型的例子:

?static struct platform_driver caorr_nand_driver = {
???????????????. driver = {
????????????????????????????????. name = " caorr-nand" ,
????????????????????????????????. owner = THIS_MODULE,
????????????????} ,
????????????????. probe = caorr_nand_probe,
????????????????. remove = caorr_nand_remove,
?} ;

?static int __init caorr_nand_init( void )
?{
????????????????printk( "CAORR NAND Driver, (c) 2008-2009./n" ) ;
????????????????return platform_driver_register( & caorr_nand_driver) ;
?}

?static void __exit caorr_nand_exit( void )
?{
????????????????platform_driver_unregister( & caorr_nand_driver) ;
?}

?module_init( caorr_nand_init) ;
?module_exit( caorr_nand_exit) ;


與大多數嵌入式Linux 驅動一樣,NAND 驅動也是從module_init 宏開始。 caorr_nand_init 是驅動初始化函數,在此函數中注冊platform driver 結構體,platform driver 結構體中自然需要定義proberemove 函數。其實在大多數嵌入式Linux 驅動中,這樣的套路基本已經成了一個定式
至于module_init 有什么作用,caorr_nand_probe 又是何時調用的,以及這個driver 是怎么和NAND 設備聯系起來的,就不再多說了,這里只提三點:
A、 以上代碼只是向內核注冊了NANDplatform_driver ,即caorr_nand_driver ,我們當然還需要一個NANDplatform_device ,要不然caorr_nand_driverprobe 函數就永遠不會被執行,因為沒有device 需要這個driver
B、Linux 內核注冊NANDplatform_device 有兩種方式:
其一是直接定義一個NANDplatform_device 結構體,然后調用platform_device_register 函數注冊。作為例子,我們可以這樣定義NANDplatform_device 結構體:

?struct platform_device caorr_nand_device = {
????????? . name = "caorr-nand" ,
????????? . id = - 1,
????????? . num_resources = 0,
??????????. resource = NULL ,
??????????. dev = {
??????????????. platform_data = & caorr_platform_default_nand,
??????????}
?} ;
?platform_device_register( & caorr_nand_device) ;

其中num_resourcesresource 與具體的硬件相關,主要包括一些寄存器地址范圍和中斷的定義。caorr_platform_default_nand 待會兒再說。需要注意的是,這個platform_devicename 的值必須與platform_driver->driver->name 的值完全一致,因為platform_bus_typematch 函數是根據這兩者的name 值來進行匹配的。

其二是用platform_device_alloc 函數動態分配一個platform_device ,然后再用platform_device_add 函數把這個platform_device 加入到內核中去。具體不再細說,Linux 內核中有很多例子可以參考。
相對來說,第一種方式更加方便和直觀一點,而第二種方式則更加靈活一點。
C、 在加載NAND 驅動時,我們還需要向MTD Core 提供一個信息,那就是NAND 的分區信息,caorr_platform_default_nand 主要就是起這個作用,更加詳細的容后再說。
2MTD 架構的簡單描述
?
MTD(memory technology device 存儲技術設備) 是用于訪問memory 設備(ROMflash )的Linux 的子系統。MTD 的主要目的是為了使新的memory 設備的驅動更加簡單,為此它在硬件和上層之間提供了一個抽象的接口。MTD 的所有源代碼在/drivers/mtd 子目錄下。MTD 設備可分為四層(從設備節點直到底層硬件驅動),這四層從上到下依次是:設備節點、MTD 設備層、MTD 原始設備層和硬件驅動層。

A、Flash硬件驅動層:硬件驅動層負責驅動Flash硬件。
B、MTD原始設備:原始設備層有兩部分組成,一部分是MTD原始設備的通用代碼,另一部分是各個特定的Flash的數據,例如分區。
用于描述MTD原始設備的數據結構是mtd_info,這其中定義了大量的關于MTD的數據和操作函數。mtd_table(mtdcore.c)則是所有MTD原始設備的列表,mtd_part(mtd_part.c)是用于表示MTD原始設備分區的結構,其中包含了mtd_info,因為每一個分區都是被看成一個MTD原始設備加在mtd_table中的,mtd_part.mtd_info中的大部分數據都從該分區的主分區mtd_part->master中獲得。
在drivers/mtd/maps/子目錄下存放的是特定的flash的數據,每一個文件都描述了一塊板子上的flash。其中調用add_mtd_device()、del_mtd_device()建立/刪除 mtd_info結構并將其加入/刪除mtd_table(或者調用add_mtd_partition()、del_mtd_partition() (mtdpart.c)建立/刪除mtd_part結構并將mtd_part.mtd_info加入/刪除mtd_table 中)。
C、MTD設備層:基于MTD原始設備,linux系統可以定義出MTD的塊設備(主設備號31)和字符設備(設備號90)。MTD字符設備的定義在mtdchar.c中實現,通過注冊一系列file operation函數(lseek、open、close、read、write)。MTD塊設備則是定義了一個描述MTD塊設備的結構 mtdblk_dev,并聲明了一個名為mtdblks的指針數組,這數組中的每一個mtdblk_dev和mtd_table中的每一個 mtd_info一一對應。
D、設備節點:通過mknod在/dev子目錄下建立MTD字符設備節點(主設備號為90)和MTD塊設備節點(主設備號為31),通過訪問此設備節點即可訪問MTD字符設備和塊設備。
E、根文件系統:在Bootloader中將JFFS(或JFFS2)的文件系統映像jffs.image(或jffs2.img)燒到flash的某一個分區中,在/arch/arm/mach-your/arch.c文件的 your_fixup函數中將該分區作為根文件系統掛載。
F、文件系統:內核啟動后,通過mount 命令可以將flash中的其余分區作為文件系統掛載到mountpoint上。
以上是從網上找到的一些資料,我只是斷斷續續地看過一些code,沒有系統地研究過,所以這里只能講一下MTD原始設備層與FLASH硬件驅動之間的交互。
一個MTD原始設備可以通過mtd_part分割成數個MTD原始設備注冊進mtd_table,mtd_table中的每個MTD原始設備都可以被注冊成一個MTD設備,有兩個函數可以完成這個工作,即 add_mtd_device函數和add_mtd_partitions函數。
其中add_mtd_device函數是把整個NAND?FLASH注冊進MTD Core,而add_mtd_partitions函數則是把NAND?FLASH的各個分區分別注冊進MTD Core。
add_mtd_partitions函數的原型是:

int add_mtd_partitions( struct mtd_info * master,

??????????? ?const struct mtd_partition * parts, int nbparts) ;

其中master就是這個MTD原始設備,parts即NAND的分區信息,nbparts指有幾個分區。那么parts和nbparts怎么來?caorr_platform_default_nand 就是起這個作用了。

?static struct mtd_partition caorr_platform_default_nand[ ] = {
?? ?[ 0] = {
???????????????. name = "Boot Strap" ,
???????????????. offset = 0,
???????????????. size = 0x40000,
????} ,
? ??[ 1] = {
???????????????. name = "Bootloader" ,
???????????????. offset = MTDPART_OFS_APPEND,
???????????????. size = 0x40000,
? ??} ,
? ??[ 2] = {
???????????????. name = "Partition Table" ,
???????????????. offset = MTDPART_OFS_APPEND,
???????????????. size = 0x40000,
?? ?} ,
? ??[ 3] = {
???????????????. name = "Linux Kernel" ,
???????????????. offset = MTDPART_OFS_APPEND,
???????????????. size = 0x500000,
?? ?} ,
?? ?[ 4] = {
???????????????. name = "Rootfs" ,
???????????????. offset = MTDPART_OFS_APPEND,
???????????????. size = MTDPART_SIZ_FULL,
?? ?} ,
?} ;

其中offset是分區開始的偏移地址,在后4個分區我們設為 MTDPART_OFS_APPEND,表示緊接著上一個分區,MTD Core會自動計算和處理分區地址;size是分區的大小,在最后一個分區我們設為MTDPART_SIZ_FULL,表示這個NADN剩下的所有部分。
這樣配置NAND的分區并不是唯一的,需要視具體的系統而定,我們可以在kernel中這樣顯式的指定,也可以使用bootloader傳給內核的參數進行配置。
另外,MTD對NAND芯片的讀寫主要分三部分:
A、struct mtd_info中的讀寫函數,如read,write_oob等,這是MTD原始設備層與FLASH硬件層之間的接口;
B、struct nand_ecc_ctrl中的讀寫函數,如read_page_raw,write_page等,主要用來做一些與ecc有關的操作;
C、struct nand_chip中的讀寫函數,如read_buf,cmdfunc等,與具體的NAND controller相關,就是這部分函數與硬件交互,通常需要我們自己來實現。(注:這里提到的read,write_oob,cmdfunc等,其實都是些函數指針,所以這里所說的函數,是指這些函數指針所指向的函數,以后本文將不再另做說明。)
值得一提的是,struct nand_chip中的讀寫函數雖然與具體的NAND controller相關,但是MTD也為我們提供了default的讀寫函數,如果你的NAND controller比較通用(使用PIO模式),對NAND芯片的讀寫與MTD提供的這些函數一致,就不必自己實現這些函數了。
這三部分讀寫函數是相互配合著完成對NAND芯片的讀寫的。首先,MTD上層需要讀寫NAND芯片時,會調用struct mtd_info中的讀寫函數,接著struct mtd_info中的讀寫函數就會調用struct nand_chip或struct nand_ecc_ctrl中的讀寫函數,最后,若調用的是struct nand_ecc_ctrl中的讀寫函數,那么它又會接著調用struct nand_chip中的讀寫函數。如下圖所示:

以讀NAND芯片為例,講解一下這三部分讀寫函數的工作過程。
首先,MTD上層會調用struct mtd_info中的讀page函數,即nand_read函數。
接著nand_read函數會調用struct nand_chip中cmdfunc函數,這個cmdfunc函數與具體的NAND controller相關,它的作用是使NAND controller向NAND 芯片發出讀命令,NAND芯片收到命令后,就會做好準備等待NAND controller下一步的讀取。
接著nand_read函數又會調用struct nand_ecc_ctrl中的read_page函數,而read_page函數又會調用struct nand_chip中read_buf函數,從而真正把NAND芯片中的數據讀取到buffer中(所以這個read_buf的意思其實應該是read into buffer,另外,這個buffer是struct mtd_info中的nand_read函數傳下來的)。
read_buf函數返回后,read_page函數就會對buffer中的數據做一些處理,比如校驗ecc,以及若數據有錯,就根據ecc對數據修正之類的,最后read_page函數返回到nand_read函數中。
對NAND芯片的其它操作,如寫,擦除等,都與讀操作類似。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253840.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253840.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253840.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

靜態時序分析——Data to data check

setup和hold的檢查也有可能發生在任意兩個數據端口,其中不包括時鐘端口。 我們將其中一個端口(pin)設置為約束端口(constrainted pin),就像觸發器中的數據端口;將另一個一個端口(pin…

開源數據庫中間件-MyCa初探與分片實踐

如今隨著互聯網的發展,數據的量級也是撐指數的增長,從GB到TB到PB。對數據的各種操作也是愈加的困難,傳統的關系性數據庫已經無法滿足快速查詢與插入數據的需求。這個時候NoSQL的出現暫時解決了這一危機。它通過降低數據的安全性,減…

【JAVA設計模式】外觀模式(Facade Pattern)

一 定義 為子系統中的一組接口提供一個一致的界面。Facade模式定義了一個高層的接口,這個接口使得這一子系統更加easy使用。二 案例 一個子系統中擁有3個模塊。每一個模塊中都有3個方法。當中一個為client調用方法,其它兩個則為各子模塊間互相調用方法…

return的用處

#include "stdio.h" main() {int a,b1,c0;for(a1;a<5;a){ cca;}printf("%d",c);return ;printf("hello word"); } 輸出結果是10并沒有hello word&#xff1b;return將不會執行下面的語句。轉載于:https://www.cnblogs.com/doublekai/p/6148…

靜態時序分析——Clock Gating check

門控時鐘是RTL級進行低功耗設計的最常用方法&#xff0c;能夠有效降低動態功耗。在實際使用中&#xff0c;一般用ICG&#xff08;集成門控時鐘單元&#xff09;來完成clock gating。ICG電路和時序如下&#xff1a; 通常來說&#xff0c;工藝庫已經集成了ICG&#xff0c;在做門控…

U-boot中TFTP 解釋

http://www.cnblogs.com/heaad/archive/2009/08/10/1542538.html

BlackHat Arsenal USA 2018 ToolsWatch黑客工具庫

原文鏈接&#xff1a;https://medium.com/hack-with-github/black-hat-arsenal-usa-2018-the-w0w-lineup-7de9b6d32796 Black Hat Arsenal USA 2018?—?The w0w lineup After the huge success of Black Hat Arsenal USA 2017, toolswatch has now announced the list of too…

SOA是什么

SOA是什么&#xff1f; SOA是面向服務的架構&#xff0c;是一個組件模型&#xff0c;它將應用程序的不同功能單元&#xff08;稱為服務&#xff09;通過這些服務之間定義良好的接口和契約聯系起來。接口是采用中立的方式進行定義的&#xff0c;它獨立于實現服務的硬件平臺、操作…

redis 優化

系統優化echo "vm.overcommit_memory1" > /etc/sysctl.conf 0&#xff0c; 表示內核將檢查是否有足夠的可用內存供應用進程使用&#xff1b;如果有足夠的可用內存&#xff0c;內存申請允許&#xff1b;否則&#xff0c;內存申請失敗&#xff0c;并把錯誤返回給應…

IC設計常見設計思想

速度與面積互換原則 所謂速度&#xff0c;是指整個工程穩定運行所能夠達到的最高時鐘頻率&#xff0c;它不僅和電路內部各個寄存器的建立時間、保持時間以及外部器件接口的各種時序要求有關&#xff0c;而且還和兩個緊鄰的寄存器間的邏輯延時&#xff0c;走線延時有關。所謂面…

DM365 u-boot啟動分析

http://www.61ic.com/Article/DaVinci/DM644X/201009/27429.html

(十三)Hibernate高級配置

配置數據庫連接池 配置C3P0連接池。先導入c3p0包。然后在hibernate.cfg.xml文件中 &#xff0c;使用下面代碼配置連接池<property name"hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>可以通過下面的…

eclipse中如何配置tomcat

1.打開eclipse上面的Windows選項&#xff0c;選擇Preferences>Server>Runtime Environments>Add 2.選擇你電腦中安裝的tomcat的版本我的是8所以我選的是Apache Tomcat v8.0 3,Next>Browse選擇Tomcat的安裝目錄&#xff0c;選擇jdk 4.Finish>OK tomcat配置完成。…

jsp調試小技巧

console.log($("#toolbar")); 打印對象可知道這個對象的參數信息轉載于:https://www.cnblogs.com/chenweida/p/6149342.html

數字IC驗證學習(一)

一、數據類型 1、logic logic類型只能有一個驅動。使用wire和reg的地方均可使用logic&#xff0c;但如雙向總線等有多個驅動的地方&#xff0c;則不可使用logic。 2、二值邏輯 對于二值邏輯變量與DUT中的四值邏輯變量連接時&#xff0c;如果DUT中產生了X和Z&#xff0c;會被…

SecureCRT 配置文件中 找密碼

打開本地電腦如下路徑 C:\Users\XXX\AppData\Roaming\VanDyke\Config\Sessions 找到配置文件。 運行命令&#xff1a;python SecureCRTDecrypt.py [配置文件名稱] 例如&#xff1a;python SecureCRTDecrypt.py 192.168.1.249.ini ssh root192.168.1.249 # 123456 即可得到密…

刷題比賽

題目描述 給你四個數組A,B,C,D. 給出每個數組的初始值A[1] 1, B[1] 1, C[1] 1, D[1] 1 , A[2] 3, B[2] 3, C[2] 3, D[2] 3; 有以下的遞推公式: (1) a[k2]p* a[k1]qa[k]b[k1]c[k1]r k^2t * k1d[k]; (2)b[k2]u* b[k1]vb[k]a[k1]c[k1]w^kd[k]; (3)c[k2]x c[k1]yc[k]a[k1]b[…

自動化測試用例設計原則

自動化測試用例設計原則&#xff1a;每一個用例 都是一個閉合的業務操作。用例之間要保持獨立 &#xff0c;不要有操作上的依賴關系&#xff0c;就算有也是測試數據上的依賴。第二個用例 依賴第一個用例產生的數據。轉載于:https://www.cnblogs.com/yyjiangnan/p/6149430.html

MII/MDIO接口詳解

MII/MDIO接口詳解 http://dpinglee.blog.163.com/blog/static/144097753201041131115262/