Linux內(nèi)核MTD驅(qū)動(dòng)程序與SD卡驅(qū)動(dòng)程序_第1頁(yè)
Linux內(nèi)核MTD驅(qū)動(dòng)程序與SD卡驅(qū)動(dòng)程序_第2頁(yè)
Linux內(nèi)核MTD驅(qū)動(dòng)程序與SD卡驅(qū)動(dòng)程序_第3頁(yè)
Linux內(nèi)核MTD驅(qū)動(dòng)程序與SD卡驅(qū)動(dòng)程序_第4頁(yè)
Linux內(nèi)核MTD驅(qū)動(dòng)程序與SD卡驅(qū)動(dòng)程序_第5頁(yè)
已閱讀5頁(yè),還剩75頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、物理閃存設(shè)備邏輯設(shè)備JFF521文件系統(tǒng)耳文件系統(tǒng)Linux內(nèi)核MT驅(qū)動(dòng)程序與SD卡驅(qū)動(dòng)程序 flash閃存設(shè)備和SD插卡設(shè)備是嵌入式設(shè)備用到的主要存儲(chǔ)設(shè)備,它們相當(dāng)于 PC機(jī)的硬盤(pán)。在嵌入設(shè)備特別是手持設(shè)備中,flash閃存是焊接在嵌入設(shè)備主板 上的flash閃存芯片。在嵌入設(shè)備上有MMC/S卡控制器及插槽,可通過(guò)MMC/SD 來(lái)擴(kuò)充存儲(chǔ)空間。嵌入設(shè)備的存儲(chǔ)設(shè)備的空間劃分及所有邏輯設(shè)備和文件系統(tǒng)示例列出如下圖:Linux文件系統(tǒng)MM17SDMMCB10CKVRT控制器員插卡1'塊設(shè)備文件系統(tǒng)圖:嵌入設(shè)備的存儲(chǔ)空間劃分及文件系統(tǒng)示例圖在嵌入設(shè)備上的flash芯片上blob和zlmage

2、直接按內(nèi)存線性地址存儲(chǔ)管理,對(duì) 于flash芯片上留出的供用戶使用的存儲(chǔ)空間,使用 MTDBLOC塊設(shè)備和JFFS2 文件系統(tǒng)。對(duì)于flash芯片的分區(qū)表信息則以MTDCHA字符設(shè)備來(lái)存儲(chǔ)管理。在嵌入設(shè)備上的MMC/S插卡則由MMCBLO驅(qū)動(dòng)程序和VFAT文件系統(tǒng)進(jìn)行存儲(chǔ) 管理。本章分析了 MTDS備和MMC/S驅(qū)動(dòng)程序。FilesystemsBJ ackdevicesLOGFSJFFS3UBl VolumNAND SupportHardware Driver NANDzI匚J11MTDNOR SupportHardware DriverFigure 3-1. UBI/MTD Integrat

