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

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

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

2、儲管理。 在嵌入設備上的MMC/SD插卡則由MMCBLOCK驅動程序和VFAT文件系統(tǒng)進行存儲管理。本章分析了MTD設備和MMC/SD驅動程序。 Figure 3-1. UBI/MTD Integration 目錄· 1 MTD內(nèi)存技術設備 o 1.1 MTD內(nèi)存技術設備層次結構 o 1.2 設備層和原始設備層的函數(shù)調用關系 o 1.3 MTD相關結構 o 1.4 MTD塊設備初始化 o 1.5 MTD塊設備的讀寫操作 o 1.6 MTD核心初始化 o 1.7 MTD字符設備 o 1.8 具體flash芯片的探測及映射 o 1.9 驅動程序實例分析 · 2 SD/MMC卡塊

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

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

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

6、它提供了基于扇區(qū)的擦除和讀寫操作的更好的接口。MTD子系統(tǒng)支持眾多的閃存設備,并且有越來越多的驅動程序正被添加進來以用于不同的閃存芯片。 MTD子系統(tǒng)提供了對字符設備MTD_CHAR和塊設備MTD_BLOCK的支持。MTD_CHAR提供對閃存的原始字符訪問,象通常的 IDE硬盤一樣,在MTD_BLOCK塊設備上可創(chuàng)建文件系統(tǒng)。MTD_CHAR字符設備文件是 /dev/mtd0、mtd1、mtd2等,MTD_BLOCK塊設備文件是 /dev/mtdblock0、mtdblock1等等。 NAND和NOR是制作Flash的工藝,CFI和JEDEC是flash硬件提供的接口,linux通過這些用通用

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

8、層,按從上到下依次為:設備節(jié)點、MTD設備層、MTD原始設備層和硬件驅動層。MTD中間層層次結構圖如下: 圖1MTD中間層層次結構圖Flash硬件驅動層對應的是不同硬件的驅動程序,它負責驅動具體的硬件。例如:符合CFI接口標準的Flash芯片驅動驅動程序在drivers/mtd/chips目錄中,NAND型Flash的驅動程序在/drivers/mtd/nand中。 在原始設備層中,各種內(nèi)存設備抽象化為原始設備,原始設備實際上是一種塊設備,MTD字符設備的讀寫函數(shù)也調用原始設備的操作函數(shù)來實現(xiàn)。 MTD使用MTD信息結構mtd_info來描述了原始設備的操作函數(shù)、各種信息,所有原始設備的信息也

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

