一、扫描mmc硬件总线
扫描mmc硬件总线,也就是检测mmc硬件总线上是否有挂载card。更加通俗的,就是卡槽上是否有插入card。
1、扫描mmc硬件总线的时机
mmc core在如下情况下会去扫描mmc硬件总线:
- 启动一个host的时候而调用mmc_detect_change
当启动一个host的时候,并不知道当前是否有card插入,此时需要调用mmc_detect_change来假设card插入状态发生了变化,
并且进行第一次扫描mmc硬件总线。
代码如下,过滤掉无关代码:
void mmc_start_host(struct mmc_host *host)
{
//...
mmc_detect_change(host, 0);
}
- 底层硬件发现card插入状态发生变化而调用mmc_detect_change的时候(sd card插入状态监控)
当底层硬件发现card插入状态发生变化,例如sd card的插入或者拔出可以触发某个GPIO产生中断。
此时,可以在中断处理中调用mmc_detect_change来进行扫描mmc硬件总线,并且根据总线上的card状态变化进行处理。
这种情况的主要目的是为了实现sd card的热插拔。
代码如下,过滤掉无关代码:
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
status = mmc_gpio_get_status(host); // 先获取card的插入状态
if (unlikely(status < 0))
goto out;
if (status ^ ctx->status) { // 与之前的card的状态进行比较,不一样则说明mmc硬件总线上的card发生了插入或者拔出事件
ctx->status = status;
/* Schedule a card detection after a debounce timeout */
mmc_detect_change(host, msecs_to_jiffies(200));
// 调用mmc_detect_change对card的插入状态变化进行处理
// 注意,这里延时了200ms是用来进行消抖
}
out:
return IRQ_HANDLED;
}
- host要求轮询sd card插入状态的情况下,所进行的轮询操作(sd card插入状态监控)
一般来说,在host无法根据硬件来及时获取card插入状态发生变化的情况下,会要求mmc_core每隔一段时间(一般是HZ,一秒)扫描一次mmc硬件总线。
在这种情况下,mmc_host的MMC_CAP_NEEDS_POLL属性会被设置。
这种情况的主要目的也是为了实现sd card的热插拔。
代码如下,过滤掉无关代码:
void mmc_rescan(struct work_struct *work)
{
if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);
// 这里先说明下
// 在《host模块说明》已经知道了在mmc_alloc_host中默认将host->detect工作设置为mmc_rescan(card扫描)函数,
// INIT_DELAYED_WORK(&host->detect, mmc_rescan)
// 这样,通过mmc_schedule_delayed_work(&host->detect, HZ)就会每隔HZ时间就会执行一次mmc_rescan
}
2、如何扫描mmc硬件总线
从上述,我们知道了可以通过调用mmc_detect_change和执行host->detect工作来发起mmc硬件总线的扫描。
而mmc_detect_change最终也是执行mmc_host->detect工作来发起mmc硬件总线扫描的。
下面来看一下这两个函数
- mmc_detect_change
代码如下:
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
host->detect_change = 1; // 设置mmc_host->detect_change,表示检测到card状态发生了变化
mmc_schedule_delayed_work(&host->detect, delay);
// 间隔delay时间之后,执行工作host->detect
// 这个delay时间用于消抖
}
可以发现,mmc_detect_change最终也是执行mmc_host->detect工作来发起mmc硬件总线扫描的。
- mmc_host->detect
通过前面的说明,可以知道mmc_host->detect才是发起mmc硬件总线扫描的工作的。
那么,这个东西是在哪里被设置又是被设置成什么的呢?这个其实在《[mmc subsystem] mmc core(第四章)——host模块说明》中已经说明过了。
代码如下,去掉无关代码:
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
//...
INIT_DELAYED_WORK(&host->detect, mmc