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

下載本文檔

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

文檔簡介

1、Linux 內(nèi)核 MTD驅(qū)動(dòng)程序與 SD卡驅(qū)動(dòng)程序flash閃存設(shè)備和 SD插卡設(shè)備是嵌入式設(shè)備用到的主要存儲設(shè)備,它們相當(dāng)于PC機(jī)的硬盤。在嵌入設(shè)備特別是手持設(shè)備中,flash閃存是焊接在嵌入設(shè)備主板上的 flash閃存芯片。在嵌入設(shè)備上有MMC/SD卡控制器及插槽,可通過MMC/SD來擴(kuò)充存儲空間。嵌入設(shè)備的存儲設(shè)備的空間劃分及所有邏輯設(shè)備和文件系統(tǒng)示例列出如下圖:圖:嵌入設(shè)備的存儲空間劃分及文件系統(tǒng)示例圖在嵌入設(shè)備上的 flash 芯片上 blob 和 zImage 直接按內(nèi)存線性地址存儲管理, 對于 flash 芯片上留出的供用戶使用的存儲空間,使用 MTDBLOCK塊設(shè)備和 JFFS

2、2 文件系統(tǒng)。對于 flash 芯片的分區(qū)表信息則以 MTDCHAR字符設(shè)備來存儲管理。在嵌入設(shè)備上的 MMC/SD插卡則由 MMCBLOCK驅(qū)動(dòng)程序和 VFAT文件系統(tǒng)進(jìn)行存儲管理。本章分析了 MTD設(shè)備和 MMC/SD驅(qū)動(dòng)程序。Figure 3-1. UBI/MTD Integration目錄 隱藏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è)備的讀寫操作o 1.6 MTD核心初始化o 1.7 MTD字符設(shè)備o 1.8 具體 flash 芯片的探測及映射o

3、 1.9 驅(qū)動(dòng)程序?qū)嵗治? SD/MMC卡塊設(shè)備驅(qū)動(dòng)程序o 2.1 MMC抽象設(shè)備層相關(guān)結(jié)構(gòu)( 1)設(shè)備描述結(jié)構(gòu)( 2) 讀寫請求相關(guān)結(jié)構(gòu)o 2.2 MMC抽象設(shè)備層 MMC塊設(shè)備驅(qū)動(dòng)程序( 1) MMC塊設(shè)備驅(qū)動(dòng)程序初始化( 2) MMC塊設(shè)備驅(qū)動(dòng)程序探測函數(shù)( 3) MMC卡請求的處理o 2.3 具體 MMC控制器驅(qū)動(dòng)程序示例( 1) amba控制器驅(qū)動(dòng)程序相關(guān)結(jié)構(gòu)( 2) amba控制器的初始化( 3)設(shè)備探測函數(shù)mmci_probe( 4) amba控制器操作函數(shù)MTD內(nèi)存技術(shù)設(shè)備Linux 中 MTD子系統(tǒng)在系統(tǒng)的硬件驅(qū)動(dòng)程序和文件系統(tǒng)之間提供通用接口。 在 MTD 上常用的文件文

4、件系統(tǒng)是 JFFS2日志閃存文件系統(tǒng)版本 2(Journaling FlashFile System)。 JFFS2用于微型嵌入式設(shè)備的原始閃存芯片的文件系統(tǒng)。 JFFS2 文件系統(tǒng)是日志結(jié)構(gòu)化的, 這意味著它基本上是一長列節(jié)點(diǎn)。 每個(gè)節(jié)點(diǎn)包含有關(guān)文件的部分信息 可能是文件的名稱、也許是一些數(shù)據(jù)。與 Ext2 文件系統(tǒng)相比, JFFS2因?yàn)橛幸韵逻@些優(yōu)點(diǎn):JFFS2在扇區(qū)級別上執(zhí)行閃存擦除寫讀操作要比Ext2 文件系統(tǒng)好。 JFFS2提供了比 Ext2fs 更好的崩潰掉電安全保護(hù)。當(dāng)需要更改少量數(shù)據(jù)時(shí),Ext2 文件系統(tǒng)將整個(gè)扇區(qū)復(fù)制到內(nèi)存(DRAM)中,在內(nèi)存中合并新數(shù)據(jù),并寫回整個(gè)扇區(qū)。這

