04、MMC子系统的组成
1、MMC子系统概括:
Linux
分别从卡(Card Concept
)、总线(Bus Concept
)以及控制器(Host Controller
)三个方面,定义MMC system
的行为:
Bus
:Bus
的虚拟抽象Host Controller
:提供诸如访问card的寄存器、检测card
的插拔、读写card
等操作方法。Card
:抽象具体的MMC
卡
我们以SD
卡为例:
2、块层
目录:/driver/mmc/card
主要是按照块设备驱动程序的框架实现一个设备的块设备驱动,在block.c
中我们可以看到写一个块设备驱动程序时需要的一结构体的定义,其中有open
`release\函数的实现,而
queue.c`则是对内核提供的请求队列的封装。
drivers/mmc/core/block.c
static const struct block_device_operations mmc_bdops = {
.open = mmc_blk_open,
.release = mmc_blk_release,
.getgeo = mmc_blk_getgeo,
.owner = THIS_MODULE,
.ioctl = mmc_blk_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = mmc_blk_compat_ioctl,
#endif
};
2
3
4
5
6
7
8
9
10
3、核心层
核心层/drivers/mmc/core
封装了对mmc/SD
操作的相关命令,例如存储卡设备的识别、设置、读写。例如不管什么设备都应该有一些识别,设置,和读写的命令,这些流程都是必须要有的,只是具体对于不同的设备会有一些各自特有的操作。core.c
文件是由sd.c
、mmc.c
两个文件支撑的,core.c
把MMC
卡、SD
卡的共性抽象出来,它们的差别由sd.c
和sd_ops.c
、mmc
和mmc_ops.c
来完成。
核心层的主要作用是取 得总线,通过总线来控制设备。core.c
文件中有检查总线操作的结构指针bus_ops
,如果该指针为空,则重新利用各总线对端口进行扫描,检测顺序依次为SDIO
设备、SD
卡、MMC
。当检测到相应的卡类型后,就使用把相对应的总线操作与连接起来,之后才能通过总线与控制器联系起来,然后就可以通过总线向控制器发送数据和命令了。
core.h
文件定义:
struct mmc_bus_ops {
void (*remove)(struct mmc_host *);
void (*detect)(struct mmc_host *);
int (*pre_suspend)(struct mmc_host *);
int (*suspend)(struct mmc_host *);
int (*resume)(struct mmc_host *);
int (*runtime_suspend)(struct mmc_host *);
int (*runtime_resume)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
int (*shutdown)(struct mmc_host *);
int (*reset)(struct mmc_host *);
};
2
3
4
5
6
7
8
9
10
11
12
13
14
联系过程:文件:mmc/core/mmc.c
static const struct mmc_bus_ops mmc_ops = {
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
.runtime_suspend = mmc_runtime_suspend,
.runtime_resume = mmc_runtime_resume,
.alive = mmc_alive,
.shutdown = mmc_shutdown,
.reset = mmc_reset,
};
int mmc_attach_mmc(struct mmc_host *host)
{
......
mmc_attach_bus(host, &mmc_ops);
......
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
文件:mmc/core/sdio.c
static const struct mmc_bus_ops mmc_sdio_ops = {
.remove = mmc_sdio_remove,
.detect = mmc_sdio_detect,
.pre_suspend = mmc_sdio_pre_suspend,
.suspend = mmc_sdio_suspend,
.resume = mmc_sdio_resume,
.runtime_suspend = mmc_sdio_runtime_suspend,
.runtime_resume = mmc_sdio_runtime_resume,
.power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive,
.reset = mmc_sdio_reset,
};
int mmc_attach_sdio(struct mmc_host *host)
{
......
mmc_attach_bus(host, &mmc_sdio_ops);
......
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
文件:mmc/core/sd.c
static const struct mmc_bus_ops mmc_sd_ops = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
.runtime_suspend = mmc_sd_runtime_suspend,
.runtime_resume = mmc_sd_runtime_resume,
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
.alive = mmc_sd_alive,
.shutdown = mmc_sd_suspend,
.reset = mmc_sd_reset,
};
int mmc_attach_sd(struct mmc_host *host)
{
......
mmc_attach_bus(host, &mmc_sd_ops);
......
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
4、主机控制器层
主控制器位于drivers/mmc/host
目录中,负责管理设备。不同硬件平台的控制器类型不同,比如常见的sdhci
(安全数字主机控制器接口)和其他类型的控制器,它们的实现方式必然不同。以sdhci.c
为例,它的实现流程是这样的:
初始化设置:首先配置控制器的基础功能,比如注册中断处理函数、完成硬件初始化等基础操作。
向核心层注册:将自己提供的功能通过一个叫
mmc_host_ops
的结构体"介绍"给MMC核心层。这个结构体像一个功能目录,里面列出了控制器能执行的所有操作(例如读写、状态查询等)对应的函数。核心层调用:当核心层需要操作硬件时,它不会直接调用控制器的具体代码,而是通过这个"功能目录"里的函数指针间接执行。这样核心层就像使用标准化接口一样操作不同控制器,而无需关心底层硬件差异。
这就像餐厅点餐:mmc_host_ops
就是菜单,核心层通过菜单点菜(调用功能),而具体厨房(控制器驱动)如何烹饪则完全隐藏。这种设计让核心代码与硬件细节彻底分离,保证了系统的灵活性和扩展性。
(注:具体实现细节在host.c
文件中)
struct mmc_host_ops {
void (*request)(struct mmc_host *host, struct mmc_request *req);
void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
int (*get_ro)(struct mmc_host *host);
};
2
3
4
5