sdio 熱插拔流程
由於SD卡插槽採用的是機械式開關,在插拔卡的時候,機械開關斷開、閉合.
系統初始化時,開關檢測引腳被設定為上升沿和下降沿觸發,因此引腳電平發生變化時,都會有中斷產生。當硬體產生中斷時,系統進入核心ISR,對開關檢測引腳進行檢測,返回相應的中斷標識碼,對於是SD插入還是拔出,則由驅動程式的IST來處理。
由於SD卡插槽採用的是機械式開關,在插拔卡的時候,機械開關斷開、閉合時會有抖動,導致SD卡檢測引腳的電平不穩定,從而有可能引起對卡的狀態的誤判。這樣會導致載入上層驅動,初始化失敗造成系統不穩定。為了使每次插拔只響應一次,必須要採用相應的方法來防止抖動,避開機械開關的抖動時間。
在驅動程式IST裡採用延時採樣的方法來避免抖動。 延時採樣是IST在收到SD卡檢測事件以後,並不是立刻進行引腳訊號判斷,而是延時一段時間採樣,延遲時間要根據系統電路特性而定,然後檢測引腳訊號,判斷插槽的狀態是卡插入還是拔出。
當拔出sdio卡的時候,卡座的開關會觸發中斷,執行中斷回呼函數mmc_detect_change
,對於工作隊列,下半部分是mmc_rescan
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
mmc_detect_change
==>mmc_schedule_delayed_work(&host->detect, delay);
==>host->detect就是mmc_rescan
==>mmc_rescan
==>host->bus_ops->detect(host);//就是mmc_sdio_detect
==>static const struct mmc_bus_ops mmc_sdio_ops.detect = mmc_sdio_detect;
==>mmc_sdio_detect //如果發現卡已經拔走,那麼執行
==>mmc_sdio_remove(host);//刪除/sys/目錄下的檔案,同時釋放kmalloc到的記憶體.
==>mmc_detach_bus
==>mmc_bus_put
if ((host->bus_refs == 0) && host->bus_ops)
__mmc_release_bus(host);
==>__mmc_release_bus
==>host->bus_ops = NULL;//這樣mmc_rescan的時候,就可以執行對mmc口進行重新檢卡操作了.
當卡插入時產生中斷,mmc_rescan()函數被執行,然後對卡進行初始化
初始化卡流程:
a、發送CMD0使卡進入IDLE狀態
b、發送CMD8,檢查卡是否SD2.0。SD1.1是不支援CMD8的,因此在SD2.0 Spec中提出了先發送CMD8,如響應為無效命令,則卡為SD1.1,否則就是SD2.0(請參考SD2.0 Spec)。
c、發送CMD5讀取OCR寄存器。
d、發送ACMD55、CMD41,使卡進入工作狀態。MMC卡並不支援ACMD55、CMD41,如果這步通過了,則證明這張卡是SD卡。
e、如果d步驟錯誤,則發送CMD1判斷卡是否為MMC。SD卡不支援CMD1,而MMC卡支援,這就是SD和MMC類型的判斷依據。
f、如果ACMD41和CMD1都不能通過,那這張卡恐怕就是無效卡了,初始化失敗。
ACMD41 命令,這條命令可以用來擷取 SDcard 的允許電壓範圍值,由於這是一條應用程式命令,所有發送它之前需要發送 CMD_55 命令。執行完後 card 狀態變為 READY 擷取的電壓範圍儲存在 ocr 中,再調用 mmc_attach_sd(host, ocr) 看這個電壓範圍是否滿足主機的要求,不滿足,則 power_off 主機。
mmc_attach_sd 完成匹配,和初始化卡的功能
host->ocr = mmc_select_voltage(host, ocr); 看是否匹配,如果匹配則做下面初始化工作
mmc_sd_init_card(host, host->ocr, NULL); 我們分析該函數
( 1 ) mmc_all_send_cid ()這個函數發生 CMD2 ,擷取卡的身份資訊,進入到身份狀態
(2)card = mmc_alloc_card(host, &sd_type); 分配一張 SD 類型的 card 結構
(3) 接著調用 mmc_send_relative_add, 擷取卡的相對位址,注意一前卡和主機通訊都採用預設地址,現在有了自己的地址了,進入到 stand_by 狀態
( 4 )通過發送 SEND_CSD (CMD9) 擷取 CSD 寄存器的資訊,包括 block 長度,卡容量等資訊
(5) mmc_select_card(card) 發送 CMD7, 選中目前 RADD 地址上的卡,任何時候匯流排上只有一張卡被選中,進入了傳輸狀態 ,
( 6 )調用 mmc_app_send_scr 發送命令 ACMD51 擷取 SRC 寄存器的內容,進入到 SENDING-DATA 狀態
在函數中還將獲得的各個卡寄存器的內容解碼,並儲存到 cmd 結構的相應成員中。
( 7 ) if (host->ops->get_ro(host) > 0 )
mmc_card_set_readonly(card);
通過調用 get_ro(host) 函數,實際上就是 s3cmci_get_ro 函數了。 我們判斷是否防寫保護,如果是的,將 card 狀態設定為唯讀狀態