3、ion目錄1 MTD內(nèi)存技術(shù)設(shè)備o 1.1 MTD內(nèi)存技術(shù)設(shè)備層次結(jié)構(gòu)o 1.2設(shè)備層和原始設(shè)備層的函數(shù)調(diào)用關(guān)系o 1.3 MTD相關(guān)結(jié)構(gòu)o 1.4 MTD塊設(shè)備初始化o 1.5 MTD塊設(shè)備的讀寫(xiě)操作o 1.6 MTD核心初始化o 1.7 MTD字符設(shè)備o 1.8具體flash芯片的探測(cè)及映射o 1.9驅(qū)動(dòng)程序?qū)嵗治? SD/MM(卡塊設(shè)備驅(qū)動(dòng)程序2.1.12.1.2(1)設(shè)備描述結(jié)構(gòu)(2)讀與請(qǐng)求相關(guān)結(jié)構(gòu)o 2.2 MMG由象設(shè)備層MM塊設(shè)備驅(qū)動(dòng)程序2.2.1(1)MM塊設(shè)備驅(qū)動(dòng)程序初始化2.2.2(2)MM塊設(shè)備驅(qū)動(dòng)程序探測(cè)函數(shù)2.2.3(3)MM卡請(qǐng)求的處理o 2.1 MMG由象設(shè)備

4、層相關(guān)結(jié)構(gòu)o 2.3具體MM控制器驅(qū)動(dòng)程序示例2.3.1(1) amba空制器驅(qū)動(dòng)程序相關(guān)結(jié)構(gòu)2.3.2(2) amba空制器的初始化2.3.3(3)設(shè)備探測(cè)函數(shù) mmci probe2.3.4(4) amba空制器操作函數(shù)國(guó)MTD內(nèi)存技術(shù)設(shè)備Linux中MTDf系統(tǒng)在系統(tǒng)的硬件驅(qū)動(dòng)程序和文件系統(tǒng)之間提供通用接口。在MTD上常用的文件文件系統(tǒng)是JFFS2日志閃存文件系統(tǒng)版本2 (Journaling Flash File System)。JFFS2用于微型嵌入式設(shè)備的原始閃存芯片的文件系統(tǒng)。JFFS2文件系統(tǒng)是日志結(jié)構(gòu)化的,這意味著它基本上是一長(zhǎng)列節(jié)點(diǎn)。每個(gè)節(jié)點(diǎn)包含有關(guān) 文件的部分信息 一可能

5、是文件的名稱、也許是一些數(shù)據(jù)。與Ext2文件系統(tǒng)相比,JFFS2因?yàn)橛幸韵逻@些優(yōu)點(diǎn):JFFS2在扇區(qū)級(jí)別上執(zhí)行閃存擦除/寫(xiě)/讀操作要比Ext2文件系統(tǒng)好。JFFS2提供了比Ext2fs更好的崩潰/掉電安全保護(hù)。當(dāng)需要更改少量數(shù)據(jù)時(shí),Ext2文件系統(tǒng)將整個(gè)扇區(qū)復(fù)制到內(nèi)存(DRA M中,在內(nèi)存中合并新數(shù)據(jù),并寫(xiě)回整個(gè)扇 區(qū)。這意味著為了更改單個(gè)字,必須對(duì)整個(gè)扇區(qū)(64 KB)執(zhí)行讀/擦除/寫(xiě)例 程,這樣做的效率非常低。JFFS2是附加文件而不是重寫(xiě)整個(gè)扇區(qū),并且具有 崩潰/掉電安全保護(hù)這一功能。JFFS2是是為FLASH定制的文件系統(tǒng),JFFS1實(shí)現(xiàn)了日志功能,JFFS2實(shí)現(xiàn)了壓 縮功能。它的整個(gè)

6、設(shè)計(jì)提供了更好的閃存管理。JFFS2的缺點(diǎn)很少,主要是當(dāng)文件系統(tǒng)已滿或接近滿時(shí),JFFS2會(huì)大大放慢運(yùn)行速度。這是因?yàn)槔占膯?wèn) 題。MTD驅(qū)動(dòng)程序是專門為基于閃存的設(shè)備所設(shè)計(jì)的,它提供了基于扇區(qū)的擦除和讀寫(xiě)操作的更好的接口。MTD子系統(tǒng)支持眾多的閃存設(shè)備,并且有越來(lái)越多的驅(qū)動(dòng) 程序正被添加進(jìn)來(lái)以用于不同的閃存芯片。MTD子系統(tǒng)提供了對(duì)字符設(shè)備 MTD_CHA和塊設(shè)備MTD_BLOCK支持。MTD_CHAR 提供對(duì)閃存的原始字符訪問(wèn),象通常的IDE硬盤(pán)一樣,在MTD_BLOCK設(shè)備上可 創(chuàng)建文件系統(tǒng)。MTD_CHA字符設(shè)備文件是/dev/mtdO、mtdl、mtd2等,MTD_BLOCK 塊

7、設(shè)備文件是 /dev/mtdblockO 、mtdblockl 等等。NAN床口 NOR!制作Flash的工藝,CFI和JEDEC是 flash 硬件提供的接口,linux 通過(guò)這些用通用接口抽象出 MTD設(shè)備。JFFS2文件系統(tǒng)就建立在 MTDS備上。NOR flash帶有SRAM!口,可以直接存取內(nèi)部的每一個(gè)字節(jié)。 NAND器件使用串 行I/O 口來(lái)存取數(shù)據(jù),8個(gè)引腳用來(lái)傳送控制、地址和數(shù)據(jù)信息。 NAND和寫(xiě) 操作用512字節(jié)的塊。MTD內(nèi)存技術(shù)設(shè)備層次結(jié)構(gòu)MTD(memory technology device內(nèi)存技術(shù)設(shè)備)在硬件和文件系統(tǒng)層之間的提 供了一個(gè)抽象的接口, MTD是用來(lái)

8、訪問(wèn)內(nèi)存設(shè)備(如:ROM flash )的中間層, 它將內(nèi)存設(shè)備的共有特性抽取出來(lái),從而使增加新的內(nèi)存設(shè)備驅(qū)動(dòng)程序變得更簡(jiǎn) 單。MTD勺源代碼都在/drivers/mtd 目錄中。MTD中間層細(xì)分為四層,按從上到下依次為:設(shè)備節(jié)點(diǎn)、MTDS備層、MTD原始設(shè)備層和硬件驅(qū)動(dòng)層。MTD中間層層次結(jié)構(gòu)圖如下:圖1 MTD中間層層次結(jié)構(gòu)圖Flash硬件驅(qū)動(dòng)層對(duì)應(yīng)的是不同硬件的驅(qū)動(dòng)程序,它負(fù)責(zé)驅(qū)動(dòng)具體的硬件。例如:符合CFI接口標(biāo)準(zhǔn)的Flash芯片驅(qū)動(dòng)驅(qū)動(dòng)程序在drivers/mtd/chips目錄中,NAN園 Flash 的驅(qū)動(dòng)程序在 /drivers/mtd/nand中。在原始設(shè)備層中,各種內(nèi)存設(shè)備

