首页 理论教育Linux内核与设备驱动深度解析:MMC框架

Linux内核与设备驱动深度解析:MMC框架

【摘要】:首先来看看MMC子系统的初始化mmc_init。MMC整体框架如图7-10所示。MMC总线整体框架主要实现了这些功能。MMC设备的管理框架提供了相应的创建和注册接口。

1.总线相关以及核心框架

MMC总线设备相对于I2C和SPI总线要复杂,但是总线框架的思路是一致的。首先来看看MMC子系统的初始化mmc_init。

978-7-111-49426-3-Chapter07-107.jpg

从分析可见,注册了两个bus(分别是mmc bus和sdio bus)和一个class(mmc host class),这里有两种类型的bus是由于MMC连接还需要支持SDIO总线类型,而在MMC框架中就需要实现SDIO总线的功能,其中SDIO总线建立在MMC总线的基础上,所以需要注册两种bus。而注册一个class的原因,与SPI设备管理部分的实现是相同的,这样是为了避免总线控制器的设备进行总线相关的操作。

接下来看看两个总线的信息:

978-7-111-49426-3-Chapter07-108.jpg

关于这两种bus先来了解MMC总线的情况:

978-7-111-49426-3-Chapter07-109.jpg

match直接返回真,所以只要是MMC总线设备就会直接与MMC总线驱动匹配,这样的情况说明MMC总线驱动只有一个,并由系统框架已经提供,可以支持所有的设备,这与MMC总线设备主要作为存储设备相关,存储设备只要提供统一的块设备驱动(mmc block层的驱动)即可。

现在对MMC总线管理的设备还是不清楚,继续看一下probe接口

978-7-111-49426-3-Chapter07-110.jpg

978-7-111-49426-3-Chapter07-111.jpg

从中可见,MMC总线设备主要就是mmc_card,而总线驱动就是mmc_driver,在mmc_driver的probe接口中会对上层的驱动相关的接口进行初始化,建立上层与MMC总线层的关联,主要就是与块设备驱动层的关联。

这样的设计与实现是合理的,因为MMC的设备(包括SD卡设备)主要用于数据存储,所以块设备是最合适的。

而SDIO则不同,SDIO设备可以借助MMC总线连接实现不同的功能,下面看看SDIO总线的相关接口:

978-7-111-49426-3-Chapter07-112.jpg

从match中可见,会涉及具体的总线设备与总线驱动的匹配,这是因为SDIO可以有不同的功能,所以需要进行匹配。

SDIO总线管理的设备在内核中主要由sdio_func来表示,而相对应的驱动则由sdio_driv-er来表示。

MMC整体框架如图7-10所示。

978-7-111-49426-3-Chapter07-113.jpg

图7-10 MMC整体框架

从图7-10可见,MMC主要管理两个总线功能:MMC和SDIO。MMC总线功能对应于块设备,而在SDIO总线之上可以是具体功能的设备。通常一个MMC接口只与一个设备进行连接,但是因为允许插拔,所以需要能支持检测、扫描来支持硬件插拔,以及不同功能设备的切换。

MMC总线整体框架主要实现了这些功能。

2.总线控制器相关

在MMC框架中,无论是MMC总线还是SDIO总线,实际的总线控制器都是相同的硬件,只是协议中命令字和状态机的差别。在介绍MMC框架初始代码时见到其中注册了class,以与MMC总线设备进行区分,相应的class就是为总线控制器提供的,MMC框架中总线控制器由mmc_host来表示和管理,细节如下:

978-7-111-49426-3-Chapter07-114.jpg

978-7-111-49426-3-Chapter07-115.jpg

可见主要是对总线控制器的操作能力以及状态进行设置,这些操作能力相关的都是属于相关规范的物理特性,需要通过这些属性标注总线控制器物理能力。另外重要的就是两个操作接口,分别是mmc_host_ops和mmc_bus_ops。

先来看看mmc_host_ops:

978-7-111-49426-3-Chapter07-116.jpg

这里主要是控制和进行传输操作的接口,是进行实际总线控制器操作的接口,真正的传输也是通过总线控制器来完成的。

mmc_bus_ops接口细节如下:

978-7-111-49426-3-Chapter07-117.jpg

需要mmc_bus_ops的原因是因为MMC总线可以支持不同协议规范的设备,这些设备相关的操作是不同的,所以在控制器中提供相应的操作接口,这样在总线设备侦测时就可以根据设备的特点加载合适的操作接口。在相应的操作中,detect是检测设备是否存在,其他大多与电源管理相关,通过规范的命令可以完成相应的操作。

MMC总线控制器框架提供了创建的接口mmc_alloc_host,主要内容如下:

978-7-111-49426-3-Chapter07-118.jpg

978-7-111-49426-3-Chapter07-119.jpg

主要的操作是分配空间,并初始化与功能相关的work,其中最重要的是探测设备的work,相应的操作是mmc_rescan,后面会进行介绍。

接下来的接口是注册并初始化控制器硬件的接口mmc_add_host,详细内容如下:

978-7-111-49426-3-Chapter07-120.jpg

在调用mmc_add_host之前,需要将mmc_host_ops初始化,并将控制器的相关属性进行正确设置。其中最重要的操作就是mmc_start_host,会通过mmc_detect_change唤醒控制器的detect work,最终会通过mmc_rescan来进行设备探测,这实现了MMC总线设备发现的重要功能,详细分析如下:

978-7-111-49426-3-Chapter07-121.jpg

978-7-111-49426-3-Chapter07-122.jpg

978-7-111-49426-3-Chapter07-123.jpg

978-7-111-49426-3-Chapter07-124.jpg(www.chuimin.cn)

可见主要的工作就是探测设备,并在探测成功后通过mmc_attach_xxx来初始化总线控制器的busops接口,并对总线设备进行初始化操作。

这样总线的主要功能,包括总线传输事务以及总线设备发现,就都在代表MMC总线的MMC总线控制器部分有了完整支持。

3.总线设备相关

前面已经提及,MMC总线设备管理由mmc_card来完成。下面具体介绍:

978-7-111-49426-3-Chapter07-125.jpg

978-7-111-49426-3-Chapter07-126.jpg

从中可见,为了支持MMC/SD/SDIO等不同的协议规范,其中的属性都在mmc_card中进行了表示,具体的类型和对应的属性都会在设备发现阶段进行初始化。

MMC设备的管理框架提供了相应的创建和注册接口。首先来了解创建的接口mmc_alloc_card:

978-7-111-49426-3-Chapter07-127.jpg

978-7-111-49426-3-Chapter07-128.jpg

主要进行设备模型相关的设置。下面的接口是用于注册的,详细内容如下:

978-7-111-49426-3-Chapter07-129.jpg

可见主要的工作与设备模型相关,当向设备模型注册了device之后,就会通过总线来进行驱动的probe操作。对MMC驱动,之前已经说明只有MMC block提供的mmcblk驱动,详细内容如下:

978-7-111-49426-3-Chapter07-130.jpg

主要与块设备层关联的工作是由mmc_blk_probe来完成的,下面来看看细节:

978-7-111-49426-3-Chapter07-131.jpg

从分析中可见,通过mmcblk驱动就可以将MMC设备与块驱动层建立关联,进而可以被文件系统和应用使用。至于request queue的操作,在MMC block层mmc_init_queue中单独创建了kthread进行相应操作:

978-7-111-49426-3-Chapter07-132.jpg

在mmc_queue_thread中则从request queue中获得request再通过mmc_queue的issue_fn接口即mmc_blk_issue_rq来真正执行相应的request。这样MMC作为存储设备的功能就完整了。

SDIO总线设备由sdio_func进行管理,其详细内容就不进行分析了,与mmc_card类似,包含一些属性,但是由于SDIO中的data0可以作为中断源,所以其中包含中断的属性,总线控制器与mmc_card没有差别,所以不需要单独关联。MMC框架也提供了创建和注册SDIO设备的接口。先来看看创建的接口sdio_alloc_func:

978-7-111-49426-3-Chapter07-133.jpg

从分析中可见,SDIO设备并不是修改mmc_card中的dev属性,而是拥有单独设备模型实体,在设备层次中其父设备是mmc_card,这与设备的逻辑层次相符,而mmc_card在sdio_func中起到了中介作用。

再来看看设备注册的接口sdio_add_func:

978-7-111-49426-3-Chapter07-134.jpg

可见主要的操作也是向设备模型进行注册,注册后就通过总线操作查找匹配的驱动并绑定,就可实现其相关功能。

对不同规范类型的设备,MMC框架通过mmc_xxx_init_card和mmc_attach_xxx等接口封装了以上的操作来实现设备的创建与注册,这些都是在设备发现阶段完成的。

在设备发现阶段MMC主要依靠探测发现的方式进行,当card有插拔的时候同样需要进行设备的重新发现与探测,MMC框架为这种情况提供了接口mmc_detect_change,其中会唤醒总线控制器的detect操作即mmc_rescan来重新detect总线设备的情况,并根据当前设备情况进行相关操作。

4.总线传输接口

MMC框架是通过mmc_re quest管理MMC总线传输,细节如下:

978-7-111-49426-3-Chapter07-135.jpg

在总线层所有的传输都是通过mmc_request来进行实际操作。具体的接口是mmc_wait_for_req,下面来看看细节:

978-7-111-49426-3-Chapter07-136.jpg

可见主要是以同步的方式进行总线传输操作的,具体操作的发起是通过mmc_start_re-quest来完成的,细节如下:

978-7-111-49426-3-Chapter07-137.jpg

978-7-111-49426-3-Chapter07-138.jpg

总线传输基本操作是先发送命令,然后进行数据操作,接下来结束命令。实际操作中后两步可选,在完整的操作中任何一步有了问题都会导致整个操作失败,相应的mmc_request中同样分为三步,并在三步的实体中都关联到mmc_request来保证正确处理。块设备的传输最终直接调用mmc_wait_for_req来完成。

除了数据等稍微复杂的传输操作之外,MMC框架对简单的命令发送还提供了mmc_wait_for_cmd接口来执行相关操作。细节如下:

978-7-111-49426-3-Chapter07-139.jpg

978-7-111-49426-3-Chapter07-140.jpg

可见主要的操作就是对mmc_wait_for_req的简单封装,其中主要是为了命令的操作。

MMC/SD/SDIO规范中都规定了一些特殊的操作和命令,虽然这些操作最终都是通过以上的接口执行的,但是为了方便开发MMC框架分别提供了相应的接口进行相关操作,具体的操作可以参考规范的说明。具体的接口如下:

978-7-111-49426-3-Chapter07-141.jpg

这样整个命令操作以及传输功能就完整了。