下面說明一些重要函數:
1、 mmc_alloc_host
/**
* mmc_alloc_host - initialise the per-host structure.
* @extra: sizeof private data structure
* @dev: pointer to host device model structure
*
* Initialise the per-host structure.
*/
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
struct mmc_host *host;
host = mmc_alloc_host_sysfs(extra, dev);
if (host) {
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_LIST_HEAD(&host->cards);
INIT_WORK(&host->detect, mmc_rescan, host);
/*
* By default, hosts do not support SGIO or large requests.
* They have to set these according to their abilities.
*/
host->max_hw_segs = 1;
host->max_phys_segs = 1;
host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
host->max_seg_size = PAGE_CACHE_SIZE;
}
return host;
}
這裏面啓動了一個延時工作隊列,會啓動mmc_rescan函數;
2、 mmc_add_host(mmc);函數
調用mmc_add_host的最終結果是device_add(&host->class->dev)(所以在/sys/class/mmc/目錄下出現mmc0文件)。
並會調用mmc_power_off(host);mmc_detect_change(host, 0);
mmc_power_off函數比較簡單,顧名思義,它是讓SD/MMC卡停止工作的,相應的,此函數就會配置相應的IO口以及時鐘等。
我們來看看mmc_detect_change函數吧。
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
mmc_schedule_delayed_work(&host->detect, delay);
}
queue_delayed_work把host->detect提交到workqueue工作對列中。
相應定義:
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
workqueue = create_singlethread_workqueue("kmmcd");
所以,當此delayed_work執行的時候,mmc_rescan將會被調用;
static void mmc_rescan(void *data)
{
struct mmc_host *host = data;
struct list_head *l, *n;
unsigned char power_mode;
/*
驅動中使用mmc_claim_host(host);來得知,當前mmc控制器是否被佔用,當前mmc控制器如果被佔用,那麼 host->claimed = 1;否則爲0,如果爲1,那麼會在for(;;)循環中調用schedule切換出自己,當佔用mmc控制器的操作完成之後,執行 mmc_release_host()的時候,會激活登記到等待隊列&host->wq中的其他程序獲得mmc主控制器的物理使用權*/
mmc_claim_host(host);//這個函數和mmc_release_host(host);配對使用,相當於一把鎖,就是在同一個時間只有一個sd卡可以保持和主控制器通訊;
/*
* Check for removed cards and newly inserted ones. We check for
* removed cards first so we can intelligently re-select the VDD.
*/
power_mode = host->ios.power_mode;
if (power_mode == MMC_POWER_ON) //最開始,卡是power_off
mmc_check_cards(host);
mmc_setup(host);//set power_mode = MMC_POWER_ON
/*
* Some broken cards process CMD1 even in stand-by state. There is
* no reply, but an ILLEGAL_COMMAND error is cached and returned
* after next command. We poll for card status here to clear any
* possibly pending error.
*/
if (power_mode == MMC_POWER_ON)
mmc_check_cards(host);
if (!list_empty(&host->cards)) {
/*
* (Re-)calculate the fastest clock rate which the
* attached cards and the host support.
*/
host->ios.clock = mmc_calculate_clock(host);
mmc_set_ios(host);
}
mmc_release_host(host);//釋放卡對主機的持有權
//查看devices鏈表中是否有卡插入,如果有就會調用mmc_register_card(card)
//該函數裏面調用device_add(&card->dev);將設備加入到devices表中,調用bus_attach_device(dev)-> device_attach(dev);如果取得存在直接調用device_bind_driver(dev),設備與取得綁定到一起;沒有則需要到總線上面去查找,函數__device_attach-> driver_probe_device(drv, dev);到這裏就是如同driver加到總線列表中一樣,調用bus中的match和probe函數,如果匹配成功調用device_bind_driver(dev)函數即可;
list_for_each_safe(l, n, &host->cards) {
struct mmc_card *card = mmc_list_to_card(l);
/*
* If this is a new and good card, register it.
*/
if (!mmc_card_present(card) && !mmc_card_dead(card)) {
if (mmc_register_card(card))
mmc_card_set_dead(card);
else
mmc_card_set_present(card);
}
/*
* If this card is dead, destroy it.
*/
if (mmc_card_dead(card)) {
list_del(&card->node);
mmc_remove_card(card);
}
}
/*
* If we discover that there are no cards on the
* bus, turn off the clock and power down.
*/
if (list_empty(&host->cards))
mmc_power_off(host);
}
還記得davinci_probe函數裏面有個定時器嗎,調用davinci_mmc_check_status函數,發現卡的插入和拔出,裏面會調用mmc_detect_change(host->mmc, 0);
static void davinci_mmc_check_status(unsigned long data)
{
unsigned long flags;
struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
if (!host->is_card_busy) {
if (host->old_card_state ^ host->new_card_state) {
davinci_reinit_chan(host);
init_mmcsd_host(host);
mmc_detect_change(host->mmc, 0);
spin_lock_irqsave(&host->mmc_lock, flags);
host->old_card_state = host->new_card_state;
spin_unlock_irqrestore(&host->mmc_lock, flags);
} else {
mmc_check_card(data);
}
}
mod_timer(&host->timer, jiffies + MULTIPLIER_TO_HZ * HZ);
}
這個函數會激活mmc_rescan,來到mmc_setup這裏,此時mmc_setup調用mmc_discover_cards。Create a mmc_card entry for each discovered card,add new card to list.同時還會調用mmc_read_switch_caps或者mmc_process_ext_csds來實現對大容量卡的支持(>