10、ivers/mtd/maps/目錄下的對應文件中。這些映射數(shù)據(jù)包括分區(qū)信息、I/O映射及特定函數(shù)的映射等。這種映射關系用映射信息結構map_info描述。在MTD設備層中,MTD字符設備通過注冊的file operation函數(shù)集來操作設備,而這些函數(shù)是通過原始設備層的操作函數(shù)來實現(xiàn)的,即調用了塊設備的操作函數(shù)。MTD塊設備實際了從塊層到塊設備的接口函數(shù)。所有的塊設備組成一個數(shù)組*mtdblksMAX_MTD_DEVICES,這個結構數(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設備種類的多樣性,MTD用MTD翻譯層將三大類flash設備進行的封裝。每大類設備有自己的操作函數(shù)集,它們的mtdblk_dev結構實例都存在mtdblks數(shù)組中。MTD設備在內(nèi)核中的層次圖如下圖。

12、 圖MTD設備在內(nèi)核中的層次圖MTD原始設備層中封裝了三大類設備,分別是Inverse Flash、NAND Flash和MTD。它們的上體讀寫方法不一樣。這里只分析了MTD,因為它是最常用的。 設備層和原始設備層的函數(shù)調用關系 原始設備層主要是通過mtd_info結構來管理設備,函數(shù)add_mtd_partitions()和del_mtd_partitions() 將的設備分區(qū)的mtd_info結構加入mtd_table數(shù)組中,mtdpart.c中還實現(xiàn)了part_read、part_write等函數(shù),這些函數(shù)注冊在每個分區(qū)中,指向主分區(qū)的read、write函數(shù),之所以這樣做而不直接將主分

13、區(qū)的read、write函數(shù)連接到每個分區(qū)中的原因是因為函數(shù)中的參數(shù)mtd_info會被調用者置為函數(shù)所屬的mtd_info,即mtd->read(mtd),而參數(shù)mtd_info其實應該指向主分區(qū)。 設備層和原始設備層的函數(shù)調用關系圖如圖2。MTD各種結構之間的關系圖如圖3。 圖2設備層和原始設備層的函數(shù)調用關系圖3MTD各種結構之間的關系MTD相關結構 MTD塊設備的結構mtdblk_dev代表了一個閃存塊設備,MTD字符設備沒有相對應的結構。結構mtdblk_dev列出如下: struct mtdblk_dev struct mtd_info mtd; / Locked */下層原

14、始設備層的MTD設備結構int count;struct semaphore cache_sem;unsigned char *cache_data;/緩沖區(qū)數(shù)據(jù)地址unsigned long cache_offset;/在緩沖區(qū)中讀寫位置偏移/緩沖區(qū)中的讀寫數(shù)據(jù)大小(通常被設置為MTD設備的erasesize)unsigned int cache_size;enum STATE_EMPTY, STATE_CLEAN, STATE_DIRTY cache_state;/緩沖區(qū)狀態(tài)結構mtd_info描述了一個MTD原始設備,每個分區(qū)也被實現(xiàn)為一個mtd_info,如果有兩個MTD原始設備,每個

15、上有三個分區(qū),在系統(tǒng)中就一共有6個mtd_info結構,這些mtd_info的指針被存放在名為mtd_table的數(shù)組里。結構mtd_info分析如下: struct mtd_info u_char type;/內(nèi)存技術的類型u_int32_t flags;/標志位u_int32_t size; / mtd設備的大小  /“主要的”erasesize(同一個mtd設備可能有數(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,意味著整個設備為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結構設備層的mtdblcok設備的notifier聲明如下: static struct mtd_notifier notifier = mtd_notify_add,mtd_notify_re

23、move,NULL;mtd_part結構是用于描述MTD原始設備分區(qū)的,結構mtd_part中的list成員鏈成一個鏈表mtd_partitons。每個 mtd_part結構中的mtd_info結構用于描述本分區(qū),被加入mtd_table數(shù)組中,其中mtd_info結構大部分成員由其主分區(qū) mtd_part->master決定,各種函數(shù)也指向主分區(qū)的相應函數(shù)。結構mtd_part列出如下: /* Our partition linked list */static LIST_HEAD(mtd_partitions);MTD原始設備分區(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;結構mtd_partition描述mtd設備分區(qū)的結構,在MTD原始設備層調用函數(shù)add_mtd_partions時傳遞分區(qū)信息使用。結構列出如下(在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ù)init_mtdblock調用層次圖 在具體的設備驅動程序初始化時,它會添加一個MTD設備結構到mtd_table數(shù)組中。MTD翻譯層通過查找這個數(shù)組,可訪問到各個具體設備驅動程序。 函數(shù)init_mtdblock注冊一個MTD翻譯層設備,初始化處理請求的線程,賦上MTD翻譯層設備操作函數(shù)集實例,注冊這個設備的通用硬盤結構。函數(shù)init_mtdblock調用層次圖如上圖。 mtd塊設備驅動程序利用一個線程,當有讀寫請求時,從緩沖區(qū)將數(shù)據(jù)寫入塊設備或從塊設備讀入到緩沖區(qū)中。 函數(shù)init_m

26、tdblock分析如下(在drivers/mtd/mtdblock.c中): static int _init init_mtdblock(void)return register_mtd_blktrans(&mtdblock_tr);MTD翻譯層設備操作函數(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;/如果第一個設備類型被注冊了,注冊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翻譯層塊設備,創(chuàng)建通用硬盤結構并注冊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結構初始化后加到&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)建請求隊列并初始化,賦上塊設備特定的請求處理函數(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ù)集/創(chuàng)建線程mtd_blktrans_threadret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL); /在devfs文件系統(tǒng)中創(chuàng)建設備的目錄名devfs_mk_dir(tr->name);  INIT_LIST_HEAD(&tr->devs);/初始化設備的鏈表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翻譯層設備結構并初始化,然后到MTD設備鏈表中tr->add_mtd(tr, mtd_tablei);  up(&mtd_table_mutex);return 0;函數(shù)mtd_blktrans_request是MTD設備的請求處理函數(shù),當請求隊列中的請求需要設備處理時調用這個函數(shù)。在MTD設備中,函數(shù) mtd_blktrans_request喚醒了MTD塊設備的線程來進行處理。函數(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ù)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為父進程的后臺進程daemonize(“%sd”, tr->name);  /因為一些內(nèi)核線程實際上要與信號打交道,daemonize()沒有做后臺化工作。/我們不能僅調用exit_sighand函數(shù),/因為當最終退出時這樣將可能引起oop(對象指針溢出錯誤)。 spin_loc

35、k_irq(&current->sighand->siglock);sigfillset(&current->blocked);  / 重新分析是否有掛起信號并設置或清除TIF_SIGPENDING標識給當前進程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);/聲明當前進程的等待隊列  req = elv_next_request(rq);/從塊設備的請求隊列中得到下一個請求  if (!req) /如果請求不存在/將設備的等待線程加到等待隊列中add_wait_queue(&tr->blkcore_priv->thread_wq, &wait);set_current_state(TASK_INTERRUPTIBLE);spin_unlock_ir

37、q(rq->queue_lock);schedule();/調度讓CPU有機會執(zhí)行等待的線程remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait);spin_lock_irq(rq->queue_lock);continue;   /如果請求存在dev = req->rq_disk->private_data;/得到請求的設備tr = dev->tr;/得到MTD翻譯層設備操作函數(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); /從請求隊列中刪除請求并更新統(tǒng)計信息spin_unlock_irq(rq->queue_lock);/調用所有請求處理完的回調函數(shù),并調用do_exit函數(shù)退出線程complete_and_exit(&tr->blkcore_priv->thread_dead, 0);函數(shù)do_blktrans_

39、request完成請求的具體操作,它調用MTD翻譯層設備操作函數(shù)集實例中的具體函數(shù)來進行處理。函數(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ù)超出了塊設備的容量,返回if (block + nsect > get_capacity(req->rq_disk)return 0; /根據(jù)(rq)->flags & 1標識來判斷操作方式,調用具體的設備操作函數(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調用層次圖結構mtd_notifier是用于通

42、知加上和去掉MTD原始設備。對于塊設備來說,這個結構實例blktrans_notifier用來通知翻譯層加上和去掉MTD原始設備。結構實例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設備,通過分配通盤硬盤結構來激活每個MTD設備,使其出現(xiàn)在系統(tǒng)中。函數(shù)register_mtd

43、_user調用層次圖如上圖。函數(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塊設備的通知結構實例blktrans_notifier加入/到全局鏈表mtd_notifiers上list_add(&new->list, &mtd_notifiers);/模塊引用計數(shù)加1_module_get

44、(THIS_MODULE); /對每個MTD塊設備調用MTD通知結構實例的加設備函數(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翻譯層將設備加入到鏈表blktrans_majors中,并分配處理每個MTD分區(qū)對應的通用硬盤結構。函數(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)/設備不存在return; /遍歷每個MTD主塊設備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翻譯層塊設備結構,初始化后加到MTD翻譯層塊設備鏈表中,函數(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主設備分配設備號,并加到MTD設備鏈表對應位置上。然后給每個MTD設備分區(qū)分配一個通用硬盤結構,初始化這個通用硬盤結構后,再注冊通用硬盤。這樣通過通用硬盤就可以訪問到每個MTD設

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

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

51、號為-1,就賦上(最后一個設備號+1)new->devnum = last_devnum+1;/所有的設備號*分區(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;/分配通知硬盤結構ge

52、ndisk,每分區(qū)一個gd = alloc_disk(1 << tr->part_bits);if (!gd) list_del(&new->list);return -ENOMEM; /初始化通用硬盤結構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; /通用硬盤結構的私有數(shù)據(jù)指向翻譯層的MTD設備new->blkcore_priv = gd;gd->queue = tr->blkcore_priv->rq; /設置請求隊列 if (new->readonly)set_disk_ro(gd, 1);/設置硬盤讀寫模式add_disk(gd);/加通用硬盤結構到全局鏈表中return 0;MTD塊設備的讀寫操作 函數(shù)mtdbl

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

56、,unsigned long block, char *buf)/從MTD塊設備數(shù)組中得到塊設備結構struct mtdblk_dev *mtdblk = mtdblksdev->devnum;if (unlikely(!mtdblk->cache_data && mtdblk->cache_size) /分配塊設備用于擦除的緩存空間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ù)寫入到設備,由于flash設備需要先擦除再才能寫入,因而,在數(shù)據(jù)塊大小不是正好扇區(qū)大小,需要通過緩存湊合成一個扇區(qū)時,才能寫入到設備。函數(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)/如果塊設備的緩沖大小為0,直接寫設備return MTD_

溫馨提示

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

評論

0/150

提交評論