上次我们了解到,mmc card设备驱动通过mmc_bus_type这条总线找到了block驱动,由block驱动去加载该设备。今天我们再进一步去了解这整个过程。
我们都知道,mmc card的驱动需要启动中断并配合定时器去检测是否有卡插入,那这个功能是在哪里实现的呢?
在函数
mmc_alloc_host中有这一个调用
INIT_DELAYED_WORK(&host->detect, mmc_rescan),它将函数工作队列执行函数mmc_rescan放置到一个延时工作队列中,等待启动。
在平台设备驱动
sdhci_arasan_probe中:
sdhci_add_host(host)->
sdhci_enable_card_detection(host)->
sdhci_unmask_irqs(host, irqs)去启动中断检测功能,接着我们看看中断检测功能里面有些什么。在中断函数
sdhci_irq里面如果发现有card插入就会调用
tasklet_schedule(&host->card_tasklet),执行注册在该card_tasklet上的函数实体——
sdhci_tasklet_card,该函数里面调用了2个函数,从命名上看,我们应该更加关心后面一个函数
mmc_detect_change,传入的参数是将200ms转化为系统能够是别的
jiffies,一层一层最后调用函数
mmc_schedule_delayed_work(&host->detect, delay),延时200ms启动mmc_rescan函数。
我们回到函数mmc_rescan,该函数里面调用了
mmc_rescan_try_freq(host, max(freqs[i], host->f_min))去进一步扫描card,调用
mmc_attach_sdio(host)去扫描是否是sdio接口的卡,如果是则主要调用函数
mmc_sdio_init_card(host, rocr, NULL, 0)去初始化该卡,里面最为重要的函数调用时
mmc_alloc_card(host, NULL),因为在该函数中,对card device进行初始化和参数配置的,可以看到最重要一句——
card->dev.bus = &mmc_bus_type,此处就真正的将device和driver通过总线关联起来了。
我们把整个流程串起来看,简单来说就是:
加载platform设备 -> 启动平台驱动 -> 生成 host驱动,包含一个中断检测功能 ----> 在/dev目录下生成mmc0、mmc1等设备文件
此时中断触发->构造一个card设备驱动,并注册到mmc总线上线->->关联到总线上的block驱动->在/dev目录下生成mmcblk0、mmcblk1等文件---->
至此生成了块设备文件。
接下来看看如何才和mmc总线上的block驱动关联起来,主要流程如下:
1. 通过总线函数bus_mach对device和driver做匹配,返回非0表示匹配成功,好像mmc的mach函数直接返回1
2. 把该drv赋值给dev,通过调用bus的probe函数对该dev进行探测
3. 通过drv的probe函数对该dev进行探测