最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【轉(zhuǎn)】SD3.0協(xié)議解讀

2022-02-09 03:25 作者:失傳技術(shù)電磁所  | 我要投稿

SD3.0協(xié)議解讀一

lwj103862095?

?于?2014-08-06 10:14:33?發(fā)布?

?50487?

?收藏?34

分類專欄:?Linux存儲技術(shù)相關(guān)

版權(quán)

Linux存儲技術(shù)相關(guān)專欄收錄該內(nèi)容

9 篇文章5 訂閱

訂閱專欄

前言:

老衲我近期研究的是SD/MMC卡驅(qū)動,研究過的SD/MMC驅(qū)動的貧僧們都應(yīng)該知道SD/MMC協(xié)議是必不可少的一部分,除非你不想研究透SD/MMC驅(qū)動,那你大可只研究driver/mmc/host目錄下的文件即可。說到SD/MMC協(xié)議,網(wǎng)上一搜,SD3.0的協(xié)議只有英文版的資料,要想真正理解協(xié)議,英文水平差的貧僧就可吃力了,老衲英文水平實(shí)在是一般,但是網(wǎng)上對SD3.0協(xié)議的解讀相關(guān)的中文資料實(shí)在是少的可憐。老衲怒想寫寫對SD3.0協(xié)議的理解,于是這一系列的SD3.0協(xié)議解讀將會陸續(xù)問世.....

系統(tǒng)特征:

卡容量:

1.標(biāo)準(zhǔn)容量卡(SDSC):最大容量為2GB

2.高容量卡(SDHC):容量大小為2~32GB的卡

3.擴(kuò)展容量卡(SDXC):容量大小為32GB~2TB的卡

問:這有什么用呢?在哪里會用到?

答:SD卡一般作為外置擴(kuò)展容量,那么不同用戶用的卡肯定不一樣,那為了區(qū)分不同的卡,SD3.0協(xié)議中在初始化和識別卡的過程中會判斷用戶插入的卡是SDSC/SDHC/SDXC中的哪一種卡,比如在R3中的第38Bit的CCS = 0b時(shí),表示插入的卡為SDSC卡,而CCS = 1b時(shí),表示插入的卡為SDHC或者SDXC卡。不同的卡在Cammand和Response中有微小的區(qū)別,具體用到的時(shí)候再回頭再說。

電壓范圍:

工作電壓范圍為:2.7~3.6V

問:告訴你電壓范圍有什么用呢?

答:卡的工作不是單邊性的,它是和CPU理的卡控制器(host)之間互動的,那么host端也有自己支持的電壓,card端也有自己支持的電壓,而這二者支持的電壓或許不一樣。比如:host支持1.8~3.8V,而card支持2.7~3.6V,而協(xié)議就是完成取交集的作用,幫助host和card協(xié)調(diào)一個(gè)大家都支持的電壓。

卡的屬性:

卡可以設(shè)計(jì)為只讀卡和可讀/可寫的卡

四線總線速率模式:


大家都應(yīng)該看的懂什么意思吧?英文水平不至于比老衲還差吧?實(shí)在太差的就裝個(gè)金山詞霸唄~~這里要解釋二個(gè)縮寫,SDR的意思是Single Data Rate(單邊數(shù)據(jù)采樣,換句話說就是,要么上升沿采樣,要么下降沿采樣),DDR的意思是Double Data Rate(雙邊數(shù)據(jù)采樣,換句話說,雙邊沿采樣)。

注意了,這些總線速率模式是在四線的模式下才支持的,如果是1線的模式下,那可能就不一樣了,而且并不是所有的host都支持所有的模式,比如并不是所有的CPU都支持SDR104模式,這個(gè)需要很強(qiáng)的IO輸入輸出能力,即便你的主頻可以跑1.8GHz,但是到了SD卡這邊的IO可不一定支持208MHz,這個(gè)具體要看CPU的spec。

好了,這篇就寫這么多,注意了,老衲并不是單純的將SD3.0的英文協(xié)議翻譯過來,翻譯只是對英文的解析,這并不是對協(xié)議的理解,這里是解讀協(xié)議!

SD3.0協(xié)議解讀二

lwj103862095?

?于?2014-08-06 13:23:41?發(fā)布?

?32805?

?收藏?15

分類專欄:?Linux存儲技術(shù)相關(guān)

版權(quán)

Linux存儲技術(shù)相關(guān)專欄收錄該內(nèi)容

9 篇文章5 訂閱

訂閱專欄

在閱讀本文章之前,請先思考一下什么是總線,總線的作用是什么?相信大家都學(xué)過I2C總線,它由SCL和SDA兩條線組成,通過這兩條線就能完成各種通信。同樣地,SD卡通信也需要有自己的總線模式。SD卡還比較牛逼,支持SD總線和SPI總線,老衲接觸的比較多的是SD總線,所以這篇文章僅介紹SD總線,對于SPI總線老衲以后有機(jī)會再介紹。

SD總線:


大家都知道總線一般支持多種頻率,在默認(rèn)的頻率下,SD總線支持一(主)對多(從)的模式,即支持一個(gè)HOST對多個(gè)SD卡的模式。但是,在高速和UHS-I,SD總線只能支持一對一的模式,即支持一個(gè)HOST對一個(gè)SD卡的模式。

問:那么對于一對多的模式,總線是如何找到相應(yīng)的SD卡呢?

答:在SD卡初始化識別模式下,通過發(fā)送CMD3來獲取RCA,即卡的邏輯地址,如果卡發(fā)現(xiàn)跟自己的邏輯地址是一致的,就會通過R6來響應(yīng)。

SD總線協(xié)議:

SD總線是基于命令和數(shù)據(jù)的,開始于起始位,結(jié)束于結(jié)束位。Command和Response都是通過CMD線來傳輸?shù)模珼ata是通過數(shù)據(jù)線來傳輸?shù)?。Command都是由主機(jī)(HOST)發(fā)起,Response都是由卡發(fā)出響應(yīng)的。


數(shù)據(jù)的傳輸是以(Block)為單位的,數(shù)據(jù)塊后面帶有CRC校驗(yàn)位,圖3-4描述了單塊和多塊的數(shù)據(jù)傳輸操作,多塊數(shù)據(jù)傳輸通過Stop命令來結(jié)束數(shù)據(jù)傳輸操作。


因?yàn)镠OST的速度總是比SD的速度要快,假如你往卡里面拼命寫數(shù)據(jù),這會出現(xiàn)什么問題?問題可大了,假如SD卡第一次都還沒成功寫完整,你就馬上發(fā)第二次第三次的數(shù)據(jù)過來,那必將會造成數(shù)據(jù)的丟失,對吧。這就引申出了等待機(jī)制。HOST必須等待Card寫完了,你才能繼續(xù)發(fā)第二次數(shù)據(jù)傳輸。

那么,在SD總線的塊寫操作里,是通過Data0的信號狀態(tài)指示卡是否Busy還是Ready的。


Command的內(nèi)部編碼格式:

Command命令都是由48bit組成的,每個(gè)命令的開始都是以'0'開始,以'1'結(jié)束的。每個(gè)命令都包含有CRC校驗(yàn)位,它的作用是,當(dāng)數(shù)據(jù)傳輸發(fā)生錯(cuò)誤時(shí),可以重新重新發(fā)起操作。


Response的內(nèi)部編碼格式:

Response有四種編碼模式,這取決于響應(yīng)內(nèi)容,長度為48bit或者136bit。由圖3-7可知,當(dāng)Response為R1、R3、R6時(shí),響應(yīng)長度為48bit,而Response為R2時(shí),響應(yīng)長度為136bit。并且在CMD線上傳輸都是先發(fā)送MSB,最后發(fā)送LSB,由于Command和Response都是在CMD線上傳輸?shù)?,所以它們都必須按照先發(fā)送MSB,最后發(fā)送LSB。這些規(guī)定都會在驅(qū)動里面被一個(gè)結(jié)構(gòu)體封裝掉,你知道是這么一回事就好了,不用特別在意。



SD卡的數(shù)據(jù)包格式:

1.Usual data (8 bit width):在字節(jié)之間先傳輸?shù)妥止?jié)后傳輸高字節(jié),在字節(jié)里面先傳輸高位后傳輸?shù)臀弧?/p>

2.Wide width data(SD卡寄存器):共有512bit,先傳高位后傳低位。

相應(yīng)的數(shù)據(jù)格式這里就不貼圖了,有興趣的讀者請查閱“Part_1_Physical_Layer_Specification_Ver3.00_Final_090416”的P28和P29,OK,這篇文章暫時(shí)聊到這里,精彩在后面哦。