9、抽象化為原始設(shè)備,原始設(shè)備實(shí)際上是一種塊設(shè) 備,MTC字符設(shè)備的讀寫(xiě)函數(shù)也調(diào)用原始設(shè)備的操作函數(shù)來(lái)實(shí)現(xiàn)。MTD使用MTD信息結(jié)構(gòu)mtd_info來(lái)描述了原始設(shè)備的操作函數(shù)、各種信息,所有原始設(shè)備的 信息也用一個(gè)全局的結(jié)構(gòu)數(shù)組來(lái)描述,列出如下(在drivers/mtd/mtdcore.c中):struct mtd_i nfo *mtd_tableMAX_MTD_DEVICES;每個(gè)原始設(shè)備可能分成多個(gè)設(shè)備分區(qū),設(shè)備分區(qū)是將一個(gè)內(nèi)存分成多個(gè)塊,每個(gè)設(shè)備分區(qū)用一個(gè)結(jié)構(gòu)mtd_part來(lái)描述,所有的分區(qū)組成一個(gè)鏈表mtd_partitio ns,這個(gè)鏈表的聲明列出如下(在 drivers/mtd/mt

10、dpart.c 中):I /* Our partition linked list */:static LIST_HEAD(mtd_partitio ns);MTD原始設(shè)備到具體設(shè)備之間存在的一些映射關(guān)系數(shù)據(jù)在drivers/mtd/maps/目錄下的對(duì)應(yīng)文件中。這些映射數(shù)據(jù)包括分區(qū)信息、I/O映射及特定函數(shù)的映射等。 這種映射關(guān)系用映射信息結(jié)構(gòu) mapnfo描述。在MTD設(shè)備層中,MTD字符設(shè)備 通過(guò)注冊(cè)的file operation函數(shù)集來(lái)操作設(shè)備,而這些函數(shù)是通過(guò)原始設(shè)備層的操作函數(shù)來(lái)實(shí)現(xiàn)的,即調(diào)用了塊設(shè)備的操作函數(shù)。MTD塊設(shè)備實(shí)際了從塊層到塊設(shè)備的接口函數(shù)。所有的塊設(shè)備組成一個(gè)數(shù)組*

11、mtdblksMAX_MTD_DEVICES這個(gè)結(jié)構(gòu)數(shù)組列出如下(在 drivers/mtd/mtdblock.c 中):IIstatic struct mtdblk_dev -struct mtdnfo *mtd;int count;struct semaphore cache_sem;un sig ned char *cache_data;I:un sig ned long cache_offset;un sig ned int cache_size;i enum STATE_EMPTY, STATE_CLEAN, STATE_DIRTY cache_state;i *mtdblksMAX

12、_MTD_DEVICES;由于flash設(shè)備種類的多樣性,MTD用MTD翻譯層將三大類flash設(shè)備進(jìn)行的封 裝。每大類設(shè)備有自己的操作函數(shù)集,它們的mtdblk_dev結(jié)構(gòu)實(shí)例都存在mtdblks數(shù)組中。MTD設(shè)備在內(nèi)核中的層次圖如下圖。邏輯文件系統(tǒng)層通用謔盤(pán)層塊層接口層MTD貝始設(shè)備層MTO翻譯層mtd_blktran5_op5結(jié)血實(shí)例inftLtrmtdblock_tr設(shè)備驅(qū)動(dòng)設(shè)備驅(qū)動(dòng)設(shè)備驅(qū)動(dòng)圖 MTD設(shè)備在內(nèi)核中的層次圖MTD原始設(shè)備層中封裝了三大類設(shè)備,分別是In verse Flash、NANDFIash和MTD 它們的上體讀寫(xiě)方法不一樣。這里只分析了MTD因?yàn)樗亲畛S玫摹TO(shè)備層

13、和原始設(shè)備層的函數(shù)調(diào)用關(guān)系原始設(shè)備層主要是通過(guò)mtd_info結(jié)構(gòu)來(lái)管理設(shè)備,函數(shù)add_mtd_partitions() 和del_mtd_partitions()將的設(shè)備分區(qū)的 mtdnfo結(jié)構(gòu)加入 mtd_table數(shù)組中,mtdpart.c 中還實(shí)現(xiàn)了 part_read、part_write 等函數(shù),這些函數(shù)注冊(cè)在每 個(gè)分區(qū)中,指向主分區(qū)的read、write函數(shù),之所以這樣做而不直接將主分區(qū)的 read、write函數(shù)連接到每個(gè)分區(qū)中的原因是因?yàn)楹瘮?shù)中的參數(shù)mtd_info會(huì)被調(diào)用者置為函數(shù)所屬的 mtd_info,即mtd->read(mtd,),而參數(shù)mtd_info其實(shí)

