Linux驱动——mmc card热插拔检测机制(十)
备注:
1. Kernel版本:5.4
2. 使用工具:Source Insight 4.0
3. 参考博客:
[sd card] mmc硬件总线扫描流程(以sd card为例)
文章目录
前言
扫描mmc硬件总线,也就是检测mmc硬件总线上是否有挂载card。更加通俗的,就是卡槽上是否有插入card。
检测机制有如下两种:
- 中断检测
- 轮询检测
卡检测时机
mmc core在如下情况下会去扫描mmc硬件总线:
-
- 启动host时,调用_mmc_detect_change,唤醒host->detect;
-
- cd-gpio中断检测到card状态发送变化,调用mmc_detect_change,唤醒host->detect;
-
- host要求轮询sd card插入状态的情况下,所进行的轮询操作;
启动host时,检测
当启动一个host的时候,并不知道当前是否有card插入,此时需要调用mmc_detect_change来假设card插入状态发生了变化,并且进行第一次扫描mmc硬件总线。
mmc_add_host——>mmc_start_host——>_mmc_detect_change
核心代码如下:
void mmc_start_host(struct mmc_host *host)
{
......
//申请 cd_gpio
mmc_gpiod_request_cd_irq(host);
/* 到这里host已经可以工作了,可以开始进行后续的card操作了 */
_mmc_detect_change(host, 0, false); // 调用mmc_detect_change检测card变化
}
中断检测
底层硬件发现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)
{
/* Schedule a card detection after a debounce timeout */
struct mmc_host *host = dev_id;
struct mmc_gpio *ctx = host->slot.handler_priv;
host->trigger_card_event = true;
// 调用mmc_detect_change对card的插入状态变化进行处理
// 注意,这里ctx->cd_debounce_delay_ms=200,延时了200ms是用来进行消抖
mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms));
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)
{
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
int i;
......
out:
// 当host设置了MMC_CAP_NEEDS_POLL属性时,需要每隔HZ的时间轮询检测host的卡槽状态,
// 调度了host->detect工作,对应就是mmc_rescan
// INIT_DELAYED_WORK(&host->detect, mmc_rescan)
// 这样,通过mmc_schedule_delayed_work(&host->detect, HZ)就会每隔HZ时间就会执行一次mmc_rescan
if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);
}
如何扫描mmc硬件总线
从上述,我们知道了可以通过调用mmc_detect_change和执行host->detect工作来发起mmc硬件总线的扫描。而mmc_detect_change最终也是执行mmc_host->detect工作来发起mmc硬件总线扫描的。
detect task的创建
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
{
......
// 初始化detect工作为mmc_rescan,
// 后续调度host->detect来检测是否有card插入时,
// 就会调用到mmc_rescan
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
......
}
detect task的唤醒
mmc_detect_change:
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
_mmc_detect_change(host, delay, true);
}
EXPORT_SYMBOL(mmc_detect_change);
_mmc_detect_change:
void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq)
{
/*
* If the device is configured as wakeup, we prevent a new sleep for
* 5 s to give provision for user space to consume the event.

3156

被折叠的 条评论
为什么被折叠?



