linux sd卡驅(qū)動_第1頁
linux sd卡驅(qū)動_第2頁
linux sd卡驅(qū)動_第3頁
linux sd卡驅(qū)動_第4頁
linux sd卡驅(qū)動_第5頁
已閱讀5頁,還剩59頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、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è)備和JFFS2文件系統(tǒng)。對于flash芯片的分區(qū)表信息則以MTDCHAR字符設(shè)備來存

2、儲管理。 在嵌入設(shè)備上的MMC/SD插卡則由MMCBLOCK驅(qū)動程序和VFAT文件系統(tǒng)進(jìn)行存儲管理。本章分析了MTD設(shè)備和MMC/SD驅(qū)動程序。 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 1.9 驅(qū)動程序?qū)嵗治?· 2 SD/MMC卡塊

3、設(shè)備驅(qū)動程序 o 2.1 MMC抽象設(shè)備層相關(guān)結(jié)構(gòu) § 2.1.1 (1)設(shè)備描述結(jié)構(gòu) § 2.1.2 (2) 讀寫請求相關(guān)結(jié)構(gòu) o 2.2 MMC抽象設(shè)備層MMC塊設(shè)備驅(qū)動程序 § 2.2.1 (1)MMC塊設(shè)備驅(qū)動程序初始化 § 2.2.2 (2)MMC塊設(shè)備驅(qū)動程序探測函數(shù) § 2.2.3 (3)MMC卡請求的處理 o 2.3 具體MMC控制器驅(qū)動程序示例 § 2.3.1 (1)amba控制器驅(qū)動程序相關(guān)結(jié)構(gòu) § 2.3.2 (2)amba控制器的初始化 § 2.3.3 (3)設(shè)備探測函數(shù)mmci_probe

4、 § 2.3.4 (4)amba控制器操作函數(shù) MTD內(nèi)存技術(shù)設(shè)備 Linux中MTD子系統(tǒng)在系統(tǒng)的硬件驅(qū)動程序和文件系統(tǒng)之間提供通用接口。在MTD上常用的文件文件系統(tǒng)是JFFS2日志閃存文件系統(tǒng)版本 2(Journaling Flash File System)。JFFS2用于微型嵌入式設(shè)備的原始閃存芯片的文件系統(tǒng)。JFFS2文件系統(tǒng)是日志結(jié)構(gòu)化的,這意味著它基本上是一長列節(jié)點(diǎn)。每個節(jié)點(diǎn)包含有關(guān)文件的部分信息 可能是文件的名稱、也許是一些數(shù)據(jù)。與Ext2文件系統(tǒng)相比,JFFS2因?yàn)橛幸韵逻@些優(yōu)點(diǎn): JFFS2在扇區(qū)級別上執(zhí)行閃存擦除寫讀操作要比Ext2文件系統(tǒng)好。JFFS2提供了比

5、Ext2fs更好的崩潰掉電安全保護(hù)。當(dāng)需要更改少量數(shù)據(jù)時,Ext2文件系統(tǒng)將整個扇區(qū)復(fù)制到內(nèi)存(DRAM)中,在內(nèi)存中合并新數(shù)據(jù),并寫回整個扇區(qū)。這意味著為了更改單個字,必須對整個扇區(qū)(64 KB)執(zhí)行讀擦除寫例程 ,這樣做的效率非常低。JFFS2是附加文件而不是重寫整個扇區(qū),并且具有崩潰掉電安全保護(hù)這一功能。 JFFS2是是為FLASH定制的文件系統(tǒng),JFFS1實(shí)現(xiàn)了日志功能,JFFS2實(shí)現(xiàn)了壓縮功能。它的整個設(shè)計(jì)提供了更好的閃存管理。JFFS2的 缺點(diǎn)很少,主要是當(dāng)文件系統(tǒng)已滿或接近滿時,JFFS2會大大放慢運(yùn)行速度。這是因?yàn)槔占膯栴}。 MTD驅(qū)動程序是專門為基于閃存的設(shè)備所設(shè)計(jì)的,