SD3.0協(xié)議解讀三

lwj103862095?

?于?2014-08-06 15:11:53?發(fā)布?

?49976?

?收藏?28

分類專欄:?Linux存儲技術(shù)相關(guān)

版權(quán)

Linux存儲技術(shù)相關(guān)專欄收錄該內(nèi)容

9 篇文章5 訂閱

訂閱專欄

SD卡功能描述

所有主機(jī)和SD卡間的通信都是由主機(jī)控制的,這和USB是一致的,例如:U盤并沒有主動通知USB控制器的能力,USB鼠標(biāo)也沒有主動通知USB控制器的能力,當(dāng)然,SD卡也是沒有主動通知SD控制器的能力的。

主機(jī)發(fā)送的命令有兩種,一種是一對多,另一種自然是一對一了,他們分別是:

1.廣播命令:廣播命令發(fā)送給所有掛在SD總線上的SD卡,有一些廣播命令需要SD卡作出響應(yīng)。

2.尋址(點(diǎn)對點(diǎn))命令:尋址命令只發(fā)送給具有相應(yīng)地址的卡,并需要找到的那張卡返回一個(gè)響應(yīng)。

SD卡有兩種模式,一種是卡識別模式,另一種是數(shù)據(jù)傳輸模式。

1.卡識別模式:在重置(reset)后,當(dāng)主機(jī)查找總線上的新卡時(shí),處于卡識別模式。重置后SD卡將始終處于該模式下,直到收到SEND_RCA命令(CMD3)。

2.數(shù)據(jù)傳輸模式:當(dāng)卡收到RCA(CMD3)后,卡就會進(jìn)入數(shù)據(jù)傳輸模式。

總的來說,卡二種操作模式,有10種狀態(tài),這兩種操作模式十種狀態(tài)貫穿了整個(gè)協(xié)議的精華,所以我們有必要來認(rèn)識一下。



下面我們將對SD3.0的卡初始化識別模式的流程進(jìn)行翻譯,這段翻譯比較枯燥無味,但是沒辦法,確實(shí)比較復(fù)雜,不仔細(xì)啃啃英文就難以理解這流程是怎么搞的。

卡識別模式:

在卡識別模式,主機(jī)重置所有處于卡識別模式的SD卡,檢驗(yàn)操作電壓范圍,識別卡,并請求卡發(fā)送相對卡地址(RCA)。這些操作都是在各自的CMD線上完成的。在卡識別的過程中,卡的操作頻率應(yīng)該在Fod下。

卡復(fù)位:

發(fā)送GO_IDLE_STATE(CMD0)到SD卡后,除處于非活動狀態(tài)(Inactive state)之外的SD卡都會進(jìn)入空閑狀態(tài)(Idle state);在Idle狀態(tài),SD卡的CMD線處于輸入模式,默認(rèn)相對地址為0x0000,默認(rèn)驅(qū)動寄存器設(shè)定為最低速度,最大驅(qū)動電流能力。

工作條件檢測:

在控制器和SD卡進(jìn)行任何通信之前,控制器不清楚SD卡支持的工作電壓范圍,故而控制器首先使用默認(rèn)的電壓發(fā)送一條reset指令(CMD0),緊跟著的CMD8指令,用于取得SD卡支持工作電壓范圍數(shù)據(jù)。SD卡通過檢測CMD8的參數(shù)部分來檢查控制器使用的工作電壓,控制器通過分析回傳的CMD8參數(shù)部分來校驗(yàn)SD卡是否可以在所給電壓下工作。如果SD卡可以在指定電壓下工作,則它回送CMD8的命令響應(yīng)字,其中包含check voltage, check pattern。如果SD卡不支持所給電壓,則SD卡不會給出任何響應(yīng)信息,并繼續(xù)處于Idle狀態(tài)。在PLV2.0(physical layer version2.0)下,在首次執(zhí)行ACMD41之前,必須執(zhí)行CMD8指令,用以初始化SDHC卡,SDHC卡根據(jù)是否接收到CMD8指令來鑒別控制器是否支持PLV2.0協(xié)議。使用低電壓的控制器也必須在ACMD41命令之前發(fā)送CMD8,避免可以工作在兩種電壓模式下的SD卡因?yàn)闆]有接收到CMD8, 而默認(rèn)工作在高電壓環(huán)境下,被誤認(rèn)為是只支持高電壓工作模式。
SD_SEND_OP_COND(ACMD41)命令的目的是給予SD卡控制器一個(gè)識別SD卡是否可以在所給Vdd范圍下工作的機(jī)制,如果SD卡無法在指定Vdd范圍內(nèi)工作,則它會進(jìn)入非活動狀態(tài)(Inactive state)。要注意的是,ACMD41是應(yīng)用相關(guān)型命令,因而,每次發(fā)出的ACMD41命令都必須緊跟在一條app_CMD(CMD55)命令之后。在空閑態(tài)(Idle State)下使用的CMD55命令使用默認(rèn)的卡相對地址(RCA)0x0000。

卡初始化和識別過程:

SD卡的初始化開始于接收到ACMD41指令之后,ACMD指令的HCS(Host Capacity Support)位如果設(shè)定為1的話,表明控制器支持SDHC卡,否則表示不支持。
在CMD8命令發(fā)送之后的ACMD41指令其功能有所擴(kuò)展,在參數(shù)里多了HCS部分,在響應(yīng)里面多了CCS(Card Capacity Status)部分。HCS參數(shù)會被不響應(yīng)CMD8命令的SD卡所拋棄??刂破飨虿豁憫?yīng)CMD8的卡發(fā)送ACMD41指令時(shí),HCS位應(yīng)該設(shè)置為零0。如果向SDHC卡發(fā)送HCS位為0的ACMD41命令,SDHC卡返回的響應(yīng),其busy標(biāo)識位永遠(yuǎn)為0,代表忙狀態(tài)。HCS標(biāo)識位用來表明SD卡是否已經(jīng)完成初始化,如果未完成,HCS為零,否則為1,如果HCS為0,控制器會重復(fù)發(fā)送ACMD41指令,SD卡只檢查首次接收到的ACMD41指令的HCS位。
響應(yīng)CMD8的SD卡發(fā)送的對于ACMD41指令響應(yīng)會包含CCS部分,控制器只檢查HCS標(biāo)志位為1的響應(yīng)所包含的CCS位。CCS=1表明其為SDHC卡,否則為標(biāo)準(zhǔn)SD卡。
控制器隨后發(fā)送ALL_SEND_CID(CMD2)命令,查詢各個(gè)卡的CID(unique card identification)值,還沒有被識別的SD卡(處于Ready狀態(tài))會發(fā)送CID值作為響應(yīng),發(fā)送完CID值之后,SD卡進(jìn)入識別狀態(tài)(Identification state),然后控制器發(fā)送CMD3(SEND_RELATIVE_ADDR)命令,要求各個(gè)SD卡發(fā)送一個(gè)新的相對地址(RCA),RCA在之后的數(shù)據(jù)傳輸模式中用于尋址。RCA發(fā)送完之后。SD卡進(jìn)入Stand-by狀態(tài),在這個(gè)狀態(tài),如果控制器想要給SD卡分配一個(gè)新的RCA,它可以發(fā)送另一條CMD3命令給SD卡。最后發(fā)布的RCA為SD卡的真實(shí)RCA。

卡的初始化和識別流程具體如下(SD模式):


總結(jié)一下流程:

當(dāng)host上電后,使所有的卡設(shè)備處于卡識別模式,完成設(shè)置有效操作電壓范圍,卡識別和請求卡相對地址等操作。
1、發(fā)送指令CMD0使卡設(shè)備處于idle狀態(tài);

2、發(fā)送指令CMD8,如果卡設(shè)備有response,說明此卡為SD2.0以上;

3、發(fā)送指令CMD55+ACMD41,該指令是用來探測卡設(shè)備的工作電壓是否符合host端的要求;在發(fā)送ACMD41這類指令之前需要先 ? ? ? 發(fā)送CMD55指令,在SDIO中ACMD41指令被CMD5替代。

4、發(fā)送指令CMD11轉(zhuǎn)換工作電壓到1.8V;

5、發(fā)送指令CMD2獲取CID;

