MMC 子系统概括:
Linux 分别从卡(Card Concept)、总线(Bus Concept)以及控制器(Host Controller)三个方面,定义 MMC system 的行为:

Bus:Bus的虚拟抽象Host Controller:提供诸如访问 card 的寄存器、检测card的插拔、读写card等操作方法。Card:抽象具体的MMC卡
我们以 SD 卡为例:
暂时无法在飞书文档外展示此内容

块层
目录:/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



核心层
核心层 /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
主机控制器层
主控制器位于 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