6、它提供了基于扇區(qū)的擦除和讀寫操作的更好的接口。MTD子系統(tǒng)支持眾多的閃存設(shè)備,并且有越來越多的驅(qū)動程序正被添加進(jìn)來以用于不同的閃存芯片。 MTD子系統(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通過這些用通用

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

8、層,按從上到下依次為:設(shè)備節(jié)點(diǎn)、MTD設(shè)備層、MTD原始設(shè)備層和硬件驅(qū)動層。MTD中間層層次結(jié)構(gòu)圖如下: 圖1MTD中間層層次結(jié)構(gòu)圖Flash硬件驅(qū)動層對應(yīng)的是不同硬件的驅(qū)動程序,它負(fù)責(zé)驅(qū)動具體的硬件。例如:符合CFI接口標(biāo)準(zhǔn)的Flash芯片驅(qū)動驅(qū)動程序在drivers/mtd/chips目錄中,NAND型Flash的驅(qū)動程序在/drivers/mtd/nand中。 在原始設(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è)備的信息也

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

10、ivers/mtd/maps/目錄下的對應(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è)備組成一個數(shù)組*mtdblksMAX_MTD_DEVICES,這個結(jié)構(gòu)數(shù)組列出如下(在drivers/mtd /mtdblock.c中): static struct mtdblk_dev struct mtd_info *mtd;

11、int count;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、NAND Flash和MTD。它們的上體讀寫方法不一樣。這里只分析了MTD,因?yàn)樗亲畛S玫摹?設(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ù)注冊在每個分區(qū)中,指向主分區(qū)的read、write函數(shù),之所以這樣做而不直接將主分