6、發(fā)送指令CMD3獲取RCA(relative card address

SD3.0協(xié)議解讀四

lwj103862095?

?于?2014-08-07 10:50:13?發(fā)布?

?25255?

?收藏?9

分類專欄:?Linux存儲技術(shù)相關(guān)

版權(quán)

Linux存儲技術(shù)相關(guān)專欄收錄該內(nèi)容

9 篇文章5 訂閱

訂閱專欄

前面的文章提到過SD卡主要分為兩個(gè)操作模式,一是初始化和識別操作模式,另一種就是這篇文章需要分析的數(shù)據(jù)傳輸模式啦。

數(shù)據(jù)傳輸模式:

數(shù)據(jù)傳輸模式主要有六種狀態(tài),分別是Stand-by狀態(tài)、Transfer狀態(tài)、Sending-data狀態(tài)、Receive-data狀態(tài)、Programming狀態(tài)、Disconnect狀態(tài)。這六種狀態(tài)通過不同的Command就可以切換到某種狀態(tài),換句話說,這六種狀態(tài)貫穿了整個(gè)數(shù)據(jù)傳輸模式。

要理解數(shù)據(jù)傳輸模式的流程,老衲認(rèn)為除了理解這六種狀態(tài),還需要對Commands有一定的了解,越熟悉越好,當(dāng)然,這并不是叫你去背Commands。好了,我們來看看數(shù)據(jù)傳輸模式的流程框圖:

?

老衲我第一次看到這圖的時(shí)候,簡直看暈了,有木有??!太惡心了吧,誰定義的協(xié)議,敢不敢再復(fù)雜一點(diǎn)?沒辦法,做IT的就是苦逼,只能慢慢一點(diǎn)點(diǎn)啃,在理解流程之前,我們必須講協(xié)議里的英文翻譯一遍,然后結(jié)合流程圖理解到底是怎么一回事,最后結(jié)合代碼來看,這才能真正明白數(shù)據(jù)傳輸?shù)倪^程是怎么一回事,下面是對英文協(xié)議里數(shù)據(jù)傳輸模式的翻譯:


數(shù)據(jù)傳輸模式(翻譯):


? 在SD卡識別模式結(jié)束之前,控制器使用的時(shí)鐘頻率均為Fod。在數(shù)據(jù)傳輸模式,控制器可能會使用Fpp頻率??刂破靼l(fā)送一條SSEND_CSD(CMD9)命令來獲取SD卡CSD寄存器(Card?Specific?Data)里面的描述值,譬如,塊長度,卡容量信息等。廣播命令SET_DSR(CMD4)配置所有識別卡的驅(qū)動段。對應(yīng)于應(yīng)用總線LayOut(長度),卡的數(shù)量和數(shù)據(jù)傳輸頻率,這個(gè)命令設(shè)置DSR寄存器。時(shí)鐘頻率在那個(gè)點(diǎn)上也應(yīng)該從Fod切換Fpp。SET_DSR命令對Host和卡都是可選的。


CMD7?用來選擇一個(gè)卡并將它置于傳輸狀態(tài)(Transfer??state),在任何時(shí)間只能有一個(gè)卡處于傳輸狀態(tài)。?如果已有一個(gè)卡處于傳輸狀態(tài),?它和主機(jī)的連接將釋放,并返回到?Stand-by狀態(tài)。當(dāng)?CMD7?以保留相對地址“0x0000”發(fā)送時(shí),所有卡將返回到?Stand-by?狀態(tài)。這可以用來識別新的卡而不重置其他已注冊的卡。?在這種狀態(tài)下已有一個(gè)?RCA?地址的卡不響應(yīng)識別命令(ACMD41,CMD2,CMD3)。

數(shù)據(jù)傳輸模式下各個(gè)狀態(tài)的轉(zhuǎn)換關(guān)系總結(jié)如下:


·所有的數(shù)據(jù)讀命令都可以被停止命令(CMD12)在任意時(shí)刻終止。數(shù)據(jù)傳輸會終止,SD卡返回Transfer狀態(tài)。讀命令有:塊讀操作(CMD17)、多塊讀操作(CMD18)、發(fā)送寫保護(hù)(CMD30)、發(fā)送scr(ACMD51)以及讀模式下的普通命令(CMD56)。

·所有的數(shù)據(jù)寫命令都可以被停止命令(CMD12)在任意時(shí)刻終止。寫命令也會在取消選擇命令(CMD7)之前停止。寫命令有:塊寫操作(CMD24,CMD25)、編程命令(CMD27)、鎖定/解鎖命令(CMD42)以及寫模式下的普通命令(CMD56)。

·數(shù)據(jù)傳輸一旦完成,SD卡會退出數(shù)據(jù)寫狀態(tài),進(jìn)入Programming狀態(tài)(傳輸成功)或者Transfer狀態(tài)(傳輸失敗)如果塊寫操作被叫停,但是寫操作包含的最終塊其長度和CRC校驗(yàn)是正確的話,數(shù)據(jù)會被編程到SD卡(從緩存寫入到Flash)。

·卡可能提供塊寫緩沖。 這意味著在前一塊數(shù)據(jù)被操作時(shí),下一塊數(shù)據(jù)可以傳送給卡。如果所有卡寫緩沖已滿, 只要卡在 Programming State, DAT0 將保持低電平(BUSY)。

·寫CSD、CID、寫保護(hù)和擦除時(shí)沒有緩沖。這表明在卡因這些命令而處于忙時(shí),不再接收其他數(shù)據(jù)傳輸命令。 在卡忙時(shí) DAT0 保持低電平, 并處于 Programming State。實(shí)際上如果 CMD 和 DAT0 線分離,而且主機(jī)占有的忙 DAT0 線和其他 DAT0 線分開,那么在卡忙時(shí),主機(jī)可以訪問其他卡。

·在卡被編程(programming)時(shí),禁止參數(shù)設(shè)置命令。參數(shù)設(shè)置命令包括:設(shè)置塊長度(CMD16),擦除塊開始(CMD32)和擦除塊結(jié)束(CMD33)??ㄔ诓僮鲿r(shí)不允許讀命令。
·使用 CMD7 指令把另一個(gè)卡從 Stand-by 狀態(tài)轉(zhuǎn)移到 Transfer 狀態(tài)不會中止擦除和編程(programming)操作??▽⑶袚Q到 Disconnect 狀態(tài)并釋放 DAT 線。
·使用 CMD7 指令可以不選中處于 Disconnect 狀態(tài)的卡??▽⑦M(jìn)入 Programming 狀態(tài),重新激活忙指示。
·使用 CMD0 或 CMD15 重置卡將中止所有掛起和活動的編程(programming)操作。這可能會破壞卡上的數(shù)據(jù)內(nèi)容,需要主機(jī)保證避免這樣的操作。CMD34-37 CMD50,CMD57保留。


看起來是挺暈的對吧,確實(shí)挺暈的,最好的辦法就是結(jié)合代碼去分析讀寫過程了,這個(gè)嘛,后面有機(jī)會再詳細(xì)分析。)

好了,這篇文章就聊到這里,是否對SD卡的初始化和識別過程有了更清晰的了解呢?這只是協(xié)議上的流程,具體的代碼實(shí)現(xiàn)我們后面再慢慢分析,千萬不能急呀~~

SD/MMC/SDIO基礎(chǔ)概念的介紹

lwj103862095?

?于?2014-08-01 14:01:30?發(fā)布?

?58070?

?收藏?36

分類專欄:?Linux存儲技術(shù)相關(guān)

版權(quán)

Linux存儲技術(shù)相關(guān)專欄收錄該內(nèi)容

9 篇文章5 訂閱

訂閱專欄

以下內(nèi)容大多摘自網(wǎng)絡(luò),自己看了覺的不錯(cuò),自己整理了一番。

1.1.什么是MMC卡

MMC:MMC就是MultiMediaCard的縮寫,即多媒體卡。它是一種非易失性存儲器件,體積小巧(24mm*32mm*1.4mm),容量大,耗電量低,傳輸速度快,廣泛應(yīng)用于消費(fèi)類電子產(chǎn)品中。

1.2.什么是SD卡

SD:SD卡為Secure Digital Memory Card,?即安全數(shù)碼卡。它在MMC的基礎(chǔ)上發(fā)展而來,增加了兩個(gè)主要特色:SD卡強(qiáng)調(diào)數(shù)據(jù)的安全安全,可以設(shè)定所儲存的?
使用權(quán)限,防止數(shù)據(jù)被他人復(fù)制;另外一個(gè)特色就是傳輸速度比2.11版的MMC卡快。在數(shù)據(jù)傳輸和物理規(guī)范上,SD卡(24mm*32mm*2.1mm,比MMC卡更厚一點(diǎn)),向前兼容了MMC卡.所有支持SD卡的設(shè)備也支持MMC卡。SD卡和2.11版的MMC卡完全兼容。