14、 應(yīng)該指向主分區(qū)。設(shè)備層和原始設(shè)備層的函數(shù)調(diào)用關(guān)系圖如圖 2。MTD各種結(jié)構(gòu)之間的關(guān)系圖如圖3。設(shè)備層原始設(shè)備層硬件驅(qū)動(dòng)層圖2設(shè)備層和原始設(shè)備層的函數(shù)調(diào)用關(guān)系K*nameroobintosizemtd erase region intohysTprwstruct module *ownermtd partmtd infor一mapjnfomtdblkdev *mtd count cache_sem *cache_datamtdchipdriver*l*probe)()(*de4ray)()*module*nameusr圖3 MTD各種結(jié)構(gòu)之間的關(guān)系MTD相關(guān)結(jié)構(gòu)MTD塊設(shè)備的結(jié)構(gòu)mtdblk_

15、dev代表了一個(gè)閃存塊設(shè)備,MTD字符設(shè)備沒(méi)有相對(duì)應(yīng) 的結(jié)構(gòu)。結(jié)構(gòu) mtdblk_dev列出如下:一 - struct mtdblk_dev | struct mtd info mtd; / Locked */下層原始設(shè)備層的 MT設(shè)備結(jié)構(gòu)Iint count; struct semaphore cache_sem;-Iunsigned char *cache_data;/ 緩沖區(qū)數(shù)據(jù)地址| un sig ned long cache_offset;在緩沖區(qū)中讀寫(xiě)位置偏移| /緩沖區(qū)中的讀寫(xiě)數(shù)據(jù)大小(通常被設(shè)置為MTD設(shè)備的erasesize)I'un sig ned int cach

16、e_size;i enum STATE_EMPTY, STATE_CLEAN, STATE_DIRTY cache_state; 緩沖 | :區(qū)狀態(tài)結(jié)構(gòu)mtd_info描述了一個(gè)MTE原始設(shè)備,每個(gè)分區(qū)也被實(shí)現(xiàn)為一個(gè) mtd_info , 如果有兩個(gè)MTD原始設(shè)備,每個(gè)上有三個(gè)分區(qū),在系統(tǒng)中就一共有6個(gè)mtd_info 結(jié)構(gòu),這些 mtd_info的指針被存放在名為 mtd_table的數(shù)組里。結(jié)構(gòu) mtdnfo 分析如下:I struct mtdnfo MI;u_char type;/內(nèi)存技術(shù)的類型II1unt32_t flags;/ 標(biāo)志位un t32_t size;/ mtd 設(shè)備的大小

17、/ “主要的” erasesize (同一個(gè)mtd設(shè)備可能有數(shù)種不同的 erasesize ) un t32_t erasesize;u_in t32_t oobblock; / oob塊大小,例如:512unt32_t oobsize; / 每個(gè)塊oob數(shù)據(jù)量,例如16unt32_t ecctype;/ecc 類型unt32_t eccsize;/自動(dòng)ecc可以工作的范圍/ Kern el-only stuff starts here. char *n ame;int in dex;'II可變擦除區(qū)域的數(shù)據(jù),如果是0,意味著整個(gè)設(shè)備為erasesize':int numera

18、seregions; II不同 erasesize 的區(qū)域的數(shù)目(通常是 1);:struct mtd_erase_regio nnfo *eraseregi ons;;Iu_in t32_t ban k_size;IIstruct module *module;j II 此 routine 用于將一個(gè) erase_info 力卩入 erase queue| int (*erase) (struct mtdnfo *mtd, struct erase_i nfo *in str);I* This stuff for eXecute- In-Place *I|int (*poi nt) (str

19、uct mtdnfo *mtd, loff_t from, size_t len,-size_t *retle n, u_char *mtdbuf);;'I* We probably shouldn ' t allow XIP if the unpoint isn' t a NULL |i *Ivoid (*unpoint) (struct mtdnfo *mtd, u_char * addr);int (*read) (struct mtdnfo *mtd, loff_t from, size_t len,I:size_t *retle n, u_char *buf)

20、;int (*write) (struct mtdnfo *mtd, loff_t to, size_t le n, size_t *retle n, const u_char *buf);: int (*read_ecc) (struct mtdnfo *mtd, loff_t from,i1size_t le n, size_t *retle n, u_char *buf, u_chari1 *eccbuf);int (*write_ecc) (struct mtdnfo *mtd, loff_t to, size_t len,:size_t *retle n, const u_char

21、*buf, u_char *eccbuf);i' int (*read_oob) (struct mtdnfo *mtd, loff_t from, size_t le n, size_t *retle n, u_char *buf);: int (*write_oob) (struct mtdnfo *mtd, loff_t to, size_t len,i'size_t *retle n, const u_char *buf);i1 /* iovec-based read/write methods. We n eed these especially for:NAND f

22、lash,I with its limited nu mber of write cycles per erase.NB: The count' parameter is the number of vectors, each of which contains an (ofs, le n) tuple.:*/int (*readv) (struct mtdnfo *mtd, struct iovec *vecs, |un sig ned long coun t, loff_t from, size_t *retle n);j int (*writev) (struct mtdnfo

23、*mtd, const struct iovec *vecs, Iun sig ned long coun t, loff_t to, size_t *retle n);I /* Sync */void (*s ync) (struct mtdnfo *mtd);/* Chip-supported device lock ing */int (*lock) (struct mtdnfo *mtd, loff_t ofs, size_t len); int (*un lock) (struct mtdnfo *mtd, loff_t ofs, size_t le n); /* Power Man

24、 ageme nt fun cti ons */int (*suspe nd) (struct mtd_i nfo *mtd);void (*resume) (struct mtd_info *mtd);void *priv;/ 指向 map_info 結(jié)構(gòu)設(shè)備層的mtdblcok設(shè)備的notifier聲明如下:static struct mtd_no tifier notifier = mtd_no tify_add,mtd_no tify_remove,:NULLImtd_part結(jié)構(gòu)是用于描述MTD原始設(shè)備分區(qū)的,結(jié)構(gòu) mtd_part中的list成員 鏈成一個(gè)鏈表 mtd_partit