5、意味著為了更改單個(gè)字,必須對整個(gè)扇區(qū)(64 KB)執(zhí)行讀擦除寫例程 ,這樣做的效率非常低。JFFS2是附加文件而不是重寫整個(gè)扇區(qū),并且具有崩潰掉電安全保護(hù)這一功能。JFFS2是是為 FLASH定制的文件系統(tǒng), JFFS1實(shí)現(xiàn)了日志功能, JFFS2實(shí)現(xiàn)了壓縮功能。它的整個(gè)設(shè)計(jì)提供了更好的閃存管理。 JFFS2的 缺點(diǎn)很少,主要是當(dāng)文件系統(tǒng)已滿或接近滿時(shí), JFFS2會大大放慢運(yùn)行速度。這是因?yàn)槔占膯栴}。MTD驅(qū)動(dòng)程序是專門為基于閃存的設(shè)備所設(shè)計(jì)的, 它提供了基于扇區(qū)的擦除和讀寫操作的更好的接口。 MTD子系統(tǒng)支持眾多的閃存設(shè)備,并且有越來越多的驅(qū)動(dòng)程序正被添加進(jìn)來以用于不同的閃存芯片。M

6、TD子系統(tǒng)提供了對字符設(shè)備MTD_CHAR和塊設(shè)備 MTD_BLOCK的支持。 MTD_CHAR提供對閃存的原始字符訪問, 象通常的 IDE 硬盤一樣,在 MTD_BLOCK塊設(shè)備上可創(chuàng)建文件系統(tǒng)。 MTD_CHAR字符設(shè)備文件是/dev/mtd0 、mtd1、mtd2 等,MTD_BLOCK塊設(shè)備文件是 /dev/mtdblock0、mtdblock1 等等。NAND和 NOR是制作 Flash 的工藝,CFI 和 JEDEC是 flash 硬件提供的接口,linux通過這些用通用接口抽象出 MTD設(shè)備。 JFFS2文件系統(tǒng)就建立在 MTD設(shè)備上。NOR flash 帶有 SRAM接口,可以

7、直接存取內(nèi)部的每一個(gè)字節(jié)。NAND器件使用串行 I/O 口來存取數(shù)據(jù), 8 個(gè)引腳用來傳送控制、地址和數(shù)據(jù)信息。 NAND讀和寫操作用 512 字節(jié)的塊。MTD內(nèi)存技術(shù)設(shè)備層次結(jié)構(gòu)MTD(memory technology device 內(nèi)存技術(shù)設(shè)備 ) 在硬件和文件系統(tǒng)層之間的提供了一個(gè)抽象的接口, MTD是用來訪問內(nèi)存設(shè)備(如: ROM、 flash )的中間層,它將內(nèi)存設(shè)備的共有特性抽取出來, 從而使增加新的內(nèi)存設(shè)備驅(qū)動(dòng)程序變得更簡單。 MTD的源代碼都在 /drivers/mtd 目錄中。MTD中間層細(xì)分為四層,按從上到下依次為:設(shè)備節(jié)點(diǎn)、設(shè)備層和硬件驅(qū)動(dòng)層。 MTD中間層層次結(jié)構(gòu)圖如

8、下:MTD設(shè)備層、 MTD原始圖 1MTD中間層層次結(jié)構(gòu)圖Flash 硬件驅(qū)動(dòng)層對應(yīng)的是不同硬件的驅(qū)動(dòng)程序,符合 CFI 接口標(biāo)準(zhǔn)的 Flash 芯片驅(qū)動(dòng)驅(qū)動(dòng)程序在NAND型 Flash 的驅(qū)動(dòng)程序在 /drivers/mtd/nand它負(fù)責(zé)驅(qū)動(dòng)具體的硬件。 例如: drivers/mtd/chips 目錄中,中。在原始設(shè)備層中, 各種內(nèi)存設(shè)備抽象化為原始設(shè)備, 原始設(shè)備實(shí)際上是一種塊設(shè)備, MTD字符設(shè)備的讀寫函數(shù)也調(diào)用原始設(shè)備的操作函數(shù)來實(shí)現(xiàn)。 MTD使用 MTD 信息結(jié)構(gòu) mtd_info 來描述了原始設(shè)備的操作函數(shù)、各種信息,所有原始設(shè)備的信息也用一個(gè)全局的結(jié)構(gòu)數(shù)組來描述,列出如下(在

9、 drivers/mtd/mtdcore.c 中):struct mtd_info *mtd_tableMAX_MTD_DEVICES;每個(gè)原始設(shè)備可能分成多個(gè)設(shè)備分區(qū), 設(shè)備分區(qū)是將一個(gè)內(nèi)存分成多個(gè)塊, 每個(gè)設(shè)備分區(qū)用一個(gè)結(jié)構(gòu) mtd_part 來描述,所有的分區(qū)組成一個(gè)鏈表mtd_partitions,這個(gè)鏈表的聲明列出如下(在drivers/mtd/mtdpart.c中):/* Our partition linked list */static LIST_HEAD(mtd_partitions);MTD原始設(shè)備到具體設(shè)備之間存在的一些映射關(guān)系數(shù)據(jù)在 drivers/mtd/maps/