1.3.什么是SDIO

SDIO:SDIO是在SD標(biāo)準(zhǔn)上定義了一種外設(shè)接口,它和SD卡規(guī)范間的一個(gè)重要區(qū)別是增加了低速標(biāo)準(zhǔn)。在SDIO卡只需要SPI和1位SD傳輸模式。低速卡的目標(biāo)應(yīng)用是以最小的硬件開銷支持低速IO能力。


現(xiàn)在已經(jīng)有非常多的手機(jī)或是手持裝置都支持?SDIO?的功能(SD?標(biāo)準(zhǔn)原本就是針對?mobile device?而制定),而且許多?SDIO?外圍也都被開發(fā)出來,讓手機(jī)外接外圍更加容易,并且開發(fā)上更有彈性(不需要內(nèi)建外圍)。目前常見的?SDIO?外圍(SDIO?卡)有:

· Wi-Fi card(無線網(wǎng)絡(luò)卡)?

· CMOS sensor card(照相模塊)?

· GPS card?

· GSM/GPRS modem card?

· Bluetooth card?

· ?Radio/TV card(很好玩)

SDIO?的應(yīng)用將是未來嵌入式系統(tǒng)最重要的接口技術(shù)之一,并且也會取代目前?GPIO?式的?SPI?接口。

1.4.什么是MCI

MCI:MCI是Multimedia Card Interface的簡稱,即多媒體卡接口。上述的MMC,SD,SDI卡定義的接口都屬于MCI接口。MCI這個(gè)術(shù)語在驅(qū)動程序中經(jīng)常使用,很多文件,函數(shù)名字都包括”mci”.

1.5.MMC/SD/SDIO卡的區(qū)別


1.5.SD/SDIO?的傳輸模式

SD?傳輸模式有以下?3?種:

· SPI mode(required)?

· 1-bit mode?

· 4-bit mode

SDIO?同樣也支持以上?3?種傳輸模式。依據(jù)?SD?標(biāo)準(zhǔn),所有的?SD(記憶卡)與?SDIO(外圍)都必須支持?SPI mode,因此?SPI mode?是「required」。此外,早期的?MMC?卡(使用?SPI?傳輸)也能接到?SD?插糟(SD slot),并且使用?SPI mode?或?1-bit mode?來讀取。


Secure digital I/Ocard,pin out

?


SD與MMC的區(qū)別

lwj103862095?

?于?2014-08-01 13:05:45?發(fā)布?

?32547?

?收藏?4

分類專欄:?Linux存儲技術(shù)相關(guān)

版權(quán)

Linux存儲技術(shù)相關(guān)專欄收錄該內(nèi)容

9 篇文章5 訂閱

訂閱專欄

該文章轉(zhuǎn)自:http://www.imhan.com/archives/12/

經(jīng)??吹絊D/MMC這樣的寫法,在這里稍微總結(jié)一下SD卡和MMC卡的異同點(diǎn)吧。

首先,兩者在外型的規(guī)格上是幾乎一致的。而且兩都的接口是兼容的。也就是說,兩者可以用同一個(gè)卡座來進(jìn)行讀取。而且,兩者在時(shí)序上也是一致的,讀寫命令控制也完全一樣,這就是為什么經(jīng)常把兩者混在一起寫的原因。

不過,雖說外型幾乎一致,但還是有點(diǎn)差異的。MMC比SD卡要薄一些,并且,長度只有SD卡的一半。下面從主機(jī)驅(qū)動方面談?wù)剝烧叩牟町悺?/p>

一。在數(shù)據(jù)位寬方面,MMC卡最大支持8BIT,而SD卡只能支持4BIT傳輸。

二、在卡的激活過程,MMC使用CMD1來進(jìn)行激活,而SD卡使用ACMD41來進(jìn)行激活的。于是,這兩條命令也成了主機(jī)區(qū)分兩種卡的類型的關(guān)鍵。在獲取卡的RCA地址時(shí),MMC卡是由主機(jī)分配RCA給設(shè)備,而SD卡則是由設(shè)備返回RCA給主機(jī)。

三、在CMD6的使用方法上也有很大不同。MMC有EXT_CSD的概念,主要用CMD8進(jìn)行讀取,CMD6進(jìn)行設(shè)置。而SD卡則只用CMD6進(jìn)行UserFunction的設(shè)置。SD卡的CMD8主要用于區(qū)別SD1.0和SD2.0。

四、MMC還支持CMD14和CMD19進(jìn)行主線測試,從而選擇合適總線進(jìn)行通信。SD則不支持。另外,MMC卡還支持CMD11、CMD20這類數(shù)據(jù)流操作,因此較多用于媒體設(shè)備上。MMC還支持Boot等高級的用法。


SD/MMC的Commands和Responses的總結(jié)

lwj103862095?

?于?2014-08-01 17:35:02?發(fā)布?

?22595?

?收藏?2

分類專欄:?Linux存儲技術(shù)相關(guān)

版權(quán)

Linux存儲技術(shù)相關(guān)專欄收錄該內(nèi)容

9 篇文章5 訂閱

訂閱專欄

SD總線通信是基于指令和數(shù)據(jù)比特流,起始位開始和停止位結(jié)束。SD總線通信有三個(gè)元素:
1.Command:由host發(fā)送到卡設(shè)備,使用CMD線發(fā)送;

2.Response:從card端發(fā)送到host端,作為對前一個(gè)CMD的相應(yīng),通過CMD線發(fā)送;

3.Data:即能從host傳輸?shù)絚ard,也能從card傳輸?shù)絟ost,通過data線傳輸。

一、Commands
以下是四種用于控制卡設(shè)備的指令類型,每個(gè)command都是固定的48位長度:
1、broadcast commands(bc), no response:廣播類型的指令,不需要有響應(yīng);
2、broadcast commands with response(bcr):廣播類型的指令且需要響應(yīng);
3、addressed(point-to-point) commands(ac):由HOST發(fā)送到指定的卡設(shè)備,沒有數(shù)據(jù)的傳輸;
4、address(point-to-point) data transfercommands(adtc):由HOST發(fā)送到指定的卡設(shè)備且伴隨有數(shù)據(jù)傳輸。

Command format如下:


Byte1:0 1 x x x x x x(命令號,由指令標(biāo)志定義CMD39為100111即16進(jìn)制0x27,那么完整的CMD39第一字節(jié)為01100111,即0x27+0x40)。
Byte2-5:Command Arguments,命令參數(shù),有些命令沒有參數(shù)。
Byte6:前7位為CRC(Cyclic Redundacy Check,循環(huán)冗余校驗(yàn))校驗(yàn)位,最后一位為停止位0。

其中bit[45:40]共6bit組成了Command index,換句話說,總共有2^6次方(64)個(gè)CMD,這些CMD伴隨在卡的初始化、識別、讀寫、擦除數(shù)據(jù)都會用到。

關(guān)于命令的詳細(xì)描述參考《Part_1_Physical_Layer_Specification_Ver3.00_Final_090416》的4.7.4 Detailed Command Description,在P88可以找到相應(yīng)的CMD的詳細(xì)介紹。

二、Responses
所有的response都通過CMD線發(fā)送到host端,R4和R5響應(yīng)類型是SDIO中特有的:
1、R1(normal response command):用來響應(yīng)常用指令;
2、R2(CID,CSD register):用來響應(yīng)CMD2和CMD10或CMD9,并把CID或CSD寄存器作為響應(yīng)數(shù)據(jù);
3、R3(OCR register):用來響應(yīng)ACMD41指令,并把OCR寄存器作為響應(yīng)數(shù)據(jù);
4、R6(published RCA response):分配相對卡地址的響應(yīng);
5、R7(card interface condition):響應(yīng)CMD8,返回卡支持的電壓信息;
6、R4(CMD5):響應(yīng)CMD5,并把OCR寄存器作為響應(yīng)數(shù)據(jù);
7、R5(CMD52):CMD52是一個(gè)讀寫寄存器的指令,R5用于CMD52的響應(yīng);

Response的格式如下:


關(guān)于響應(yīng)的詳細(xì)描述參考《Part_1_Physical_Layer_Specification_Ver3.00_Final_090416》的4.9 Responses 在P98可以找到相應(yīng)的Responses的詳細(xì)介紹。