25、ons 。每個(gè)mtd_part結(jié)構(gòu)中的mtdnfo 結(jié)構(gòu)用于描述 本分區(qū),被加入mtd_table數(shù)組中,其中mtd_info結(jié)構(gòu)大部分成員由其主分區(qū) mtd_part->master決定,各種函數(shù)也指向主分區(qū)的相應(yīng)函數(shù)。 結(jié)構(gòu)mtd_part 列出如下:II;/* Our partition linked list */:static LIST_HEAD(mtd_partitio ns);MTD原 始設(shè)備分區(qū)I的鏈表struct mtd_part !struct mtd_info mtd;/分區(qū)的信息(大部分由其 master1決定)struct mtd_info *master; u

26、_in t32_t offset;int in dex;/該分區(qū)的主分區(qū)/該分區(qū)的偏移地址/分區(qū)號(hào)struct list_head list;結(jié)構(gòu)mtd_partition描述mtd設(shè)備分區(qū)的結(jié)構(gòu),在 MTD原始設(shè)備層調(diào)用函數(shù)add_mtd_partions時(shí)傳遞分區(qū)信息使用。結(jié)構(gòu)列出如下(在中):in clude/li nu x/mtd/partitio n.hstruct mtd_partiti on char *n ame;u_in t32_t size; u_in t32_t offset;/分區(qū)名/分區(qū)大小/在主MTD空間的偏移u_in t32_t mask_flags;MTD塊設(shè)備

27、初始化圖函數(shù)init_mtdblock調(diào)用層次圖在具體的設(shè)備驅(qū)動(dòng)程序初始化時(shí),它會(huì)添加一個(gè)MTD設(shè)備結(jié)構(gòu)到mtd_table數(shù)組 中。MTD翻譯層通過(guò)查找這個(gè)數(shù)組,可訪問(wèn)到各個(gè)具體設(shè)備驅(qū)動(dòng)程序。函數(shù)init_mtdblock注冊(cè)一個(gè)MTD翻譯層設(shè)備,初始化處理請(qǐng)求的線程,賦上MTD翻譯層設(shè)備操作函數(shù)集實(shí)例,注冊(cè)這個(gè)設(shè)備的通用硬盤(pán)結(jié)構(gòu)。函數(shù)in it_mtdblock調(diào)用層次圖如上圖。mtd塊設(shè)備驅(qū)動(dòng)程序利用一個(gè)線程,當(dāng)有讀寫(xiě)請(qǐng)求時(shí),從緩沖區(qū)將數(shù)據(jù)寫(xiě)入塊設(shè) 備或從塊設(shè)備讀入到緩沖區(qū)中。函數(shù) init_mtdblock分析如下(在 drivers/mtd/mtdblock.c 中):I= stat

28、ic int _init in it_mtdblock(void) 一return register_mtd_blktra ns(&m tdblock_tr);IMTD翻譯層設(shè)備操作函數(shù)集實(shí)例列出如下:static struct mtd_blktra ns_ops mtdblock_tr = .n ame=“ mtdblock ”,.major=31,.part_bits=0,.ope n=mtdblock_ope n.flush=mtdblock_flush,.release=mtdblock_release,.readsect=mtdblock_readsect,.writesec

29、t=mtdblock_writesect,.add_mtd=mtdblock_add_mtd,.remove_dev=mtdblock_remove_dev,.ow ner=THIS_MODULE,i ;Istatic LIST_HEAD(blktrans_majors);int register_mtd_blktra ns(struct mtd_blktra ns_ops *tr)!ii IIIIin t ret, i;i /如果第一個(gè)設(shè)備類型被注冊(cè)了,注冊(cè)notifier 來(lái)阻止/* Register the notifier if/when the first device type i

30、s registered, to preve nt the link/init orderi ng from fuck ing us over. */如果不存在注冊(cè)MTD翻譯層塊設(shè)備,創(chuàng)建通用硬盤(pán)結(jié)構(gòu)并注冊(cè)if (!blktra ns_n otifier.list. next)/ register_mtd_user(&blktra ns_n otifier);tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);if (!tr->blkcore_priv) return -ENOMEM;me

