一、struct mmc_host 結構體
struct dw_mci {
spinlock_t lock;
spinlock_t irq_lock;
void __iomem *regs;
void __iomem *fifo_reg;
struct scatterlist *sg;
struct sg_mapping_iter sg_miter;
struct dw_mci_slot *cur_slot;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
struct mmc_command stop_abort;
unsigned int prev_blksz;
unsigned char timing;
/* DMA interface members*/
int use_dma;
int using_dma;
int dma_64bit_address;
dma_addr_t sg_dma;
void *sg_cpu;
const struct dw_mci_dma_ops *dma_ops;
/* For idmac */
unsigned int ring_size;
/* For edmac */
struct dw_mci_dma_slave *dms;
/* Registers's physical base address */
resource_size_t phy_regs;
u32 cmd_status;
u32 data_status;
u32 stop_cmdr;
u32 dir_status;
struct tasklet_struct tasklet;
unsigned long pending_events;
unsigned long completed_events;
enum dw_mci_state state;
struct list_head queue;
u32 bus_hz;
u32 current_speed;
u32 num_slots;
u32 fifoth_val;
u16 verid;
struct device *dev;
struct dw_mci_board *pdata;
const struct dw_mci_drv_data *drv_data;
void *priv;
struct clk *biu_clk;
struct clk *ciu_clk;
struct dw_mci_slot *slot[MAX_MCI_SLOTS];
/* FIFO push and pull */
int fifo_depth;
int data_shift;
u8 part_buf_start;
u8 part_buf_count;
union {
u16 part_buf16;
u32 part_buf32;
u64 part_buf;
};
void (*push_data)(struct dw_mci *host, void *buf, int cnt);
void (*pull_data)(struct dw_mci *host, void *buf, int cnt);
/* Workaround flags */
u32 quirks;
bool vqmmc_enabled;
unsigned long irq_flags; /* IRQ flags */
int irq;
int sdio_id0;
struct timer_list cmd11_timer;
struct timer_list cto_timer;
struct timer_list dto_timer;
struct timer_list xfer_timer;
};
struct mmc_host(linux/include/linux/mmc/host.h)用於與core層的命令請求,數據 傳輸等信息,這裏代碼較長,展示部分
struct mmc_host
{
const struct mmc_host_ops *ops; // SD卡主控制器的操作函數,即該控制器所具備的驅動能力
const struct mmc_bus_ops *bus_ops; // SD總線驅動的操作函數,即SD總線所具備的驅動能力
struct mmc_ios ios; // 配置時鐘、總線、電源、片選、時序等
struct mmc_card *card; // 連接到此主控制器的SD卡設備
... ...
};
結構體詳解可以參考:http://blog.chinaunix.net/uid-28414100-id-5754672.html
二、SD控制器之初始化
dw_mci_probe 初始化dw_mci結構體相關內容,解析dts的數據,創建mmc_host對象
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
int err;
struct mmc_host *host;
host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
if (!host)
return NULL;
/* scanning will be enabled when we're ready */
host->rescan_disable = 1;
idr_preload(GFP_KERNEL);
spin_lock(&mmc_host_lock);
err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT); //內核高效搜索樹,
if (err >= 0)
host->index = err;
spin_unlock(&mmc_host_lock);
idr_preload_end();
if (err < 0) {
kfree(host);
return NULL;
}
dev_set_name(&host->class_dev, "mmc%d", host->index);
host->parent = dev;
host->class_dev.parent = dev;
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev); //初始化host->class_dev,這個日後會通過device_register註冊進系統。
if (mmc_gpio_alloc(host)) {
put_device(&host->class_dev);
return NULL;
}
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
#ifdef CONFIG_PM
host->pm_notify.notifier_call = mmc_pm_notify;
#endif
setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
/*
* By default, hosts do not support SGIO or large requests.
* They have to set these according to their abilities.
*/
host->max_segs = 1;
host->max_seg_size = PAGE_CACHE_SIZE;
host->max_req_size = PAGE_CACHE_SIZE;
host->max_blk_size = 512;
host->max_blk_count = PAGE_CACHE_SIZE / 512;
return host;
}
三、設備驅動功能函數
static const struct mmc_host_ops dw_mci_ops = {
.request = dw_mci_request, //下面解釋。
.pre_req = dw_mci_pre_req,
.post_req = dw_mci_post_req,
.set_ios = dw_mci_set_ios, //設置SD卡控制器,前面我們所見到的設置控制器時鐘,數據線寬度等等一系列操作最終就是通過他來實現的。
.set_sdio_status = dw_mci_set_sdio_status,
.get_ro = dw_mci_get_ro, //獲取卡的寫保護狀態,前面所過,SD卡初始化完成以後,我們進行的一個最後的工作便是檢測卡的寫保護狀態,其實就是調用get_ro方法。
.get_cd = dw_mci_get_cd, //檢測卡是否在卡槽之中
.enable_sdio_irq = dw_mci_enable_sdio_irq, //開啓sdio中斷,這個是對sdio卡而言的
.execute_tuning = dw_mci_execute_tuning,
.card_busy = dw_mci_card_busy,
.start_signal_voltage_switch = dw_mci_switch_voltage,
.init_card = dw_mci_init_card,
.prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
};
dw_mci_request
dw_mci_queue_request
host->state == STATE_WAITING_CMD11_DONE //判斷電壓是否正確
dw_mci_start_request
__dw_mci_start_request
dw_mci_submit_data //實現數據的傳輸
dw_mci_start_command //實現指令的傳輸,需要sd卡主控芯片手冊
-
response類型
根據SD卡的協議,當SD卡收到從控制器發來的cmd指令後,SD卡會發出response相應,而response的類型分爲R1,R1b,R2,R3,R6,R7,這些類型分別對應不同的指令,各自的數據包結構也不同(具體內容參考SD卡協議)。這裏,通過RSP_TYPE對指令cmd的opcode的解析得到相對應的reponse類型,再通過swich賦給寄存器MMC_CMDAT對應的[1:0]位。
-
將指令和參數寫入寄存器
mci_writel()是整個SD卡主控制器設備驅動的實質,通過對主控制器芯片寄存器MMC_CMD,MMC_ARGH,MMC_ARGL,MMC_CMDAT的設置,實現主控制器發送指令到SD卡的功能。
四、中斷
有兩個中斷,一個爲SD主控制器芯片內電路固有的內部中斷,另一個爲探測引腳的探測到外部有SD卡插拔引起的中斷
devm_request_irq(host->dev, host->irq, dw_mci_interrupt,host->irq_flags, “dw-mci”, host);
當有SD卡插入或拔出時,硬件主控制器芯片的探測pin腳產生外部中斷,進入中斷處理函數,執行工作隊列裏的mmc_rescan,掃描SD總線,對插入或拔出SD卡作相應的處理。
enable_sdio_irq = dw_mci_enable_sdio_irq,
當調用(*request),即host->ops->request(host, mrq),即上文中的_request()後控制器與SD卡之間開始進行一次指令或數據傳輸,通信完畢後,主控芯片將產生一個內部中斷,
以告知此次指令或數據傳輸完畢。這個中斷的具體值將保存在一個名爲MMC_I_REG的中斷寄存器中以供讀取,中斷寄存器MMC_I_REG中相關描述