10、目錄下的對應(yīng)文件中。 這些映射數(shù)據(jù)包括分區(qū)信息、 I/O 映射及特定函數(shù)的映射等。這種映射關(guān)系用映射信息結(jié)構(gòu) map_info 描述。 在 MTD設(shè)備層中, MTD字符設(shè)備通過注冊的 file operation 函數(shù)集來操作設(shè)備,而這些函數(shù)是通過原始設(shè)備層的操作函數(shù)來實(shí)現(xiàn)的,即調(diào)用了塊設(shè)備的操作函數(shù)。 MTD塊設(shè)備實(shí)際了從塊層到塊設(shè)備的接口函數(shù)。所有的塊設(shè)備組成一個(gè)數(shù)組 *mtdblksMAX_MTD_DEVICES,這個(gè)結(jié)構(gòu)數(shù)組列出如下(在drivers/mtd/mtdblock.c中):static struct mtdblk_dev struct mtd_info *mtd;int c

11、ount;struct semaphore cache_sem;unsigned char *cache_data;unsigned long cache_offset;unsigned int cache_size;enum STATE_EMPTY, STATE_CLEAN, STATE_DIRTY cache_state; *mtdblksMAX_MTD_DEVICES;由于 flash設(shè)備種類的多樣性, MTD用 MTD翻譯層將三大類 flash設(shè)備進(jìn)行的封裝。每大類設(shè)備有自己的操作函數(shù)集,它們的 mtdblk_dev 結(jié)構(gòu)實(shí)例都存在 mtdblks 數(shù)組中。 MTD設(shè)備在內(nèi)核中的層次圖

12、如下圖。圖 MTD設(shè)備在內(nèi)核中的層次圖MTD原始設(shè)備層中封裝了三大類設(shè)備, 分別是 Inverse Flash 、NANDFlash 和 MTD。它們的上體讀寫方法不一樣。這里只分析了MTD,因?yàn)樗亲畛S玫摹TO(shè)備層和原始設(shè)備層的函數(shù)調(diào)用關(guān)系原始設(shè)備層主要是通過mtd_info 結(jié)構(gòu)來管理設(shè)備, 函數(shù) add_mtd_partitions()和 del_mtd_partitions() 將的設(shè)備分區(qū)的 mtd_info 結(jié)構(gòu)加入 mtd_table 數(shù)組中, mtdpart.c 中還實(shí)現(xiàn)了 part_read 、part_write 等函數(shù),這些函數(shù)注冊在每個(gè)分區(qū)中,指向主分區(qū)的 read 、

13、write 函數(shù),之所以這樣做而不直接將主分區(qū)的read 、write 函數(shù)連接到每個(gè)分區(qū)中的原因是因?yàn)楹瘮?shù)中的參數(shù) mtd_info 會被調(diào)用者置為函數(shù)所屬的 mtd_info ,即 mtd- >read(mtd,) , 而參數(shù) mtd_info 其實(shí)應(yīng)該指向主分區(qū)。設(shè)備層和原始設(shè)備層的函數(shù)調(diào)用關(guān)系圖如圖 2。MTD各種結(jié)構(gòu)之間的關(guān)系圖如圖3。圖 2設(shè)備層和原始設(shè)備層的函數(shù)調(diào)用關(guān)系圖 3MTD各種結(jié)構(gòu)之間的關(guān)系MTD相關(guān)結(jié)構(gòu)MTD塊設(shè)備的結(jié)構(gòu) mtdblk_dev 代表了一個(gè)閃存塊設(shè)備, MTD字符設(shè)備沒有相對應(yīng)的結(jié)構(gòu)。結(jié)構(gòu) mtdblk_dev 列出如下:struct mtdblk_