31、mset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv); dow n(&m td_table_mutex);/ 創(chuàng)建blk_major_name結(jié)構(gòu)初始化后加到&major_names數(shù)組中ret = register_blkdev(tr->major, tr->n ame);spino ck_i nit(&tr->blkcore_priv->queue_lock); ini t_completio n(&tr->blkcore_priv->thread_dead);

32、 ini t_waitqueue_head(&tr->blkcore_priv->thread_wq);/創(chuàng)建請(qǐng)求隊(duì)列并初始化,賦上塊設(shè)備特定的請(qǐng)求處理函數(shù)mtd_blktra ns_request tr->blkcore_priv->rq = blk_i ni t_queue(mtd_blktra ns_request.& tr->blkcore_priv->queue_lock);函數(shù)mtd_blktrans_request 是MTD設(shè)備的請(qǐng)求處理函數(shù),當(dāng)請(qǐng)求隊(duì)列中的請(qǐng)求 需要設(shè)備處理時(shí)調(diào)用這個(gè)函數(shù)。在MTD設(shè)備中,函數(shù)mtd_blktr

33、ans_request 喚醒了 MTD塊設(shè)備的線程來(lái)進(jìn)行處理。函數(shù)列出如下(在 drivers/mtd/mtd_blkdevs.c中):IIstatic void mtd_blktra ns_request(struct request_queue *rq)struct mtd_blktra ns_ops *tr = rq->queuedata; wake up(&tr->blkcore priv->thread wq);線程函數(shù)mtd_blktrans_thread 處理塊設(shè)備的讀寫(xiě)請(qǐng)求,函數(shù)mtd_blktra ns_thread列出如下:static int m

34、td_blktrans_thread(void *arg)Iii! III.4Iistruct mtd_blktra ns_ops *tr = arg;i struct request_queue *rq = tr->blkcore_priv->rq;/* we might get invo Ived whe n memory gets low, so use PF_MEMALLOC */ :curre nt->flags |= PF_MEMALLOC | PF_NOFREEZE;i /變成以init為父進(jìn)程的后臺(tái)進(jìn)程daemonize( “%sd , tr ->nam

35、e);i II因?yàn)橐恍﹥?nèi)核線程實(shí)際上要與信號(hào)打交道,daemonize()沒(méi)有做后臺(tái)化工 i作。i II我們不能僅調(diào)用exit_sighand函數(shù),? II因?yàn)楫?dāng)最終退出時(shí)這樣將可能引起 oop (對(duì)象指針溢出錯(cuò)誤)。I:spino ck_irq(&curre nt->sigha nd->siglock);isigfillset(&curre nt->blocked);II重新分析是否有掛起信號(hào)并設(shè)置或清除TIF_SIGPENDIN(標(biāo)識(shí)給當(dāng)前進(jìn)程Irecalc_sigpe ndin g();|spin_ un lock_irq(&curre nt-&

36、gt;sigha nd->siglock);Ispino ck_irq(rq->queue_lock);/調(diào)用所有請(qǐng)求處理完的回調(diào)函數(shù),并調(diào)用 do_exit函數(shù)退出線程complete_a nd_exit(&tr->blkcore_priv->thread_dead, 0);函數(shù)do_blktrans_request完成請(qǐng)求的具體操作,它調(diào)用MTD翻譯層設(shè)備操作函數(shù)集實(shí)例中的具體函數(shù)來(lái)進(jìn)行處理。函數(shù)do_blktra ns_request分析如下:static int do_blktra ns_request(struct mtd_blktra ns_ops

37、*tr,:struct mtd_blktra ns_dev *dev,istruct request *req)i un sig ned long block, n sect; char *buf;IIblock = req->sector;jn sect = req->curre nt_n r_sectors;|buf = req->buffer;i':if (!(req->flags & REQ_CMD)Iireturn 0;i /如果讀寫(xiě)的扇區(qū)數(shù)超出了塊設(shè)備的容量,返回if (block + n sect > get_capacity(req

38、->rq_disk):return 0;II/ 根據(jù)(rq)->flags & 1標(biāo)識(shí)來(lái)判斷操作方式,調(diào)用具體的設(shè)備操作函數(shù)switch(rq_data_dir(req) :case READ:ifor (; n sect > 0; n sect-, block+, buf += 512)if (tr->readsect(dev, block, buf) return 0;Iireturn 1;IILcase WRITE:I if (!tr->writesect)|'return 0;for (; n sect > 0; n sect-, b

39、lock+, buf += 512)Iiif (tr->writesect(dev, block, buf)Iireturn 0;return 1;Midefault:圖函數(shù)register_mtd_user調(diào)用層次圖結(jié)構(gòu)mtd_notifier是用于通知加上和去掉 MTD原始設(shè)備。對(duì)于塊設(shè)備來(lái)說(shuō),這個(gè)結(jié)構(gòu)實(shí)例blktrans_notifier用來(lái)通知翻譯層加上和去掉MTD原始設(shè)備。結(jié)構(gòu)實(shí)例.blktrans_notifier列出如下_(在一 一.drivers/mtd/mtd_blkdevs.c中):_static struct mtd_ no tifier blktra ns_n o

40、tifier = .add = blktra ns_no tify_add,.remove = blktra ns_no tify_remove.函數(shù)register_mtd_user 注冊(cè)MTD設(shè)備,通過(guò)分配通盤(pán)硬盤(pán)結(jié)構(gòu)來(lái)激活每個(gè) MTD設(shè)備,使其出現(xiàn)在系統(tǒng)中。函數(shù) register_mtd_user調(diào)用層次圖如上圖。函數(shù)register_mtd_user 分析如下(在 drivers/mtd/mtdcore.c 中):I static LIST_HEAD(mtd_notifiers);void register_mtd_user (struct mtd_ no tifier *n ew);

41、 一一 一'int i;i static LIST_HEAD(blktra ns_majors);static void blktra ns_no tify_add(struct mtdnfo *mtd)? 一一 一Iistruct list_head *this;iif (mtd->type = MTD_ABSENT)設(shè)備不存在return;IrI/ 遍歷每個(gè)MTE主塊設(shè)備list_for_each(this, & blktra ns_majors) struct mtd_blktra ns_ops *tr = list_e ntry(this,|struct mtd_

42、blktra ns_ops, list);i'tr->add_mtd(tr, mtd);: 一Idow n(&m td_table_mutex);f /將MTD塊設(shè)備的通知結(jié)構(gòu)實(shí)例blktrans_notifier加入i/ 到全局鏈表 mtd notifiers上Ilist_add(&n ew->list, &mtd_ no tifiers);j一模塊引用計(jì)數(shù)加1 -j _module_get(THIS_MODULE);I/ 對(duì)每個(gè)MTD塊設(shè)備調(diào)用MTD通知結(jié)構(gòu)實(shí)例的加設(shè)備函數(shù):for (i=0; i< MAX_MTD_DEVICES; i+)

43、if (mtd_tablei)n ew->add(mtd_tablei);up(&m td_table_mutex); 一 一函數(shù)blktrans_notify_add通知MTD翻譯層將設(shè)備加入到鏈表 blktrans_majors中,并分配處理每個(gè)MTD分區(qū)對(duì)應(yīng)的通用硬盤(pán)結(jié)構(gòu)。函數(shù)blktrans_notify_add分析如下(在 drivers/mtd/mtd_blkdevs.c 中):函數(shù)mtdblock_add_mtd分配了 MTD翻譯層塊設(shè)備結(jié)構(gòu),初始化后加到MTD翻譯層塊設(shè)備鏈表中,函數(shù)mtdblock_add_mtd分析如下:static void mtdblock

44、_add_mtd(struct mtd_blktra ns_ops *tr,IIstruct mtdnfo *mtd)i:IIIristruct mtd_blktra ns_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);i'if (!dev)return;jmemset(dev, 0, sizeof(*dev);|dev->mtd = mtd;dev->de vnum = mtd->in dex; dev->blksize = 512;Iidev->size = mtd->size >> 9;i

