Linux SDIO總線驅(qū)動
CMD53命令:
CMD52每次只能讀寫一個字節(jié),因為有了CMD53對讀寫進行了擴展,CMD53允許每次讀寫多個字節(jié)或者多個塊(BLOCK)。CMD53的命令格式如下:
第一位是1,為開始位,然后是一位方向位,總是1,代表方向為HOST向DEVICE設(shè)備傳送,其后6位為命令號,這里是110101b,用十進制表示為53,CMD53的名字也由此而來。
然后是1位的讀寫標(biāo)志。接著是3位功能號,這個同CMD52都是相同的。BlockMode如果1代表是塊傳輸模式,否則為字節(jié)傳輸模式。
OP Code為操作位,如果是0,代表數(shù)據(jù)往固定的位置讀寫,如果1代表是地質(zhì)增量讀寫。例如,對地址0固定讀寫16個字節(jié),相當(dāng)于16次讀寫的地址0,而對地址0增量讀寫16個字節(jié),相當(dāng)于讀寫0~15地址的數(shù)據(jù)。
然后是17位的地址寄存器,可以尋址到128K字節(jié)的地址,然后是9位的讀寫的計數(shù),對于字節(jié)讀取,讀寫大小就是這個計數(shù),而對于塊讀寫,讀寫的大小是計數(shù)乘以塊的大小。
隨后的7位為CRC校驗碼。最后一位為1。
當(dāng)讀寫操作是塊操作的時候,塊的大小是可以通過設(shè)置FBR中的相關(guān)寄存器來設(shè)置。
同CMD52命令不同的是,CMD53沒有返回的命令的,這里判斷是否DEVICE設(shè)備讀寫完畢是需要驅(qū)動里面自己判斷的,一般有2個方法,1.設(shè)置相應(yīng)的讀寫完畢中斷。如果DEVICE設(shè)備讀寫完畢,則對HOST設(shè)備發(fā)送中斷。2.HOST設(shè)備主動查詢DEVICE設(shè)備是否讀寫完畢,可以通過CMD命令是否有返回來判斷是否DEVICE是否讀寫完畢。
驅(qū)動:
以SDIO為例其會采用mmc_attach_sdio來實現(xiàn)驅(qū)動和設(shè)備的匹配,其本質(zhì)還是根據(jù)sdio_bus的匹配規(guī)則來實現(xiàn)匹配。在mmc_attach_sdio中首先是mmc匹配一個bus,即采用何種bus來進行mmc bus來處理host。在這里需要理解一點就是在SDIO中,對于SD卡存儲器mmc為實體設(shè)備,而對于非SD卡存儲器,如SDIO接口的設(shè)備,則mmc則表征為bus,這個比較重要。除了mmc bus外還存在SDIO_BUS。
int mmc_attach_sdio(struct mmc_host *host,u32 ocr)
{
interr;
inti, funcs;
structmmc_card *card;
mmc_attach_bus(host,&mmc_sdio_ops); --host匹配一條mmc bus
card= mmc_alloc_card(host, NULL); --申請一個card實體,類似于總線設(shè)備。
card->type= MMC_TYPE_SDIO;
card->sdio_funcs= funcs;
host->card= card;
for(i = 0;i < funcs;i++) {
sdio_init_func(host->card,i + 1);
}
mmc_release_host(host);
mmc_add_card(host->card);
for(i = 0;i < funcs;i++) {
sdio_add_func(host->card->sdio_func[i]);
}
return0;
}
比較難以理解的是func,這個東東其實是一個實體設(shè)備的封裝,可以認為其是一個設(shè)備。
struct sdio_func *sdio_alloc_func(structmmc_card *card)
{
structsdio_func *func;
func= kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
func->card= card;
device_initialize(&func->dev);
func->dev.parent= &card->dev; --很明顯card設(shè)備為sdio設(shè)備的父設(shè)備。
func->dev.bus= &sdio_bus_type;
func->dev.release= sdio_release_func;
returnfunc;
}
上面的code一目了然,其就是具體設(shè)備實體的封裝,其bus類型為sdio_bus. sdio_init_func僅僅是初始化一個設(shè)備,而并沒有register。在sdio_add_func實現(xiàn)設(shè)備的register,同理就是card實體,在mmc_add_card之前并沒有注冊,在mmc_add_card函數(shù)中才實現(xiàn)設(shè)備的注冊。
到此設(shè)備注冊也就完成了,其實sdio總線在形式上類似于usb bus,為什么呢?編寫過usb驅(qū)動的童鞋們應(yīng)該知道,編寫usb驅(qū)動僅僅是編寫驅(qū)動的加載,并沒有具體加載設(shè)備實體,導(dǎo)致很多童鞋的困惑,為什么沒有設(shè)備的加載,其實在usb設(shè)備插入時,會動態(tài)的創(chuàng)建一個usb設(shè)備實體,在usb設(shè)備實體創(chuàng)建完成后,根據(jù)不同設(shè)備id調(diào)用相匹配的驅(qū)動。而SDIO設(shè)備設(shè)備也是一樣的。上面的code比較混亂,總是讓人看不出具體的設(shè)備的加載。其實在上面的code中,其中包括了mmc host的驅(qū)動。
評論