14、dev struct mtd_info mtd; / Locked */下層原始設(shè)備層的MTD設(shè)備結(jié)構(gòu)int count;struct semaphore cache_sem;unsigned char *cache_data;/ 緩沖區(qū)數(shù)據(jù)地址unsigned long cache_offset;/在緩沖區(qū)中讀寫位置偏移/ 緩沖區(qū)中的讀寫數(shù)據(jù)大?。ㄍǔ1辉O(shè)置為 MTD設(shè)備的 erasesize )unsigned int cache_size;enum STATE_EMPTY, STATE_CLEAN, STATE_DIRTY cache_state;/ 緩沖區(qū)狀態(tài)結(jié)構(gòu) mtd_info描述

15、了一個(gè) MTD原始設(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) mtd_info 分析如下:struct mtd_info u_char type;/ 內(nèi)存技術(shù)的類型u_int32_t flags;/ 標(biāo)志位u_int32_t size;/ mtd設(shè)備的大小/ “主要的” erasesize(同一個(gè) mtd 設(shè)備可能有數(shù)種不同的 erasesize ) u_int32_t erasesize;u_int32_t oobb

16、lock; / oob塊大小,例如: 512u_int32_t oobsize;/每個(gè)塊oob 數(shù)據(jù)量,例如16u_int32_t ecctype;/ecc類型u_int32_t eccsize;/自動(dòng)ecc 可以工作的范圍/ Kernel-only stuff starts here. char *name;int index;/ 可變擦除區(qū)域的數(shù)據(jù),如果是 0,意味著整個(gè)設(shè)備為 erasesizeint numeraseregions; /不同 erasesize的區(qū)域的數(shù)目(通常是1)struct mtd_erase_region_info *eraseregions;u_int32_t

17、 bank_size;struct module *module;/ 此 routine 用于將一個(gè) erase_info 加入 erase queue int (*erase) (struct mtd_info *mtd, struct erase_info *instr);/* This stuff for eXecute-In-Place */int (*point) (struct mtd_info *mtd, loff_t from, size_t len,size_t *retlen, u_char *mtdbuf);/* We probably shouldnt allow XI

18、P if the unpoint isnt a NULL*/void (*unpoint) (struct mtd_info *mtd, u_char * addr); 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);int (*read_ecc) (struct mtd_info

19、*mtd, loff_t from,size_t len, size_t *retlen, u_char *buf, u_char*eccbuf);int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);int (*write_oob) (s

20、truct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);/* iovec-based read/write methods. We need these especially for NAND flash,with its limited number of write cycles per erase.NB: The count parameter is the number of vectors, each ofwhich contains an (ofs, len) tuple.*/in

21、t (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);/* Sync */void (*sync) (struct mtd_info *mtd);/* Chip-supported device locking */int

22、(*lock) (struct mtd_info *mtd, loff_t ofs, size_t len); int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len); /* Power Management functions */int (*suspend) (struct mtd_info *mtd);void (*resume) (struct mtd_info *mtd);void *priv;/ 指向 map_info 結(jié)構(gòu)設(shè)備層的 mtdblcok 設(shè)備的 notifier聲明如下:static struct mt

