編寫自己的SD/MMC Host驅動(一):註冊

網上已經有很多文章寫了Linux SD/MMC的驅動的分析了,尤其是SAMSUNG系列的,估計用汗牛充棟來描寫都不過分。俺只能說點我自己寫的基於CBP的EVB板子的SD/MMC controller的驅動了,這個驅動沒有采用DMA,雖然那是我最擅長的。使用的是pio模式,其實就是CPU讀寫了,但是竟然也沒有使用tasklet,也就沒有中斷的上下半部的說法了,應該不是一個很好的習慣,雖然tasklet其實就是啓動一個內核運行隊列,去運行pio的讀寫等等,本質上沒有大的區別,但沒有使用就是沒有使用,實事求是而已。

那就說說Linux SD/MMC驅動的工作過程吧:

首先按照platform驅動的方式,註冊probe函數,然後系統就會調用probe函數,具體方法和原理請參考本人寫的以及轉載的plateform的文章,就不在贅述了。

在probe裏面首先分配一個mmc_host的結構,Linux以後發起各種操作的時候,參數都會通過這個結構傳遞。

mmc=mmc_alloc_host(sizeof(struct cbpmci_host), &pdev->dev);

mmc_alloc_host這個函數比較有意思,其中傳入的第一個參數是一個長度,這個長度是在mmc_hos後面額外連續分配的一塊數據,我這句的意思就是緊跟着mmc_host分配了一個cbpmci_host的結構,看mmc_host的定義如下:

struct mmc_host {

       struct device          *parent;

………省略若干行………………

unsigned long        private[0] ____cacheline_aligned;

};


其實cbpmci_host的位置就是private[0]的位置,巧妙吧?經常看看Linux代碼能學到不少Linux大牛們的方法。這樣就可以通過這個函數來從mmc_host中得到自己帶入的私有數據了:

static inline void *mmc_priv(struct mmc_host *host)

{

       return (void *)host->private;

}

按照Linux驅動的慣例,此時應該註冊SD/MMC的操作函數了,SD/MMC的操作函數恐怕是Linux驅動裏面最少的之一了,只有如下幾個:

struct mmc_host_ops {

       int (*enable)(struct mmc_host *host);

       int (*disable)(struct mmc_host *host, int lazy);

       void (*request)(struct mmc_host *host, struct mmc_request *req);

       void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);

       int    (*get_ro)(struct mmc_host *host);

       int    (*get_cd)(struct mmc_host *host);

       void (*enable_sdio_irq)(struct mmc_host *host, int enable);

};

我的定義:

static struct mmc_host_ops cbpmci_ops = {

       .request   = cbpmci_request,

       .set_ios   = cbpmci_set_ios,

       .get_ro           = cbpmci_get_ro,

       .get_cd           = cbpmci_card_present,

       .enable_sdio_irq = cbpmci_enable_sdio_irq,

};

將cbpmci_ops 賦值給mmc->ops即可

mmc->ops     = &cbpmci_ops;

爲啥連讀寫都沒有呢,因爲他是通過request裏面的參數來進行標識的。Request函數主要處理Linux發到驅動的命令請求,包括帶數據的和不帶數據的,帶數據的一般就是read/write, 其實ext CSD之類的東東也是通過讀來完成的。

其中的set_ios是設置一些控制參數的,比如時鐘頻率,電源開/關,總線寬度等等。

get_ro是獲取SD/MMC的寫保護標誌的,就是SD卡上的那個小開關的狀態,如果返回0則是可寫的,不然爲只讀。

get_cd是獲取卡的插入狀態的,返回0則有卡,不然返回1。

接着當然是要申請對應的SD的中斷了,在中斷函數中將處理命令完成,CRC錯誤等等中斷。

然後再初始化一些mmc_host的參數就OK了,比如最大最小頻率,總線寬度,最大的block count等等。然後調用 mmc_add_host將host驅動加入。

ret = mmc_add_host(mmc);

如果驅動加入沒有錯誤,系統將會調用相應的初始化過程,好像寫的有點長了,還是下回分解吧!

 


 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章