Linux MMC子系统分析(一)——模型分析
在linux内核中,大多数驱动都会遵循设备总线驱动这个模型即device-bus-driver。mmc子系统也不例外,mmc子系统在内核中主要有三个目录,这三个目录也对应了三条虚拟总线。
card:card driver位于最上面的一层,负责驱动mmc core层抽象出来的虚拟card设备,并将其对接到内核的其它framework例如块设备,ttyy以及wireless等,从而实现具体的功能。
core:core层是实现mmc的核心实现,负责抽象host、bus、card等软件实体,并向host层提供统一的API接口,便于编写host controller driver。
host:host位于底层,主要是基于core提供的API框架编写实际操作硬件控制器的驱动代码,这部分是驱动开发人员需要去完成的。Host控制器驱动是以platform驱动的形式实现的,后续文章将以host/sdhci-s3c.c为例做进一步分析。
mmc子系统完全遵照device-bus-driver这个模型来实现的。当一个SD卡或者其他类型的设备接入到控制器时,我们的驱动会进行设备探测添加的流程(具体流程在后续文章中将详细讲述),其最终会触发调用bus中的match、probe等函数。接下来让我们看一下这些函数的具体实现:
mmc_bus_type结构体
static struct bus_type mmc_bus_type = {
.name = "mmc",
.dev_groups = mmc_dev_groups,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
.shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
mmc_bus_match函数中定义了card和card driver中的匹配规则。在设备总线驱动模型中,这个设备和驱动的匹配规则通常是按名字来进行匹配的,如果同名即匹配成功,然后会继续调用probe函数进行后续的工作。但是在mmc子系统中,是一个无条件匹配的bus中的match函数始终返回1。
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
说明当一个设备接入控制器后,会无条件的执行probe函数,那么来看一下probe函数中具体做了什么吧。
static int mmc_bus_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
return drv->probe(card);
}
从代码中可以看见,这里最后是调用了driver中的probe函数,mmc_driver结构体的具体实现在card/block.c中。看一下mmc_driver结构体中具体实现了哪些功能。
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk",
.pm = &mmc_blk_pm_ops,
},
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.shutdown = mmc_blk_shutdown,
};
这里的probe函数对应bus->probe函数中最终调用的那个函数,该函数最终将设备的具体功能,会将SD卡实现为一个块设备。关于快设备的添加,不做相关介绍。
本文介绍了mmc子系统的最基本模型,以及card、bus、card driver三者之间的如何关联在一起。后续文章将分别介绍host驱动的实现、mmc子系统中card的检测方式、card的添加流程等内容。