23、d_notifier notifier = mtd_notify_add,mtd_notify_remove,NULL;mtd_part 結(jié)構(gòu)是用于描述MTD原始設(shè)備分區(qū)的,結(jié)構(gòu)mtd_part 中的 list成員鏈成一個(gè)鏈表 mtd_partitons。每個(gè) mtd_part 結(jié)構(gòu)中的 mtd_info結(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列出如下:/* Our partition linked list */static LIST_

24、HEAD(mtd_partitions);MTD原始設(shè)備分區(qū)的鏈表struct mtd_part struct mtd_info mtd;/ 分區(qū)的信息(大部分由其master決定)struct mtd_info *master;u_int32_t offset;int index;struct list_head list;/ 該分區(qū)的主分區(qū)/ 該分區(qū)的偏移地址/ 分區(qū)號;結(jié)構(gòu) mtd_partition 描述 mtd 設(shè)備分區(qū)的結(jié)構(gòu),在 MTD原始設(shè)備層調(diào)用函數(shù) add_mtd_partions 時(shí)傳遞分區(qū)信息使用。結(jié)構(gòu)列出如下(在include/linux/mtd/partition.h

25、中):struct mtd_partition char *name;u_int32_t size;/ 分區(qū)名/ 分區(qū)大小u_int32_t offset;/ 在主MTD空間的偏移u_int32_t mask_flags;MTD塊設(shè)備初始化圖函數(shù) init_mtdblock調(diào)用層次圖在具體的設(shè)備驅(qū)動(dòng)程序初始化時(shí), 它會添加一個(gè) MTD設(shè)備結(jié)構(gòu)到 mtd_table 數(shù)組中。 MTD翻譯層通過查找這個(gè)數(shù)組,可訪問到各個(gè)具體設(shè)備驅(qū)動(dòng)程序。函數(shù) init_mtdblock 注冊一個(gè) MTD翻譯層設(shè)備,初始化處理請求的線程,賦上MTD翻譯層設(shè)備操作函數(shù)集實(shí)例,注冊這個(gè)設(shè)備的通用硬盤結(jié)構(gòu)。函數(shù)init_

26、mtdblock調(diào)用層次圖如上圖。mtd 塊設(shè)備驅(qū)動(dòng)程序利用一個(gè)線程,當(dāng)有讀寫請求時(shí),從緩沖區(qū)將數(shù)據(jù)寫入塊設(shè)備或從塊設(shè)備讀入到緩沖區(qū)中。函數(shù) init_mtdblock分析如下(在 drivers/mtd/mtdblock.c中):static int _init init_mtdblock(void)return register_mtd_blktrans(&mtdblock_tr);MTD翻譯層設(shè)備操作函數(shù)集實(shí)例列出如下:static struct mtd_blktrans_ops mtdblock_tr = .name.major.part_bits.open.flush.rel

27、ease.readsect.writesect.add_mtd= “mtdblock ”,= 31,= 0,= mtdblock_open,= mtdblock_flush,= mtdblock_release,= mtdblock_readsect,= mtdblock_writesect,= mtdblock_add_mtd,.remove_dev= mtdblock_remove_dev,.owner= THIS_MODULE,;static LIST_HEAD(blktrans_majors);int register_mtd_blktrans(struct mtd_blktrans_

28、ops *tr)int ret, i;/ 如果第一個(gè)設(shè)備類型被注冊了,注冊 notifier 來阻止 /* Register the notifier if/when the first device type is registered, to prevent the link/init ordering from fuckingus over. */如果不存在/注冊 MTD翻譯層塊設(shè)備,創(chuàng)建通用硬盤結(jié)構(gòu)并注冊register_mtd_user(&blktrans_notifier); tr->blkcore_priv = kmalloc(sizeof(*tr->blkc

29、ore_priv),GFP_KERNEL);if (!tr->blkcore_priv)return -ENOMEM;memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv); down(&mtd_table_mutex);/ 創(chuàng)建 blk_major_name 結(jié)構(gòu)初始化后加到 &major_names 數(shù)組中 ret = register_blkdev(tr->major, tr->name);,spin_lock_init(&tr->blkcore_priv->queue_

30、lock); init_completion(&tr->blkcore_priv->thread_dead); init_waitqueue_head(&tr->blkcore_priv->thread_wq);/ 創(chuàng)建請求隊(duì)列并初始化,賦上塊設(shè)備特定的請求處理函數(shù) mtd_blktrans_requesttr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock);,tr->blkcore_pri

31、v->rq->queuedata= tr;/賦上 MTD翻譯層塊設(shè)備操作函數(shù)集/ 創(chuàng)建線程 mtd_blktrans_threadret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);,/ 在 devfs 文件系統(tǒng)中創(chuàng)建設(shè)備的目錄名 devfs_mk_dir(tr->name);INIT_LIST_HEAD(&tr->devs);/ 初始化設(shè)備的鏈表 list_add(&tr->list, &blktrans_majors);for (i=0; i<MAX_MTD_DEV

32、ICES; i+) if (mtd_tablei && mtd_tablei->type != MTD_ABSENT)/創(chuàng)建 MTD翻譯層設(shè)備結(jié)構(gòu)并初始化,然后到MTD設(shè)備鏈表中tr->add_mtd(tr, mtd_tablei);up(&mtd_table_mutex);return 0;函數(shù) mtd_blktrans_request 是 MTD設(shè)備的請求處理函數(shù),當(dāng)請求隊(duì)列中的請求需要設(shè)備處理時(shí)調(diào)用這個(gè)函數(shù)。在 MTD設(shè)備中,函數(shù) mtd_blktrans_request 喚醒了 MTD塊設(shè)備的線程來進(jìn)行處理。函數(shù)列出如下(在drivers/mtd/m

33、td_blkdevs.c中):static void mtd_blktrans_request(struct request_queue *rq)struct mtd_blktrans_ops *tr = rq->queuedata;wake_up(&tr->blkcore_priv->thread_wq);線程函數(shù) mtd_blktrans_thread 處理塊設(shè)備的讀寫請求,函數(shù) mtd_blktrans_thread 列出如下:static int mtd_blktrans_thread(void *arg)struct mtd_blktrans_ops *tr

