下面说明一些重要函数:
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来实现对大容量卡的支持(> 4G );从而实现对卡拔出和插入的检查;