1.Linux 總線模型linux
Linux下的任何驅動在內核中最終都抽象爲bus, driver以及device三者間的相互做用。ios
總線是處理器和一個或多個設備之間的通道,在設備模型中,全部的設備都經過總線相鏈接。總線將設備和驅動綁定,在系統每註冊一個設備的時候,會遍歷該總線上的driver list,經過bus的math函數尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會便利該總線上的device 尋找與之匹配的設備,而匹配由總線的match函數完成。一但匹配,則會調用總線的probe函數。git
在此模型下,若是存在實際總線固然很好,好比mmc總線,i2c總線和spi總線,相應的device和driver均可以直接註冊在總線上。可是老是有一些設備和總線無關,爲此,linux kernel引入了platform 虛擬總線,框架
Platform總線是一種虛擬的總線,相應的設備則爲platform_device,經過platform_driver_register;而驅動則爲platform_driver,經過platform_driver_register 註冊。內核中該總線定義以下:dom
struct bus_type platform_bus_type = {函數
.name = "platform",測試
.dev_groups= platform_dev_groups,fetch
.match = platform_match,spa
.uevent = platform_uevent,.net
.pm = &platform_dev_pm_ops,
};
platform_總線match採用名稱匹 配的方式,即driver和device二者的name同樣則認爲該device對應該driver,詳見下圖:
2.MMC 簡介
MMC
MMC全稱MultiMedia Card,由西門子公司和SanDisk公司1997年推出的多媒體記憶卡標準。MMC卡尺寸爲32mm x24mm x 1.4mm,它將存貯單元和控制器一同作到了卡上,智能的控制器使得MMC保證兼容性和靈活性。
MMC卡具備MMC和SPI兩種工做模式,MMC模式是默認工做模式,具備MMC的所有特性。而SPI模式則是MMC協議的一個子集,主要用於低速系統。
SD
SD卡全稱Secure DigitalMemory Card,由松下、東芝和SanDisk公司於1999年8月共同開發的新一代記憶卡標準,已徹底兼容MMC標準。SD卡比MMC卡多了一個進行數據著做權保護的暗號認證功能。
SD卡尺寸爲32mm x 24mm x2.1mm,長寬和MMC卡同樣,只是比MMC卡厚了0.7mm,以容納更大容量的存貯單元。SD卡與MMC卡保持向上兼容,也就是說,MMC卡能夠被新的設有SD卡插槽的設備存取,可是SD卡卻不能夠被設有MMC插槽的設備存取。
SDIO
SDIO全稱Secure DigitalInput and Output Card,SDIO是在SD標準上定義了一種外設接口,它使用SD的I/O接口來鏈接外圍設備,並經過SD上的I/O數據接口與這些外圍設備傳輸數據。如今已經有不少手持設備支持SDIO功能,並且許多SDIO外設也被開發出來,目前常見的SDIO外設有:WIFI Card、GPS Card、 Bluetooth Card等等。
eMMC
eMMC全稱Embedded MultiMediaCard,是MMC協會所制定的內嵌式存儲器標準規格,主要應用於智能手機和移動嵌入式產品等。eMMC是一種嵌入式非易失性存儲系統,由閃存和閃存控制器兩部分組成,它的一個明顯優點是在封裝中集成了一個閃存控制器,它採用JEDEC標準BGA封裝,並採用統一閃存接口管理閃存。
eMMC結構由一個嵌入式存儲解決方案組成,帶有MMC接口、快閃存儲設備及主控制器,全部這些由一個小型BGA封裝。因爲採用標準封裝,eMMC也很容易升級,並不用改變硬件結構。
eMMC的這種將Nand Flash芯片和控制芯片封裝在一塊兒的設計概念,就是爲了簡化產品內存儲器的使用,客戶只須要採購eMMC芯片放進產品中,不須要處理其它複雜的Nand Flash兼容性和管理問題,減小研發成本和研發週期。
3.MMC 模塊總線模型
mmc子系統涉及到三條總線,以下:
Host驅動相應的driver和device掛載在Linux內核內置的虛擬抽象總線platform_bus_type。二者的匹配採用名稱匹配的方式,即driver和device二者的name同樣則認爲該device對應該driver,這裏是」rda,hsmmc」。
Card驅動相應的driver和device掛載在mmc本身建立的虛擬總線mmc_bus_type下,直接匹配。
Sdio驅動相應的driver和device掛載在mmc本身建立的虛擬總線sdio_bus_type下,ID匹配。
按照時間前後順序,mmc模塊中bus,device和driver的註冊順序以下:
3.1.host device
linux kernel 經過下圖所示流程,解析dts文件mmc模塊相關配置,生成名爲rda,hsmmc的platformdevice,掛在platform平臺總線上。
3.2.mmc_bus, sdio_bus
mmc core初始化時,文件core.c中的subsys_initcall(mmc_init), 調用mmc_register_bus和sdio_register_bus註冊mmc bus 和sdio bus,具體如圖下圖所示。
由上圖能夠看出,任何掛在mmc總線上的device 和driver都會匹配,而掛在sdio總線上的設備和deriver須要經過id進行匹配。
3.3.card driver
card目錄下,block.c中module_init(mmc_blk_init)調用mmc_register_driver函數建立mmcblk driver,並將之掛載到mmc_bus_type總線的driver list鏈表上。
注意:mmc core提供了mmc_test.c做爲mmc driver的測試文件。mmc_test.c中,module_init(mmc_test_init)函數中,調用mmc_register_driver函數建立了mmc_test driver,而且將之掛載在mmc_bus_type總線的driver list鏈表上。
mmc模塊若是須要使用mmc_test功能,須要把CONFIG_MMC_BLOKC宏關閉,而後把CONFIG_MMC_BLOCK=y。不然,card將會匹配blockdreiver,不會再次匹配mmc_test driver,具體見下圖。
3.4.host driver
host目錄下,rda_sgmmc.c文件中,module_init(rda_mmc_init),把rda_mmc_init連接到相應的init字段中。在初始化時候,執行rda_mmc_init(),調用platform_driver_register註冊名爲rda,hsmmc的host driver,此driver掛在platform虛擬總線上。
3.5. card device
在第四步中,hostdriver註冊成功後,platform總線會把此driver和1中註冊的host dev匹配,而後執行host driver的probe 函數rda_mmc_probe。該函數中完成mmc_alloc_host申請mmc host 結構體,而後完成初始化,以及中斷等的申請等,最後調用mmc_add_host完成card 的探測,若是card存在,生成card device。
由於sd卡支持熱插拔,因此在probe階段,sd卡沒有插入的狀況下,不會生成card device。而是在後期插入sd卡時候,產生中斷,中斷處理函數中調用mmc_detect_change函數探測sd card是否存在,完成初始化而且生成card device。具體見下圖。
從上圖中,咱們並無看到card設備的生成。這是由於咱們經過detect work完成了sd,mmc,或sdio設備的初始化,而且生成相應的block設備,具體見下圖:
3.6. card driver執行
在第五步中,card device已經掛到mmc總線上,此時會匹配到carddriver,自動執行driver 的probe函數。若是在3中,CONFIG_MMC_BLOCK=y,則會執行mmc_blk_probe,生成block設備。若是CONFIG_MMC_BLOCK=n, CONFIG_MMC_TEST=y,則會自動執行mmc_test_probe。
綜上所述,設備經過dts文件把mmc host dev(platform設備)掛在虛擬平臺總線上,而後註冊sdio和mmc總線,緊接着註冊card driver,掛在mmc總線上。其後,在host目錄下,咱們本身的driver中,調用platform_driver_register註冊platform平臺驅動,即host driver。此時,platform會匹配host dev 和driver,執行driver的probe函數,經過mmc_add_host註冊card
device,掛載到mmc總線上。最後,mmc總線會匹配card dev 和driver,執行card driver的probe函數,生成block設備或者mmc_test相關的屬性文件。
4.MMC 協議實現
到此爲止,mmc 的相關框架已經介紹清楚了。由於在框架明瞭的狀況下,驅動已經很簡單了,因此後面僅僅會簡單介紹一下mmc驅動。
sd,sdio或者mmc的協議實如今哪裏呢?能夠在圖5中看到,初始化就是在mmc_attach_sdio, mmc_attach_sd或者mmc_attach_mmc函數中。
1.初始化時候,首先發送cmd0使卡進入idle狀態;
2.接着發送cmd8,檢測卡是否SD2.0。SD1.1不支持cmd8,所以若是發送cmd8無迴應,則卡爲SD1.1,不然就是SD2.0;
3. mmc_attach_sdio發送cmd5讀取OCR 寄存器,判斷是否爲sdio,若是是就綁定sdio總線;
4. mmc_attach_sd發送命令acmd5五、cmd41,使卡進入工做狀態。若是經過,則認爲是sd卡,綁定sd總線。mmc卡不支持acmd55,和cmd41,因此若是無迴應,則認爲卡是mmc卡;
5. mmc_attach_mmc中發送命令1,判斷是否爲mmc卡,若是迴應,則綁定mmc總線。若是cmd1無迴應,則不是mmc卡。
具體實現和協議強相關,只要對照協議來看,很簡單,就再也不多述了。
ls kernel/drivers/mmc,能夠看到以下三個目錄:
card core host
card目錄下主要是完成了上章中所述的mmc總線driver,也就是2.3所述的card driver,
core目錄主要是完成了上章中sdio bus和mmc bus註冊,card device的添加,host目錄就是具體的host driver的添加了。
在mmc driver中,須要作的很重要的一部就是實現mmc_host_ops,在probe函數中把其賦值給mmc_host 結構體的ops變量,rda_sgmmc.c的mmc_host_ops實現以下:
static const struct mmc_host_ops rda_mmc_ops= {
.request = rda_mmc_request,
.get_ro = rda_mmc_get_ro,
.get_cd = rda_mmc_get_cd,
.set_ios = rda_mmc_set_ios,
.enable_sdio_irq =rda_mmc_enable_sdio_irq,
};
其中,request函數,主要實現命令發送,數據的讀寫;set_ios主要用來設置數據速度,mmc相位,power mode 和data bus width;get_cd用來檢測設備是否存在;get_ro用來判斷mmc是否爲read-only card;enable_sdio_irq是用來使能或者關閉sdio中斷。
mmc dev正常讀寫的時候調用流程是怎麼樣呢?怎麼和上面註冊的mmc_host_ops關聯起來呢?塊設備的讀寫會被放入request_queue。見下圖:
其中,blk_fetch_request等涉及到block文件的讀寫實現方式,這裏再也不敘述,有興趣的話你們能夠看看代碼。
由此,mmc card dev就和上面註冊的mmc_host_ops關聯起來了。
5.MMC test driver 使用
在第二章介紹card driver時候已經介紹到了mmc test driver了。若是要使用mmc_test function,能夠按照以下步驟:
1.CONFIG_MMC_BLOCK=n,CONFIG_MMC_TEST=y。或者CONFIG_MMC_BLOCK=y, CONFIG_MMC_TEST=y。若是選用後一種配置,須要再系統起來後,在總線driver中手動bind和unbind,見後面;
2.CONFIG_DEBUG_FS=y,CONFIG_DEBUG_KERNEL=y,這兩項在咱們項目的kernel的defconfig中已經配置,因此不須要進行改動;
3. mount -t debugfs none /sys/kernel/debug,這個咱們的project中已經掛載了,不須要進行改動;
完成上面三項後,啓動系統,若是在步驟1中CONFIG_MMC_BLOCK=y,那麼須要先執行執行以下操做:
etau:/ # ls sys/bus/mmc/devices/
mmc0:aaaa
etau:/sys/bus/mmc/drivers # ls
mmc_test/ mmcblk/
etau:/sys/bus/mmc/drivers # cd mmcblk/
etau:/sys/bus/mmc/drivers/mmcblk # ls -al
total 0
drwxr-xr-x 2 root root 0 2000-01-01 01:27 .
drwxr-xr-x 4 root root 0 2000-01-01 01:27 ..
--w------- 1 root root 4096 2000-01-01 01:28bind
lrwxrwxrwx 1 root root 0 2000-01-01 01:28 mmc0:aaaa ->../../../../devices/soc0/20a50000.rda-mmc0/mmc_host/mmc0/mmc0:aaaa
--w------- 1 root root 4096 2000-01-01 01:28uevent
--w------- 1 root root 4096 2000-01-01 01:28unbind
etau:/sys/bus/mmc/drivers/mmcblk #echo –n mmc0:aaaa> unbind
etau:/sys/bus/mmc/drivers # cdmmc_test/
etau:/sys/bus/mmc/drivers/mmc_test # ls
bind uevent unbind
etau:/sys/bus/mmc/drivers/mmc_test #echo –n mmc0:aaaa> bind
完成上述操做後,完成了mmc0:aaaa和mmc_test driver的綁定。後續步驟徹底一致,以下:
etau:/sys/kernel/debug/mmc0/mmc0:aaaa# cat testlist
1: Basic write (no data verification)
2: Basic read (no data verification)
3: Basic write (with data verification)
4: Basic read (with data verification)
5: Multi-block write
6: Multi-block read
7: Power of two block writes
8: Power of two block reads
9: Weird sized block writes
10: Weird sized block reads
11: Badly aligned write
12: Badly aligned read
13: Badly aligned multi-block write
14: Badly aligned multi-block read
15: Correct xfer_size at write (start failure)
16: Correct xfer_size at read (start failure)
17: Correct xfer_size at write (midway failure)
18: Correct xfer_size at read (midway failure)
19: Highmem write
20: Highmem read
21: Multi-block highmem write
22: Multi-block highmem read
23: Best-case read performance
24: Best-case write performance
25: Best-case read performance into scattered pages
26: Best-case write performance from scatteredpages
27: Single read performance by transfer size
28: Single write performance by transfer size
29: Single trim performance by transfer size
30: Consecutive read performance by transfer size
31: Consecutive write performance by transfer size
32: Consecutive trim performance by transfer size
33: Random read performance by transfer size
34: Random write performance by transfer size
35: Large sequential read into scattered pages
36: Large sequential write from scattered pages
37: Write performance with blocking req 4k to 4MB
38: Write performance with non-blocking req 4k to 4MB
39: Read performance with blocking req 4k to 4MB
40: Read performance with non-blocking req 4k to 4MB
41: Write performance blocking req 1 to 512 sg elems
42: Write performance non-blocking req 1 to 512 sg elems
43: Read performance blocking req 1 to 512 sg elems
44: Read performance non-blocking req 1 to 512 sg elems
45: Reset test
而後執行etau:/sys/kernel/debug/mmc0/mmc0:aaaa# echo 1 > test能夠看到測試結果:
[314034.644348] mmc0: Starting tests of cardmmc0:aaaa...
[314034.645080] mmc0: Test case 1. Basicwrite (no data verification)...
[314034.647583] mmc0: Result: OK
[314034.647827] mmc0: Tests completed.
至此,mmc模塊就告一段落了。————————————————版權聲明:本文爲CSDN博主「kivy_xian」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/kivy_xian/article/details/53333831