SD/MMC相關(guān)寄存器的介紹

lwj103862095?

?于?2014-08-01 15:15:54?發(fā)布?

?38862?

?收藏?12

分類專欄:?Linux存儲技術(shù)相關(guān)

版權(quán)

Linux存儲技術(shù)相關(guān)專欄收錄該內(nèi)容

9 篇文章5 訂閱

訂閱專欄

熟悉SD/MMC的相關(guān)寄存器對協(xié)議的理解有一定的輔助作用,所以這篇文章來介紹一下SD/MMC相關(guān)的寄存器有哪些呢?

1.SD卡內(nèi)部架構(gòu)

在熟悉SD/MMC相關(guān)寄存器之前,我們先來看看SD卡的內(nèi)部架構(gòu)是怎么樣的,如下圖所示:


2.SD/MMC相關(guān)寄存器的介紹


從上圖中總結(jié)出:SD卡內(nèi)部有7個(gè)寄存器.

一、OCR,CID,CSD和SCR寄存器保存卡的配置信息;

二、RCA寄存器保存著通信過程中卡當(dāng)前暫時(shí)分配的地址(只適合SD模式);

三、CSR寄存器卡狀態(tài)(Card Status)和SSR寄存器SD狀態(tài)(SD Status)寄存器保存著卡的狀態(tài)(例如,是否寫成功,通信的CRC校驗(yàn)是否正確等),這兩個(gè)寄存器的內(nèi)容與通信模式(SD模式或SPI模式)相關(guān).

四、MMC卡沒有SCR和SSR寄存器.

下面分別對7個(gè)寄存器中比較重要的寄存器詳細(xì)解釋一下,分別是CID、CSD、SCR、OCR、RCA這5個(gè)寄存器。

2.1.?Card Identification Register(CID)

這個(gè) CID 寄存器有 16 字節(jié)長,如下表所示,它包含了本卡的特別識別碼(ID 號)。 這些信息是在卡的生產(chǎn)期間被編程(燒錄),主控制器不 能修改它們的內(nèi)容。 注意:SD卡的 CID 寄存器和 MMC 卡的 CID 寄存器在記錄結(jié)構(gòu)上是不同的。


2.2.Card Specific Data Register(CSD)


這個(gè)描述數(shù)據(jù)寄存器(CSD)有 128 字節(jié)長,如下表所示,此卡的包含了訪問該卡數(shù)據(jù)時(shí)的必要配置信息?!癱ell type”欄內(nèi)定義了CSD的區(qū)域是只讀(R)、一次編程(R/W)或可擦除的(R/W/E)[“R/W”是指可以多次擦寫,“R/W(1)”是指只能一次寫入,不可擦除]。該張表中所顯示的值都對應(yīng)真實(shí)的CSD結(jié)構(gòu)中的各自區(qū)域和編碼。CSD區(qū)域的樣式是依照欄標(biāo)記(和一個(gè)復(fù)選標(biāo)記√)的樣式。注意SD卡內(nèi)的 CSD寄存器和MultiMedia卡的CSD寄存器有著不同的結(jié)構(gòu)。

在SD3.0協(xié)議中,CSD分為版本1.0和版本2.0,版本1.0對應(yīng)標(biāo)準(zhǔn)容量的SD卡,版本2.0對應(yīng)高容量和超高容量的SD卡。



CSD Version 2.0的如下:


2.3.SD card Configuration Register (SCR)

除了 CSD 寄存器外,還有一個(gè)配置寄存器的名字是:SD 卡配置寄存器(SCR)。SCR 提供了SD 卡的一些特殊特性在這張卡內(nèi)。它的大小是64 位。這個(gè)寄存器內(nèi)容由制造商在生產(chǎn)廠內(nèi)設(shè)置,MMC卡沒有SCR。


SCR_STRUCTURE?關(guān)于SD卡內(nèi)的物理級說明中SCR結(jié)構(gòu)的版本號。

SD_SPEC描述這張SD卡在物理級上所支持的說明版本。

DATA_STAT_AFTER_ERASE?定義了數(shù)據(jù)在擦除后的狀態(tài)。是“0”或“1”中的任何一個(gè)(這要依賴卡的供應(yīng)商)。

SD_SECURITY?描述了該卡所支持的安全算法。0:無 1:安全協(xié)議1.0 安全說明版本 0.96 2:安全協(xié)議2.0 安全說明版本 1.0 - 1.01。其他保留

SD_BUS_WIDTHS描述該卡所支持的所有數(shù)據(jù)總線寬度。從SD 卡支持最少1 位或4 位寬度這兩種總線模式開始,任何SD 卡都將最少要設(shè)置0 和2 這兩個(gè)位(即SD_BUS_WIDTH = 0101 ),1.4位保留。

2.4.Operating Conditions Register (OCR)

這個(gè) 32 位的工作條件寄存器儲存了卡的 VDD 電壓輪廓圖。任何標(biāo)準(zhǔn)的 SD 卡主控制器可以使用 2V 至 3.6V 的工作電壓來讓 SD 卡能執(zhí)行這個(gè)電壓識別操作(CMD1)。而訪問存儲器的陣列操作無論如何都需要 2.7V 至 3.6V 的工作電壓。OCR 寄存器顯示了在訪問卡的數(shù)據(jù)時(shí)所需要的電壓范圍。OCR 寄存器的結(jié)構(gòu)描述:


2.5.RCA寄存器
該16位卡地址寄存器保存了在卡識別過程中卡發(fā)布的器件地址。該地址用于在卡識別后主機(jī)利用該地址與卡進(jìn)行通信。該寄存器只有在SD總線模式下才有效。

Read 系統(tǒng)調(diào)用在用戶空間中的處理過程

Linux?系統(tǒng)調(diào)用(SCI,system call interface)的實(shí)現(xiàn)機(jī)制實(shí)際上是一個(gè)多路匯聚以及分解的過程,該匯聚點(diǎn)就是 0x80 中斷這個(gè)入口點(diǎn)(X86 系統(tǒng)結(jié)構(gòu))。也就是說,所有系統(tǒng)調(diào)用都從用戶空間中匯聚到 0x80 中斷點(diǎn),同時(shí)保存具體的系統(tǒng)調(diào)用號。當(dāng) 0x80 中斷處理程序運(yùn)行時(shí),將根據(jù)系統(tǒng)調(diào)用號對不同的系統(tǒng)調(diào)用分別處理(調(diào)用不同的內(nèi)核函數(shù)處理)。系統(tǒng)調(diào)用的更多內(nèi)容,請參見參考資料。

Read 系統(tǒng)調(diào)用也不例外,當(dāng)調(diào)用發(fā)生時(shí),庫函數(shù)在保存 read 系統(tǒng)調(diào)用號以及參數(shù)后,陷入 0x80 中斷。這時(shí)庫函數(shù)工作結(jié)束。Read 系統(tǒng)調(diào)用在用戶空間中的處理也就完成了。

回頁首

Read 系統(tǒng)調(diào)用在核心空間中的處理過程

0x80 中斷處理程序接管執(zhí)行后,先檢察其系統(tǒng)調(diào)用號,然后根據(jù)系統(tǒng)調(diào)用號查找系統(tǒng)調(diào)用表,并從系統(tǒng)調(diào)用表中得到處理 read 系統(tǒng)調(diào)用的內(nèi)核函數(shù) sys_read ,最后傳遞參數(shù)并運(yùn)行 sys_read 函數(shù)。至此,內(nèi)核真正開始處理 read 系統(tǒng)調(diào)用(sys_read 是 read 系統(tǒng)調(diào)用的內(nèi)核入口)。

在講解 read 系統(tǒng)調(diào)用在核心空間中的處理部分中,首先介紹了內(nèi)核處理磁盤請求的層次模型,然后再按該層次模型從上到下的順序依次介紹磁盤讀請求在各層的處理過程。

Read 系統(tǒng)調(diào)用在核心空間中處理的層次模型

圖1顯示了 read 系統(tǒng)調(diào)用在核心空間中所要經(jīng)歷的層次模型。從圖中看出:對于磁盤的一次讀請求,首先經(jīng)過虛擬文件系統(tǒng)層(vfs layer),其次是具體的文件系統(tǒng)層(例如 ext2),接下來是 cache 層(page cache 層)、通用塊層(generic block layer)、IO 調(diào)度層(I/O scheduler layer)、塊設(shè)備驅(qū)動層(block device driver layer),最后是物理塊設(shè)備層(block device layer)