34、 = arg;struct request_queue *rq = tr->blkcore_priv->rq;/* we might get involved when memory gets low, so use PF_MEMALLOC */ current->flags |= PF_MEMALLOC | PF_NOFREEZE;/ 變成以 init 為父進(jìn)程的后臺進(jìn)程daemonize( “%sd”, tr->name);/ 因?yàn)橐恍﹥?nèi)核線程實(shí)際上要與信號打交道, daemonize() 沒有做后臺化工作。/ 我們不能僅調(diào)用 exit_sighand 函數(shù),/ 因

35、為當(dāng)最終退出時(shí)這樣將可能引起 oop(對象指針溢出錯(cuò)誤)。spin_lock_irq(&current->sighand->siglock);sigfillset(&current->blocked);/ 重新分析是否有掛起信號并設(shè)置或清除 TIF_SIGPENDING標(biāo)識給當(dāng)前進(jìn)程 recalc_sigpending();spin_unlock_irq(&current->sighand->siglock); spin_lock_irq(rq->queue_lock);while (!tr->blkcore_priv->

36、exiting) struct request *req;struct mtd_blktrans_dev *dev;int res = 0;DECLARE_WAITQUEUE(wait, current);/ 聲明當(dāng)前進(jìn)程的等待隊(duì)列req= elv_next_request(rq);/從塊設(shè)備的請求隊(duì)列中得到下一個(gè)請求if (!req) /如果請求不存在/ 將設(shè)備的等待線程加到等待隊(duì)列中add_wait_queue(&tr->blkcore_priv->thread_wq, &wait); set_current_state(TASK_INTERRUPTIBLE);

37、 spin_unlock_irq(rq->queue_lock);schedule();/ 調(diào)度讓 CPU有機(jī)會執(zhí)行等待的線程remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait); spin_lock_irq(rq->queue_lock);continue;/ 如果請求存在dev = req->rq_disk->private_data;/得到請求的設(shè)備tr = dev->tr;/ 得到 MTD翻譯層設(shè)備操作函數(shù)集實(shí)例spin_unlock_irq(rq->queue_lo

38、ck);down(&dev->sem); res = do_blktrans_request(tr, dev, req);/請求 up(&dev->sem);spin_lock_irq(rq->queue_lock);end_request(req, res); /從請求隊(duì)列中刪除請求并更新統(tǒng)計(jì)信息處理spin_unlock_irq(rq->queue_lock);/調(diào)用所有請求處理完的回調(diào)函數(shù),并調(diào)用do_exit函數(shù)退出線程complete_and_exit(&tr->blkcore_priv->thread_dead, 0);函

39、數(shù) do_blktrans_request 完成請求的具體操作, 它調(diào)用 MTD翻譯層設(shè)備操作函數(shù)集實(shí)例中的具體函數(shù)來進(jìn)行處理。函數(shù) do_blktrans_request 分析如下:static int do_blktrans_request(struct mtd_blktrans_ops *tr, struct mtd_blktrans_dev *dev,struct request *req)unsigned long block, nsect;char *buf;block = req->sector;nsect = req->current_nr_sectors;buf