45、'dev->tr = tr;if (!(mtd->flags & MTD_WRITEABLE)j dev->reado nly = 1;|add_mtd_blktra ns_dev(dev);II函數(shù)add_mtd_blktrans_dev給每個(gè)MT吐設(shè)備分配設(shè)備號(hào),并加到 MTD設(shè)備鏈 表對(duì)應(yīng)位置上。然后給每個(gè)MTD設(shè)備分區(qū)分配一個(gè)通用硬盤(pán)結(jié)構(gòu),初始化這個(gè)通 用硬盤(pán)結(jié)構(gòu)后,再注冊(cè)通用硬盤(pán)。這樣通過(guò)通用硬盤(pán)就可以訪問(wèn)到每個(gè) MTD設(shè)備 分區(qū)。函數(shù) add_mtd_blktrans_dev 分析如下(在 drivers/mtd/mtd_blkdevs.c 中):

46、int add_mtd_blktra ns_dev(struct mtd_blktra ns_dev *new)I! struct mtd_blktra ns_ops *tr = n ew->tr;struct list_head *this;if (!tr->writesect) n ew->read only = 1;:/ 分配通知硬盤(pán)結(jié)構(gòu)gen disk,每分區(qū)一個(gè) gd = alloc_disk(1 << tr->part_bits);;if (!gd) Ilist_del(&n ew->list);i1return -ENOMEM;;