13、區(qū)的read、write函數(shù)連接到每個分區(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代表了一個閃存塊設(shè)備,MTD字符設(shè)備沒有相對應(yīng)的結(jié)構(gòu)。結(jié)構(gòu)mtdblk_dev列出如下: struct mtdblk_dev struct mtd_info mtd; / Locked */下層原

14、始設(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描述了一個MTD原始設(shè)備,每個分區(qū)也被實(shí)現(xiàn)為一個mtd_info,如果有兩個MTD原始設(shè)備,每個

15、上有三個分區(qū),在系統(tǒng)中就一共有6個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(同一個mtd設(shè)備可能有數(shù)種不同的erasesize)u_int32_t erasesize;u_int32_t oobblock; / oob塊大小,例如:512u_int32_t oobsize; /每個塊oob數(shù)據(jù)量,例如16u_i

16、nt32_t ecctype;/ecc類型u_int32_t eccsize; /自動ecc可以工作的范圍  / Kernel-only stuff starts here.char *name;int index;  /可變擦除區(qū)域的數(shù)據(jù),如果是0,意味著整個設(shè)備為erasesizeint numeraseregions; /不同erasesize的區(qū)域的數(shù)目(通常是1)struct mtd_erase_region_info *eraseregions;u_int32_t bank_size;struct module *module;/此routine用于將一個era

17、se_info加入erase queueint (*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 XIP if the unpoint isnt a NULL */void (*unpoint) (struct mt

18、d_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 *mtd, loff_t from,size_t len, size_t *retlen, u_char *buf,

19、 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) (struct mtd_info *mtd, loff_t to, size_t len,size_t *retlen,

20、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.*/int (*readv) (struct mtd_info *mtd, struct iovec *vecs,un

21、signed 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 (*lock) (struct mtd_info *mtd, loff_t ofs, size_t

22、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 mtd_notifier notifier = mtd_notify_add,mtd_notify_re

23、move,NULL;mtd_part結(jié)構(gòu)是用于描述MTD原始設(shè)備分區(qū)的,結(jié)構(gòu)mtd_part中的list成員鏈成一個鏈表mtd_partitons。每個 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_HEAD(mtd_partitions);MTD原始設(shè)備分區(qū)的鏈表struct mtd_part struct m

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

25、 offset;/在主MTD空間的偏移u_int32_t mask_flags;MTD塊設(shè)備初始化 圖函數(shù)init_mtdblock調(diào)用層次圖 在具體的設(shè)備驅(qū)動程序初始化時,它會添加一個MTD設(shè)備結(jié)構(gòu)到mtd_table數(shù)組中。MTD翻譯層通過查找這個數(shù)組,可訪問到各個具體設(shè)備驅(qū)動程序。 函數(shù)init_mtdblock注冊一個MTD翻譯層設(shè)備,初始化處理請求的線程,賦上MTD翻譯層設(shè)備操作函數(shù)集實(shí)例,注冊這個設(shè)備的通用硬盤結(jié)構(gòu)。函數(shù)init_mtdblock調(diào)用層次圖如上圖。 mtd塊設(shè)備驅(qū)動程序利用一個線程,當(dāng)有讀寫請求時,從緩沖區(qū)將數(shù)據(jù)寫入塊設(shè)備或從塊設(shè)備讀入到緩沖區(qū)中。 函數(shù)init_m

26、tdblock分析如下(在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= “mtdblock”,.major= 31,.part_bits= 0,.open= mtdblock_open,.flush= mtdblock_flush,.release= mtdblock_releas

27、e,.readsect= mtdblock_readsect,.writesect= mtdblock_writesect,.add_mtd= mtdblock_add_mtd,.remove_dev= mtdblock_remove_dev,.owner= THIS_MODULE,; static LIST_HEAD(blktrans_majors);int register_mtd_blktrans(struct mtd_blktrans_ops *tr) int ret, i;/如果第一個設(shè)備類型被注冊了,注冊notifier來阻止/* Register the notifie

28、r if/when the first device type isregistered, to prevent the link/init ordering from fuckingus over. */if (!blktrans_notifier.list.next)/如果不存在/注冊MTD翻譯層塊設(shè)備,創(chuàng)建通用硬盤結(jié)構(gòu)并注冊register_mtd_user(&blktrans_notifier);tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);  if (!tr->b

29、lkcore_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_lock);init_completion(&tr->b

30、lkcore_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_priv->rq->queuedata = tr;/賦上MT

31、D翻譯層塊設(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_DEVICES; i+) if (mtd_tablei &&

32、; 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è)備處理時調(diào)用這個函數(shù)。在MTD設(shè)備中,函數(shù) mtd_blktrans_request喚醒了MTD塊設(shè)備的線程來進(jìn)行處理。函數(shù)列出如下(在drivers/mtd/mtd_blkdevs.c 中): static void mtd_b

33、lktrans_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 = arg;struct request_queue *rq =

34、 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ù),/因?yàn)楫?dāng)最終退出時這樣將可能引起oop(對象指針溢出錯誤)。 spin_loc

35、k_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->exiting) struct request *r

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

37、q(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_lock);down(&

38、;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);函數(shù)do_blktrans_

39、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 = req->buf

40、fer; 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, block,

41、 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 %ldn”, rq_data_dir(req);return 0;圖函數(shù)register_mtd_user調(diào)用層次圖結(jié)構(gòu)mtd_notifier是用于通

42、知加上和去掉MTD原始設(shè)備。對于塊設(shè)備來說,這個結(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)來激活每個MTD設(shè)備,使其出現(xiàn)在系統(tǒng)中。函數(shù)register_mtd

43、_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ù)加1_module_get

44、(THIS_MODULE); /對每個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中,并分配處理每個MTD分區(qū)對應(yīng)的通用硬盤結(jié)構(gòu)。函數(shù)blktrans_notify_add分析如下(在drivers/mtd/mtd_blkdevs.c中): static LIST_HEAD(blkt

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

46、數(shù)mtdblock_add_mtd分配了MTD翻譯層塊設(shè)備結(jié)構(gòu),初始化后加到MTD翻譯層塊設(shè)備鏈表中,函數(shù)mtdblock_add_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->devnum = mt

47、d->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給每個MTD主設(shè)備分配設(shè)備號,并加到MTD設(shè)備鏈表對應(yīng)位置上。然后給每個MTD設(shè)備分區(qū)分配一個通用硬盤結(jié)構(gòu),初始化這個通用硬盤結(jié)構(gòu)后,再注冊通用硬盤。這樣通過通用硬盤就可以訪問到每個MTD設(shè)

48、備分區(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();/遍歷

49、MTD每個主塊設(shè)備list_for_each(this, &tr->devs) struct mtd_blktrans_dev *d = list_entry(this,struct mtd_blktrans_dev,list); if (new->devnum = -1) /如果沒有設(shè)備號/使用第一個空閑的設(shè)備號if (d->devnum != last_devnum+1) /找到空閑設(shè)備號,并把設(shè)備加到鏈表的尾部new->devnum = last_devnum+1;list_add_tail(&new->list, &d-&

50、gt;list);goto added; else if (d->devnum = new->devnum) /設(shè)備號已被使用/* Required number taken */return -EBUSY; else if (d->devnum > new->devnum) /申請的設(shè)備號是空閑的,加到鏈表的尾部list_add_tail(&new->list, &d->list);goto added;last_devnum = d->devnum; if (new->devnum = -1)/如果新設(shè)備的設(shè)備

51、號為-1,就賦上(最后一個設(shè)備號+1)new->devnum = last_devnum+1;/所有的設(shè)備號*分區(qū)數(shù) > 256 if (new->devnum << tr->part_bits) > 256) return -EBUSY; init_MUTEX(&new->sem);list_add_tail(&new->list, &tr->devs);/加到鏈表尾部 added:if (!tr->writesect)new->readonly = 1;/分配通知硬盤結(jié)構(gòu)ge

52、ndisk,每分區(qū)一個gd = alloc_disk(1 << tr->part_bits);if (!gd) list_del(&new->list);return -ENOMEM; /初始化通用硬盤結(jié)構(gòu)gd->major = tr->major;gd->first_minor = (new->devnum) << tr->part_bits;gd->fops = &mtd_blktrans_ops;snprintf(gd->disk_name, sizeof(gd->disk_na

53、me),“%s%c”, tr->name, (tr->part_bits?a:0) + new->devnum);snprintf(gd->devfs_name, sizeof(gd->devfs_name),“%s/%c”, tr->name, (tr->part_bits?a:0) + new->devnum); /* 2.5 has capacity in units of 512 bytes while stillhaving BLOCK_SIZE_BITS set to 10. Just to keep us amused.

54、*/set_capacity(gd, (new->size * new->blksize) >> 9);gd->private_data = new; /通用硬盤結(jié)構(gòu)的私有數(shù)據(jù)指向翻譯層的MTD設(shè)備new->blkcore_priv = gd;gd->queue = tr->blkcore_priv->rq; /設(shè)置請求隊(duì)列 if (new->readonly)set_disk_ro(gd, 1);/設(shè)置硬盤讀寫模式add_disk(gd);/加通用硬盤結(jié)構(gòu)到全局鏈表中return 0;MTD塊設(shè)備的讀寫操作 函數(shù)mtdbl

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

56、,unsigned long block, char *buf)/從MTD塊設(shè)備數(shù)組中得到塊設(shè)備結(jié)構(gòu)struct mtdblk_dev *mtdblk = mtdblksdev->devnum;if (unlikely(!mtdblk->cache_data && mtdblk->cache_size) /分配塊設(shè)備用于擦除的緩存空間mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);if (!mtdblk->cache_data)return -EINTR; /從位置bl

57、ock開始寫一個扇區(qū)(512字節(jié))return do_cached_write(mtdblk, block<<9, 512, buf);函數(shù)do_cached_write將數(shù)據(jù)寫入到設(shè)備,由于flash設(shè)備需要先擦除再才能寫入,因而,在數(shù)據(jù)塊大小不是正好扇區(qū)大小,需要通過緩存湊合成一個扇區(qū)時,才能寫入到設(shè)備。函數(shù)do_cached_write分析如下: static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,int len, const char *buf)struct mtd_info *mtd = mtdblk->mtd;/得到擦除緩沖區(qū)大小unsigned int sect_size = mtdblk->cache_size;size_t retlen;int ret; if (!sect_size)/如果塊設(shè)備的緩沖大小為0,直接寫設(shè)備return MTD_

溫馨提示

  • 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)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論