圖1 read 系統(tǒng)調(diào)用在核心空間中的處理層次
?

  • 虛擬文件系統(tǒng)層的作用:屏蔽下層具體文件系統(tǒng)操作的差異,為上層的操作提供一個(gè)統(tǒng)一的接口。正是因?yàn)橛辛诉@個(gè)層次,所以可以把設(shè)備抽象成文件,使得操作設(shè)備就像操作文件一樣簡單。

  • 在具體的文件系統(tǒng)層中,不同的文件系統(tǒng)(例如 ext2 和 NTFS)具體的操作過程也是不同的。每種文件系統(tǒng)定義了自己的操作集合。關(guān)于文件系統(tǒng)的更多內(nèi)容,請參見參考資料。

  • 引入 cache 層的目的是為了提高 linux 操作系統(tǒng)對磁盤訪問的性能。 Cache 層在內(nèi)存中緩存了磁盤上的部分?jǐn)?shù)據(jù)。當(dāng)數(shù)據(jù)的請求到達(dá)時(shí),如果在 cache 中存在該數(shù)據(jù)且是最新的,則直接將數(shù)據(jù)傳遞給用戶程序,免除了對底層磁盤的操作,提高了性能。

  • 通用塊層的主要工作是:接收上層發(fā)出的磁盤請求,并最終發(fā)出 IO 請求。該層隱藏了底層硬件塊設(shè)備的特性,為塊設(shè)備提供了一個(gè)通用的抽象視圖。

  • IO 調(diào)度層的功能:接收通用塊層發(fā)出的 IO 請求,緩存請求并試圖合并相鄰的請求(如果這兩個(gè)請求的數(shù)據(jù)在磁盤上是相鄰的)。并根據(jù)設(shè)置好的調(diào)度算法,回調(diào)驅(qū)動層提供的請求處理函數(shù),以處理具體的 IO 請求。

  • 驅(qū)動層中的驅(qū)動程序?qū)?yīng)具體的物理塊設(shè)備。它從上層中取出 IO 請求,并根據(jù)該 IO 請求中指定的信息,通過向具體塊設(shè)備的設(shè)備控制器發(fā)送命令的方式,來操縱設(shè)備傳輸數(shù)據(jù)。

  • 設(shè)備層中都是具體的物理設(shè)備。定義了操作具體設(shè)備的規(guī)范。

相關(guān)的內(nèi)核數(shù)據(jù)結(jié)構(gòu):

  • Dentry : 聯(lián)系了文件名和文件的 i 節(jié)點(diǎn)

  • inode : 文件 i 節(jié)點(diǎn),保存文件標(biāo)識、權(quán)限和內(nèi)容等信息

  • file : 保存文件的相關(guān)信息和各種操作文件的函數(shù)指針集合

  • file_operations :操作文件的函數(shù)接口集合

  • address_space :描述文件的 page cache 結(jié)構(gòu)以及相關(guān)信息,并包含有操作 page cache 的函數(shù)指針集合

  • address_space_operations :操作 page cache 的函數(shù)接口集合

  • bio : IO 請求的描述

數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系:

圖2示意性地展示了上述各個(gè)數(shù)據(jù)結(jié)構(gòu)(除了 bio)之間的關(guān)系??梢钥闯觯河?dentry 對象可以找到 inode 對象,從 inode 對象中可以取出 address_space 對象,再由 address_space 對象找到 address_space_operations 對象。

File 對象可以根據(jù)當(dāng)前進(jìn)程描述符中提供的信息取得,進(jìn)而可以找到 dentry 對象、 address_space 對象和 file_operations 對象。


圖2 數(shù)據(jù)結(jié)構(gòu)關(guān)系圖:
?

前提條件:

對于具體的一次 read 調(diào)用,內(nèi)核中可能遇到的處理情況很多。這里舉例其中的一種情況:

  • 要讀取的文件已經(jīng)存在

  • 文件經(jīng)過 page cache

  • 要讀的是普通文件

  • 磁盤上文件系統(tǒng)為 ext2 文件系統(tǒng),有關(guān) ext2 文件系統(tǒng)的相關(guān)內(nèi)容,參見參考資料

準(zhǔn)備:

注:所有清單中代碼均來自 linux2.6.11 內(nèi)核原代碼

讀數(shù)據(jù)之前,必須先打開文件。處理 open 系統(tǒng)調(diào)用的內(nèi)核函數(shù)為 sys_open 。?
所以我們先來看一下該函數(shù)都作了哪些事。清單1顯示了 sys_open 的代碼(省略了部分內(nèi)容,以后的程序清單同樣方式處理)


清單1 sys_open 函數(shù)代碼

? ? ? ? ? ? ? ?asmlinkage long sys_open(const char __user * filename, int flags, int mode) { …… fd = get_unused_fd(); if (fd >= 0) { struct file *f = filp_open(tmp, flags, mode); fd_install(fd, f); } …… return fd; …… }

?

代碼解釋:

  • get_unuesed_fd() :取回一個(gè)未被使用的文件描述符(每次都會選取最小的未被使用的文件描述符)。

  • filp_open() :調(diào)用 open_namei() 函數(shù)取出和該文件相關(guān)的 dentry 和 inode (因?yàn)榍疤嶂该髁宋募呀?jīng)存在,所以 dentry 和 inode 能夠查找到,不用創(chuàng)建),然后調(diào)用 dentry_open() 函數(shù)創(chuàng)建新的 file 對象,并用 dentry 和 inode 中的信息初始化 file 對象(文件當(dāng)前的讀寫位置在 file 對象中保存)。注意到 dentry_open() 中有一條語句:

f->f_op = fops_get(inode->i_fop);

這個(gè)賦值語句把和具體文件系統(tǒng)相關(guān)的,操作文件的函數(shù)指針集合賦給了 file 對象的 f _op 變量(這個(gè)指針集合是保存在 inode 對象中的),在接下來的 sys_read 函數(shù)中將會調(diào)用 file->f_op 中的成員 read 。

  • fd_install() :以文件描述符為索引,關(guān)聯(lián)當(dāng)前進(jìn)程描述符和上述的 file 對象,為之后的 read 和 write 等操作作準(zhǔn)備。

  • 函數(shù)最后返回該文件描述符。

圖3顯示了 sys_open 函數(shù)返回后, file 對象和當(dāng)前進(jìn)程描述符之間的關(guān)聯(lián)關(guān)系,以及 file 對象中操作文件的函數(shù)指針集合的來源(inode 對象中的成員 i_fop)。


圖3 file 對象和當(dāng)前進(jìn)程描述符之間的關(guān)系
?

到此為止,所有的準(zhǔn)備工作已經(jīng)全部結(jié)束了,下面開始介紹 read 系統(tǒng)調(diào)用在圖1所示的各個(gè)層次中的處理過程。

虛擬文件系統(tǒng)層的處理:

內(nèi)核函數(shù) sys_read() 是 read 系統(tǒng)調(diào)用在該層的入口點(diǎn),清單2顯示了該函數(shù)的代碼。


清單2 sys_read 函數(shù)的代碼

? ? ? ? ? ? ? ?asmlinkage ssize_t sys_read(unsigned int fd, char __user * buf, size_t count) { struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } return ret; }

?

代碼解析:

  • fget_light() :根據(jù) fd 指定的索引,從當(dāng)前進(jìn)程描述符中取出相應(yīng)的 file 對象(見圖3)。

  • 如果沒找到指定的 file 對象,則返回錯(cuò)誤

  • 如果找到了指定的 file 對象:

  • 調(diào)用 file_pos_read() 函數(shù)取出此次讀寫文件的當(dāng)前位置。

  • 調(diào)用 vfs_read() 執(zhí)行文件讀取操作,而這個(gè)函數(shù)最終調(diào)用 file->f_op.read() 指向的函數(shù),代碼如下:

if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);

  • 調(diào)用 file_pos_write() 更新文件的當(dāng)前讀寫位置。

  • 調(diào)用 fput_light() 更新文件的引用計(jì)數(shù)。

  • 最后返回讀取數(shù)據(jù)的字節(jié)數(shù)。

到此,虛擬文件系統(tǒng)層所做的處理就完成了,控制權(quán)交給了 ext2 文件系統(tǒng)層。

在解析 ext2 文件系統(tǒng)層的操作之前,先讓我們看一下 file 對象中 read 指針來源。

File 對象中 read 函數(shù)指針的來源:

從前面對 sys_open 內(nèi)核函數(shù)的分析來看, file->f_op 來自于 inode->i_fop 。那么 inode->i_fop 來自于哪里呢?在初始化 inode 對象時(shí)賦予的。見清單3。