47、1I'/ 初始化通用硬盤(pán)結(jié)構(gòu)Igd->major = tr->major;gd->first_m inor = (n ew->de vnum) << tr->part_bits;:gd->fops = &mtd_blktra ns_ops;i'snprin tf(gd->disk_ name, sizeof(gd->disk_ name),i1“s%”,tr ->name, (tr- >part_bits? ' a' : ' O' ) + new->devnum

48、);:snprin tf(gd->devfs_ name, sizeof(gd->devfs_ name),I“%s/%C , tr ->name, (tr- >part_bits? ' a' : ' O' ) +i1 n ew->de vnu m);1II/* 2.5 has capacity in units of 512 bytes while stilli' havi ng BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ set_capacity(gd, (

49、n ew->size * n ew->blksize) >> 9);:gd->private_data = new; /通用硬盤(pán)結(jié)構(gòu)的私有數(shù)據(jù)指向翻譯層的MTD|設(shè)備一jn ew->blkcore_priv = gd;gd->queue = tr->blkcore_priv->rq; /設(shè)置請(qǐng)求隊(duì)列irIif (n ew->read only) set_disk_ro(gd, 1);/設(shè)置硬盤(pán)讀寫(xiě)模式:add_disk(gd);加通用硬盤(pán)結(jié)構(gòu)到全局鏈表中return 0;MTD塊設(shè)備的讀寫(xiě)操作函數(shù)mtdblock_writesect

50、調(diào)用層次圖MTD翻譯層設(shè)備操作函數(shù)集實(shí)例mtdblock_tr有對(duì)MT設(shè)備的各種操作函數(shù),這 些操作函數(shù)調(diào)用了 mtd_info結(jié)構(gòu)中的操作函數(shù)。這里只分析了函數(shù) mtdblock_writesect ,它的源代碼都在 drivers/mtd/mtdblock.c 中。由于 flash 設(shè)備需要先擦除一個(gè)扇區(qū),再才能寫(xiě)一個(gè)扇區(qū),因而,使用了緩存來(lái)幫助不是正 好一個(gè)扇區(qū)的數(shù)據(jù)的寫(xiě)操作。函數(shù)mtdblock_writesect將數(shù)據(jù)寫(xiě)入到flash設(shè)備中。函數(shù)分析如下:Istatic int mtdblock_writesect(struct mtd_blktra ns_dev *dev,un s

51、ig ned long block, char *buf);I /從MTD塊設(shè)備數(shù)組中得到塊設(shè)備結(jié)構(gòu)struct mtdblk_dev *mtdblk = mtdblksdev->de vnu m;if (un likely(!mtdblk->cache_data && mtdblk->cache_size) |/分配塊設(shè)備用于擦除的緩存空間一imtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);if (!mtdblk->cache_data)-return -EINTR;II!j/

52、 從位置block開(kāi)始寫(xiě)一個(gè)扇區(qū)(512字節(jié))|return do_cached_write(mtdblk, block<<9, 512, buf);函數(shù)do_cached_write將數(shù)據(jù)寫(xiě)入到設(shè)備,由于flash設(shè)備需要先擦除再才能寫(xiě)入,因而,在數(shù)據(jù)塊大小不是正好扇區(qū)大小,需要通過(guò)緩存湊合成一個(gè)扇區(qū)時(shí),才能寫(xiě)入到設(shè)備。函數(shù)do_cached_write分析如下:static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,int len, const char *buf); struct mtd

53、nfo *mtd=mtdblk->mtd;i/ 得到擦除緩沖區(qū)大小|fun sig ned int sect_size = mtdblk->cache_size;I:size t retlen;;i'int ret;jif (!sect_size)如果塊設(shè)備的緩沖大小為0,直接寫(xiě)設(shè)備|return MTD_WRITE (mtd, pos, le n, & retle n, buf);II:while (le n > 0) - /將要寫(xiě)的在設(shè)備上的位置pos地址處,長(zhǎng)度為len/|<-offset->|v-size->|/sect_start-

54、|poslen-|If/|<- sect_size ->|j/計(jì)算扇區(qū)開(kāi)始位置jun sig ned long sect_start = (pos/sect_size)*sect_size;:/計(jì)算出相對(duì)扇區(qū)開(kāi)始位置的偏移;Ii- un sig ned int offset = pos - sect_start;!/ 計(jì)算出所寫(xiě)的大小|un sig ned int size = sect_size - offset;if( size > len )isize = len;I:if (size = sect_size) /正好是擦除緩沖區(qū)大??;/直接寫(xiě)入,不需要通過(guò)緩沖區(qū)ret

55、 = erase_write (mtd, pos, size, buf);if (ret)!return ret;! else !/只有部分扇區(qū)大小的數(shù)據(jù),需通過(guò)緩沖區(qū)補(bǔ)充成扇區(qū)大小|;/方法是:先從設(shè)備中讀出數(shù)據(jù)到緩沖區(qū),再將buf中數(shù)據(jù)拷貝到|緩沖區(qū),/這樣,湊合成一個(gè)扇區(qū)大小的數(shù)據(jù),再把緩沖區(qū)數(shù)據(jù)寫(xiě)入設(shè)備。 |;/如果緩沖區(qū)數(shù)據(jù)是臟的,把緩沖區(qū)數(shù)據(jù)寫(xiě)設(shè)備iif (mtdblk->cache_state = STATE_DIRTY &&【Imtdblk->cache_offset != sect_start) i'ret = write_cached_data(mtdblk);'if (ret)函數(shù)write_cached_data將設(shè)備緩存中的數(shù)據(jù)寫(xiě)入到設(shè)備,在寫(xiě)完緩存中數(shù)據(jù)時(shí),緩存的狀態(tài)發(fā)生變化。函數(shù)一write_cached_data 一一 -列出如下:static int wr

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論