40、= req->buffer;if (!(req->flags & REQ_CMD)return 0;/ 如果讀寫的扇區(qū)數(shù)超出了塊設(shè)備的容量,返回 if (block + nsect > get_capacity(req->rq_disk)return 0;/ 根據(jù) (rq)->flags & 1 標(biāo)識來判斷操作方式,調(diào)用具體的設(shè)備操作函數(shù) switch(rq_data_dir(req) case READ:for (; nsect > 0; nsect-, block+, buf += 512)if (tr->readsect(dev,

41、 block, buf)return 0;return 1;case WRITE:if (!tr->writesect)return 0;for (; nsect > 0; nsect-, block+, buf += 512)if (tr->writesect(dev, block, buf)return 0;return 1;default:printk(KERN_NOTICE “Unknown request %ld n”, rq_data_dir(req);return 0;圖函數(shù) register_mtd_user調(diào)用層次圖結(jié)構(gòu) mtd_notifier是用于通知加

42、上和去掉MTD原始設(shè)備。對于塊設(shè)備來說,這個(gè)結(jié)構(gòu)實(shí)例 blktrans_notifier用來通知翻譯層加上和去掉MTD原始設(shè)備。結(jié)構(gòu)實(shí)例 blktrans_notifier列出如下(在 drivers/mtd/mtd_blkdevs.c中):static struct mtd_notifier blktrans_notifier = .add = blktrans_notify_add,.remove = blktrans_notify_remove,;函數(shù) register_mtd_user注冊 MTD設(shè)備,通過分配通盤硬盤結(jié)構(gòu)來激活每個(gè)MTD設(shè)備,使其出現(xiàn)在系統(tǒng)中。函數(shù) register_

43、mtd_user 調(diào)用層次圖如上圖。 函數(shù) register_mtd_user 分析如下(在 drivers/mtd/mtdcore.c 中):static LIST_HEAD(mtd_notifiers);void register_mtd_user (struct mtd_notifier *new)int i;down(&mtd_table_mutex);/將 MTD塊設(shè)備的通知結(jié)構(gòu)實(shí)例blktrans_notifier加入/ 到全局鏈表 mtd_notifiers 上list_add(&new->list, &mtd_notifiers);/ 模塊引用計(jì)數(shù)

44、加 1_module_get(THIS_MODULE);/ 對每個(gè) MTD塊設(shè)備調(diào)用 MTD通知結(jié)構(gòu)實(shí)例的加設(shè)備函數(shù) for (i=0; i< MAX_MTD_DEVICES; i+)if (mtd_tablei)new->add(mtd_tablei);up(&mtd_table_mutex);函數(shù) blktrans_notify_add 通知 MTD翻譯層將設(shè)備加入到鏈表 blktrans_majors 中,并分配處理每個(gè) MTD分區(qū)對應(yīng)的通用硬盤結(jié)構(gòu)。 函數(shù) blktrans_notify_add分析如下(在 drivers/mtd/mtd_blkdevs.c中):s

45、tatic LIST_HEAD(blktrans_majors);static void blktrans_notify_add(struct mtd_info *mtd)struct list_head *this;if (mtd->type = MTD_ABSENT)/設(shè)備不存在return;/ 遍歷每個(gè) MTD主塊設(shè)備list_for_each(this, &blktrans_majors) struct mtd_blktrans_ops *tr = list_entry(this,struct mtd_blktrans_ops, list);tr->add_mtd(

46、tr, mtd);函數(shù) mtdblock_add_mtd層塊設(shè)備鏈表中,函數(shù)分配了 MTD翻譯層塊設(shè)備結(jié)構(gòu),初始化后加到mtdblock_add_mtd 分析如下:MTD翻譯static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr,struct mtd_info *mtd)struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); if (!dev)return;memset(dev, 0, sizeof(*dev);dev->mtd = mtd;dev->

47、;devnum = mtd->index;dev->blksize = 512;dev->size = mtd->size >> 9;dev->tr = tr;if (!(mtd->flags & MTD_WRITEABLE)dev->readonly = 1;add_mtd_blktrans_dev(dev);函數(shù) add_mtd_blktrans_dev 給每個(gè) MTD主設(shè)備分配設(shè)備號,并加到 MTD設(shè)備鏈表對應(yīng)位置上。 然后給每個(gè) MTD設(shè)備分區(qū)分配一個(gè)通用硬盤結(jié)構(gòu), 初始化這個(gè)通用硬盤結(jié)構(gòu)后, 再注冊通用硬盤。 這樣通過通用

48、硬盤就可以訪問到每個(gè) MTD設(shè)備分區(qū)。函數(shù) add_mtd_blktrans_dev分析如下(在 drivers/mtd/mtd_blkdevs.c中):int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)struct mtd_blktrans_ops *tr = new->tr;struct list_head *this;int last_devnum = -1;struct gendisk *gd;if (!down_trylock(&mtd_table_mutex) up(&mtd_table_mutex);BUG();/ 遍歷 MTD每個(gè)主塊設(shè)備 list_for_each(

溫馨提示

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

最新文檔

評論

0/150

提交評論