清單3 ext2_read_inode() 函數(shù)部分代碼

? ? ? ? ? ? ? ?void ext2_read_inode (struct inode * inode) { …… if (S_ISREG(inode->i_mode)) { inode->i_op = &ext2_file_inode_operations; inode->i_fop = &ext2_file_operations; if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else inode->i_mapping->a_ops = &ext2_aops; } …… }

?

從代碼中可以看出,如果該 inode 所關(guān)聯(lián)的文件是普通文件,則將變量 ext2_file_operations 的地址賦予 inode 對象的 i_fop 成員。所以可以知道: inode->i_fop.read 函數(shù)指針?biāo)赶虻暮瘮?shù)為 ext2_file_operations 變量的成員 read 所指向的函數(shù)。下面來看一下 ext2_file_operations 變量的初始化過程,如清單4。


清單4 ext2_file_operations 的初始化

? ? ? ? ? ? ? ?struct file_operations ext2_file_operations = { .llseek = generic_file_llseek, ? ?.read ? ? ? ?= generic_file_read, ? ?.write ? ? ? = generic_file_write, ? ?.aio_read ? = generic_file_aio_read, ? ?.aio_write = generic_file_aio_write, ? ?.ioctl ? ? ? = ext2_ioctl, ? ?.mmap ? ? ? ?= generic_file_mmap, ? ?.open ? ? ? ?= generic_file_open, ? ?.release ? ? = ext2_release_file, ? ?.fsync ? ? ? = ext2_sync_file, ? ?.readv ? ? ? = generic_file_readv, ? ?.writev ? ? ?= generic_file_writev, ? ?.sendfile ? ?= generic_file_sendfile, };

?

該成員 read 指向函數(shù) generic_file_read 。所以, inode->i_fop.read 指向 generic_file_read 函數(shù),進(jìn)而 file->f_op.read 指向 generic_file_read 函數(shù)。最終得出結(jié)論: generic_file_read 函數(shù)才是 ext2 層的真實(shí)入口。

Ext2 文件系統(tǒng)層的處理


圖4 read 系統(tǒng)調(diào)用在 ext2 層中處理時(shí)函數(shù)調(diào)用關(guān)系
?

由圖 4 可知,該層入口函數(shù) generic_file_read 調(diào)用函數(shù) __generic_file_aio_read ,后者判斷本次讀請求的訪問方式,如果是直接 io (filp->f_flags 被設(shè)置了 O_DIRECT 標(biāo)志,即不經(jīng)過 cache)的方式,則調(diào)用 generic_file_direct_IO 函數(shù);如果是 page cache 的方式,則調(diào)用 do_generic_file_read 函數(shù)。函數(shù) do_generic_file_read 僅僅是一個(gè)包裝函數(shù),它又調(diào)用 do_generic_mapping_read 函數(shù)。

在講解 do_generic_mapping_read 函數(shù)都作了哪些工作之前,我們再來看一下文件在內(nèi)存中的緩存區(qū)域是被怎么組織起來的。

文件的 page cache 結(jié)構(gòu)

圖5顯示了一個(gè)文件的 page cache 結(jié)構(gòu)。文件被分割為一個(gè)個(gè)以 page 大小為單元的數(shù)據(jù)塊,這些數(shù)據(jù)塊(頁)被組織成一個(gè)多叉樹(稱為 radix 樹)。樹中所有葉子節(jié)點(diǎn)為一個(gè)個(gè)頁幀結(jié)構(gòu)(struct page),表示了用于緩存該文件的每一個(gè)頁。在葉子層最左端的第一個(gè)頁保存著該文件的前4096個(gè)字節(jié)(如果頁的大小為4096字節(jié)),接下來的頁保存著文件第二個(gè)4096個(gè)字節(jié),依次類推。樹中的所有中間節(jié)點(diǎn)為組織節(jié)點(diǎn),指示某一地址上的數(shù)據(jù)所在的頁。此樹的層次可以從0層到6層,所支持的文件大小從0字節(jié)到16 T 個(gè)字節(jié)。樹的根節(jié)點(diǎn)指針可以從和文件相關(guān)的 address_space 對象(該對象保存在和文件關(guān)聯(lián)的 inode 對象中)中取得(更多關(guān)于 page cache 的結(jié)構(gòu)內(nèi)容請參見參考資料)。


圖5 文件的 page cache 結(jié)構(gòu)
?

現(xiàn)在,我們來看看函數(shù) do_generic_mapping_read 都作了哪些工作, do_generic_mapping_read 函數(shù)代碼較長,本文簡要介紹下它的主要流程:

  • 根據(jù)文件當(dāng)前的讀寫位置,在 page cache 中找到緩存請求數(shù)據(jù)的 page

  • 如果該頁已經(jīng)最新,將請求的數(shù)據(jù)拷貝到用戶空間

  • 否則, Lock 該頁

  • 調(diào)用 readpage 函數(shù)向磁盤發(fā)出添頁請求(當(dāng)下層完成該 IO 操作時(shí)會解鎖該頁),代碼:

error = mapping->a_ops->readpage(filp, page);

?

  • 再一次 lock 該頁,操作成功時(shí),說明數(shù)據(jù)已經(jīng)在 page cache 中了,因?yàn)橹挥?IO 操作完成后才可能解鎖該頁。此處是一個(gè)同步點(diǎn),用于同步數(shù)據(jù)從磁盤到內(nèi)存的過程。

  • 解鎖該頁

  • 到此為止數(shù)據(jù)已經(jīng)在 page cache 中了,再將其拷貝到用戶空間中(之后 read 調(diào)用可以在用戶空間返回了)

到此,我們知道:當(dāng)頁上的數(shù)據(jù)不是最新的時(shí)候,該函數(shù)調(diào)用 mapping->a_ops->readpage 所指向的函數(shù)(變量 mapping 為 inode 對象中的 address_space 對象),那么這個(gè)函數(shù)到底是什么呢?

Readpage 函數(shù)的由來

address_space 對象是嵌入在 inode 對象之中的,那么不難想象: address_space 對象成員 a_ops 的初始化工作將會在初始化 inode 對象時(shí)進(jìn)行。如清單3中后半部所顯示。

if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else ? ?inode->i_mapping->a_ops = &ext2_aops;

?

可以知道 address_space 對象的成員 a_ops 指向變量 ext2_aops 或者變量 ext2_nobh_aops 。這兩個(gè)變量的初始化如清單5所示。


清單5 變量 ext2_aops 和變量 ext2_nobh_aops 的初始化

? ? ? ? ? ? ? ?struct address_space_operations ext2_aops = { ? ?.readpage ? ? ? ? ?= ? ? ? ? ? ? ? ?ext2_readpage, ? ?.readpages ? ? ? ? = ext2_readpages, ? ?.writepage ? ? ? ? = ext2_writepage, ? ?.sync_page ? ? ? ? = block_sync_page, ? ?.prepare_write ? ? = ext2_prepare_write, ? ?.commit_write ? ? ? = generic_commit_write, ? ?.bmap ? ? ? ? ? ? ? ? = ext2_bmap, ? ?.direct_IO ? ? ? ? ? = ext2_direct_IO, ? ?.writepages ? ? ? ? ?= ext2_writepages, }; struct address_space_operations ext2_nobh_aops = { ? ?.readpage ? ? ? ? ? ? ? ?= ext2_readpage, ? ?.readpages ? ? ? ? ? = ext2_readpages, ? ?.writepage ? ? ? ? = ext2_writepage, ? ?.sync_page ? ? ? ? ? = block_sync_page, ? ?.prepare_write ? ? ?= ext2_nobh_prepare_write, ? ?.commit_write ? ? ? = nobh_commit_write, ? ?.bmap ? ? ? ? ? ? ? ? = ext2_bmap, ? ?.direct_IO ? ? ? ? ? = ext2_direct_IO, ? ?.writepages ? ? ? ? ?= ext2_writepages, };

?

從上述代碼中可以看出,不論是哪個(gè)變量,其中的 readpage 成員都指向函數(shù) ext2_readpage 。所以可以斷定:函數(shù) do_generic_mapping_read 最終調(diào)用 ext2_readpage 函數(shù)處理讀數(shù)據(jù)請求。

到此為止, ext2 文件系統(tǒng)層的工作結(jié)束。

Page cache 層的處理

