sdio 热插拔流程

由于SD卡插槽采用的是机械式开关,在插拔卡的时候,机械开关断开、闭合.

系统初始化时,开关检测引脚被设置为上升沿和下降沿触发,因此引脚电平发生变化时,都会有中断产生。当硬件产生中断时,系统进入核心ISR,对开关检测引脚进行检测,返回相应的中断标识码,对于是SD插入还是拔出,则由驱动程序的IST来处理。

由于SD卡插槽采用的是机械式开关,在插拔卡的时候,机械开关断开、闭合时会有抖动,导致SD卡检测引脚的电平不稳定,从而有可能引起对卡的状态的误判。这样会导致加载上层驱动,初始化失败造成系统不稳定。为了使每次插拔只响应一次,必须要采用相应的方法来防止抖动,避开机械开关的抖动时间。

  在驱动程序IST里采用延时采样的方法来避免抖动。 延时采样是IST在收到SD卡检测事件以后,并不是立刻进行引脚信号判断,而是延时一段时间采样,延迟时间要根据系统电路特性而定,然后检测引脚信号,判断插槽的状态是卡插入还是拔出。




当拔出sdio卡的时候,卡座的开关会触发中断,执行中断回调函数mmc_detect_change
,对于工作队列,下半部分是mmc_rescan
INIT_DELAYED_WORK(&host->detect, mmc_rescan);

mmc_detect_change
==>mmc_schedule_delayed_work(&host->detect, delay);
==>host->detect就是mmc_rescan
==>mmc_rescan
==>host->bus_ops->detect(host);//就是mmc_sdio_detect
==>static const struct mmc_bus_ops mmc_sdio_ops.detect = mmc_sdio_detect;
==>mmc_sdio_detect //如果发现卡已经拔走,那么执行
==>mmc_sdio_remove(host);//删除/sys/目录下的文件,同时释放kmalloc到的内存.
==>mmc_detach_bus
==>mmc_bus_put
if ((host->bus_refs == 0) && host->bus_ops)
__mmc_release_bus(host);
==>__mmc_release_bus
==>host->bus_ops = NULL;//这样mmc_rescan的时候,就可以执行对mmc口进行重新检卡操作了.

当卡插入时产生中断,mmc_rescan()函数被执行,然后对卡进行初始化

初始化卡流程:
a、发送CMD0使卡进入IDLE状态
b、发送CMD8,检查卡是否SD2.0。SD1.1是不支持CMD8的,因此在SD2.0 Spec中提出了先发送CMD8,如响应为无效命令,则卡为SD1.1,否则就是SD2.0(请参考SD2.0 Spec)。
c、发送CMD5读取OCR寄存器。
d、发送ACMD55、CMD41,使卡进入工作状态。MMC卡并不支持ACMD55、CMD41,如果这步通过了,则证明这张卡是SD卡。
e、如果d步骤错误,则发送CMD1判断卡是否为MMC。SD卡不支持CMD1,而MMC卡支持,这就是SD和MMC类型的判断依据。
f、如果ACMD41和CMD1都不能通过,那这张卡恐怕就是无效卡了,初始化失败。

ACMD41 命令,这条命令可以用来获取 SDcard 的允许电压范围值,由于这是一条应用命令,所有发送它之前需要发送 CMD_55 命令。执行完后 card 状态变为 READY 获取的电压范围保存在 ocr 中,再调用 mmc_attach_sd(host, ocr) 看这个电压范围是否满足主机的要求,不满足,则 power_off 主机。

mmc_attach_sd 完成匹配,和初始化卡的功能

host->ocr = mmc_select_voltage(host, ocr); 看是否匹配,如果匹配则做下面初始化工作

mmc_sd_init_card(host, host->ocr, NULL); 我们分析该函数

( 1 ) mmc_all_send_cid ()这个函数发生 CMD2 ,获取卡的身份信息,进入到身份状态

(2)card = mmc_alloc_card(host, &sd_type); 分配一张 SD 类型的 card 结构

(3) 接着调用 mmc_send_relative_add, 获取卡的相对地址,注意一前卡和主机通信都采用默认地址,现在有了自己的地址了,进入到 stand_by 状态

( 4 )通过发送 SEND_CSD (CMD9) 获取 CSD 寄存器的信息,包括 block 长度,卡容量等信息

(5) mmc_select_card(card) 发送 CMD7, 选中目前 RADD 地址上的卡,任何时候总线上只有一张卡被选中,进入了传输状态 ,

( 6 )调用 mmc_app_send_scr 发送命令 ACMD51 获取 SRC 寄存器的内容,进入到 SENDING-DATA 状态

在函数中还将获得的各个卡寄存器的内容解码,并保存到 cmd 结构的相应成员中。

( 7 ) if (host->ops->get_ro(host) > 0 )

mmc_card_set_readonly(card);

通过调用 get_ro(host) 函数,实际上就是 s3cmci_get_ro 函数了。 我们判断是否写保护,如果是的,将 card 状态设置为只读状态