從上文得知:ext2_readpage 函數(shù)是該層的入口點(diǎn)。該函數(shù)調(diào)用 mpage_readpage 函數(shù),清單6顯示了 mpage_readpage 函數(shù)的代碼。


清單6 mpage_readpage 函數(shù)的代碼

? ? ? ? ? ? ? ?int mpage_readpage(struct page *page, get_block_t get_block) { ? ?struct bio *bio = NULL; ? ?sector_t last_block_in_bio = 0; ? ?bio = do_mpage_readpage(bio, page, 1, ? ? ? ? ? ? ? ? ? ? ? ? &last_block_in_bio, get_block); ? ?if (bio) ? ? ? ?mpage_bio_submit(READ, bio); ? ?return 0; }

?

該函數(shù)首先調(diào)用函數(shù) do_mpage_readpage 函數(shù)創(chuàng)建了一個(gè) bio 請求,該請求指明了要讀取的數(shù)據(jù)塊所在磁盤的位置、數(shù)據(jù)塊的數(shù)量以及拷貝該數(shù)據(jù)的目標(biāo)位置——緩存區(qū)中 page 的信息。然后調(diào)用 mpage_bio_submit 函數(shù)處理請求。 mpage_bio_submit 函數(shù)則調(diào)用 submit_bio 函數(shù)處理該請求,后者最終將請求傳遞給函數(shù) generic_make_request ,并由 generic_make_request 函數(shù)將請求提交給通用塊層處理。

到此為止, page cache 層的處理結(jié)束。

通用塊層的處理

generic_make_request 函數(shù)是該層的入口點(diǎn),該層只有這一個(gè)函數(shù)處理請求。清單7顯示了函數(shù)的部分代碼


清單7 generic_make_request 函數(shù)部分代碼

? ? ? ? ? ? ? ?void generic_make_request(struct bio *bio) { ? ?…… ? ?do { ? ? ? ?char b[BDEVNAME_SIZE]; ? ? ? ?q = bdev_get_queue(bio->bi_bdev); ? ? ? ?…… ? ? ? ?block_wait_queue_running(q); ? ? ? ?/* ? ? ? ?* If this device has partitions, remap block n ? ? ? ?* of partition p to block n+start(p) of the disk. ? ? ? ?*/ ? ? ? ?blk_partition_remap(bio); ? ? ? ?ret = q->make_request_fn(q, bio); ? ?} while (ret); }

?

主要操作:

  • 根據(jù) bio 中保存的塊設(shè)備號取得請求隊(duì)列 q

  • 檢測當(dāng)前 IO 調(diào)度器是否可用,如果可用,則繼續(xù);否則等待調(diào)度器可用

  • 調(diào)用 q->make_request_fn 所指向的函數(shù)將該請求(bio)加入到請求隊(duì)列中

到此為止,通用塊層的操作結(jié)束。

IO 調(diào)度層的處理

對 make_request_fn 函數(shù)的調(diào)用可以認(rèn)為是 IO 調(diào)度層的入口,該函數(shù)用于向請求隊(duì)列中添加請求。該函數(shù)是在創(chuàng)建請求隊(duì)列時(shí)指定的,代碼如下(blk_init_queue 函數(shù)中):

q->request_fn = rfn; blk_queue_make_request(q, __make_request);

?

函數(shù) blk_queue_make_request 將函數(shù) __make_request 的地址賦予了請求隊(duì)列 q 的 make_request_fn 成員,那么, __make_request 函數(shù)才是 IO 調(diào)度層的真實(shí)入口。

__make_request 函數(shù)的主要工作為:

  1. 檢測請求隊(duì)列是否為空,若是,延緩驅(qū)動程序處理當(dāng)前請求(其目的是想積累更多的請求,這樣就有機(jī)會對相鄰的請求進(jìn)行合并,從而提高處理的性能),并跳到3,否則跳到2

  2. 試圖將當(dāng)前請求同請求隊(duì)列中現(xiàn)有的請求合并,如果合并成功,則函數(shù)返回,否則跳到3

  3. 該請求是一個(gè)新請求,創(chuàng)建新的請求描述符,并初始化相應(yīng)的域,并將該請求描述符加入到請求隊(duì)列中,函數(shù)返回

將請求放入到請求隊(duì)列中后,何時(shí)被處理就由 IO 調(diào)度器的調(diào)度算法決定了(有關(guān) IO 調(diào)度器的算法內(nèi)容請參見參考資料)。一旦該請求能夠被處理,便調(diào)用請求隊(duì)列中成員 request_fn 所指向的函數(shù)處理。這個(gè)成員的初始化也是在創(chuàng)建請求隊(duì)列時(shí)設(shè)置的:

q->request_fn = rfn; blk_queue_make_request(q, __make_request);

?

第一行是將請求處理函數(shù) rfn 指針賦給了請求隊(duì)列的 request_fn 成員。而 rfn 則是在創(chuàng)建請求隊(duì)列時(shí)通過參數(shù)傳入的。

對請求處理函數(shù) request_fn 的調(diào)用意味著 IO 調(diào)度層的處理結(jié)束了。

塊設(shè)備驅(qū)動層的處理

request_fn 函數(shù)是塊設(shè)備驅(qū)動層的入口。它是在驅(qū)動程序創(chuàng)建請求隊(duì)列時(shí)由驅(qū)動程序傳遞給 IO 調(diào)度層的。

IO 調(diào)度層通過回調(diào) request_fn 函數(shù)的方式,把請求交給了驅(qū)動程序。而驅(qū)動程序從該函數(shù)的參數(shù)中獲得上層發(fā)出的 IO 請求,并根據(jù)請求中指定的信息操作設(shè)備控制器(這一請求的發(fā)出需要依據(jù)物理設(shè)備指定的規(guī)范進(jìn)行)。

到此為止,塊設(shè)備驅(qū)動層的操作結(jié)束。

塊設(shè)備層的處理

接受來自驅(qū)動層的請求,完成實(shí)際的數(shù)據(jù)拷貝工作等等。同時(shí)規(guī)定了一系列規(guī)范,驅(qū)動程序必須按照這個(gè)規(guī)范操作硬件。

后續(xù)工作

當(dāng)設(shè)備完成了 IO 請求之后,通過中斷的方式通知 cpu ,而中斷處理程序又會調(diào)用 request_fn 函數(shù)進(jìn)行處理。

當(dāng)驅(qū)動再次處理該請求時(shí),會根據(jù)本次數(shù)據(jù)傳輸?shù)慕Y(jié)果通知上層函數(shù)本次 IO 操作是否成功,如果成功,上層函數(shù)解鎖 IO 操作所涉及的頁面(在 do_generic_mapping_read 函數(shù)中加的鎖)。

該頁被解鎖后, do_generic_mapping_read() 函數(shù)就可以再次成功獲得該鎖(數(shù)據(jù)的同步點(diǎn)),并繼續(xù)執(zhí)行程序了。之后,函數(shù) sys_read 可以返回了。最終 read 系統(tǒng)調(diào)用也可以返回了。

至此, read 系統(tǒng)調(diào)用從發(fā)出到結(jié)束的整個(gè)處理過程就全部結(jié)束了。

回頁首

總結(jié)

本文介紹了 linux 系統(tǒng)調(diào)用 read 的處理全過程。該過程分為兩個(gè)部分:用戶空間的處理和核心空間的處理。在用戶空間中通過 0x80 中斷的方式將控制權(quán)交給內(nèi)核處理,內(nèi)核接管后,經(jīng)過6個(gè)層次的處理最后將請求交給磁盤,由磁盤完成最終的數(shù)據(jù)拷貝操作。在這個(gè)過程中,調(diào)用了一系列的內(nèi)核函數(shù)。如圖 6


圖6 read 系統(tǒng)調(diào)用在內(nèi)核中所經(jīng)歷的函數(shù)調(diào)用層次
?


【轉(zhuǎn)】SD3.0協(xié)議解讀的評論 (共 條)

分享到微博請遵守國家法律
阿鲁科尔沁旗| 佛学| 庄河市| 石首市| 平湖市| 沙雅县| 察雅县| 邮箱| 宜昌市| 龙岩市| 竹溪县| 安西县| 江华| 罗田县| 本溪| 徐州市| 明水县| 大石桥市| 白朗县| 安岳县| 德庆县| 方山县| 喜德县| 潮安县| 页游| 手机| 安阳县| 天等县| 新平| 宁都县| 亳州市| 武清区| 南宫市| 崇义县| 保德县| 深泽县| 丹凤县| 漳平市| 赤峰市| 玉环县| 关岭|