以下整理自 Jollen 笔记(非教学文件),许多地方未能清楚交待,这部份有请大家自行补齐了。本文分享给有志研究 Linux MMC 驱动程序实作(MMC Core)的朋友参考。以下分析基于 Linux 2.6.17.7,更新版本的 kernel 加入了许多 patch(例如 Linux 2.6.19 的 SDHC patch),这些更新内容不在讨论之列。
续前一篇日记「Linux(open source)的 SD/MMC/SDIO 支援现况概要」所提到的,目前的 Linux SD/MMC/SDIO 「严格来说」,只支持 MMC 记忆卡,如果是要插上 SD 记忆卡,使用上则会有诸多限制。
由 Linux 驱动程序的角度来看,单就 MMC 的部份来分析的话,Linux 的 SD/MMC 驱动程序层包含以下实作(Kconfig):
- CONFIG_MMC
- CONFIG_MMC_BLOCK
相关档案位于 drivers/mmc/ 目录,我们由 Makefile 来找到实作档案:
#
# Core
#
obj-$(CONFIG_MMC) += mmc_core.o
#
# Media drivers
#
obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
#
# Host drivers
#
obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_IMX) += imxmmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o
mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
Host controller 驱动程序的部份先不讨论,MMC Core API 层的实作档案整理如下:
- drivers/mmc/mmc.c:主要的 MMC command 与 protocol 实作。
- drivers/mmc/mmc_queue.c:I/O Request Queue 的实作。
- drivers/mmc/mmc_sysfs.c:Linux 2.6 的 kobject 与 sysfs 实作。
- drivers/mmc/mmc_block.c:区块层架构实作,即 interface to user-space 的 file operation 部份。
由此可知,MMC Core 层包含以下原始程序代码:
- drivers/mmc/mmc.c
- drivers/mmc/mmc_queue.c
- drivers/mmc/mmc_sysfs.c
区块层部份,mmc_block.c 以 devfs 的方式向 kernel 注册:
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk",
},
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
};
static int __init mmc_blk_init(void)
{
int res = -ENOMEM;
res = register_blkdev(major, "mmc");
if (res < 0) {
printk(KERN_WARNING "Unable to get major %d for MMC media: %d/n",
major, res);
goto out;
}
if (major == 0)
major = res;
devfs_mk_dir("mmc");
return mmc_register_driver(&mmc_driver);
out:
return res;
}
...
module_init(mmc_blk_init);
mmc_register_driver() 向 MMC Core 层注册,接着 MMC Core 再对 kobject 做注册。学过 Linux 2.6 驱动程序的朋友都晓得,Core API 层必须呼叫 driver_register() 向 kobject 注册为 Driver;对于底层(machine-dependent)的 host controller 驱动程序而言,则必须向 kobject 注册为 Platform Driver。
由于 kobject 会 callback fops 的 probe method,所以 mmc_blk_probe() 函数就是 MMC 区块层的进入点(entry point)。所以,MMC 区块层的一切动作就要由 mmc_blk_probe() 函数看起。Linux 2.6.17.7 的 MMC 区块层使用到大家所熟悉的 genhd.c 层。
至于 Linux 区块层驱动程序最重要的「初始化 I/O request queue」动作,则是同样在 mmc_blk_probe() 阶段呼叫到 MMC Core 层的 mmc_init_queue() 来完成。
了解 Linux 的 MMC 整体架构后,便能开始深入研究「规格的实作」部份。
=================================================================================================
=================================================================================================
Linux(open source)的 SD/MMC/SDIO 支援現況概要
SD(Secure Digital)与 MMC(Multimedia Card)
SD 是一种 flash memory card 的标准,也就是一般常见的 SD 记忆卡,而 MMC 则是较早的一种记忆卡标准,目前已经被 SD 标准所取代。在维基百科上有相当详细的 SD/MMC 规格说明:[http://zh.wikipedia.org/wiki/Secure_Digital]。
SDIO(Secure Digital I/O)
SDIO 是目前我们比较关心的技术,SDIO 故名思义,就是 SD 的 I/O 接口(interface)的意思,不过这样解释可能还有点抽像。更具体的说明,SD 本来是记忆卡的标准,但是现在也可以把 SD 拿来插上一些外围接口使用,这样的技术便是 SDIO。
所以 SDIO 本身是一种相当单纯的技术,透过 SD 的 I/O 接脚来连接外部外围,并且透过 SD 上的 I/O 数据接位与这些外围传输数据,而且 SD 协会会员也推出很完整的 SDIO stack 驱动程序,使得 SDIO 外围(我们称为 SDIO 卡)的开发与应用变得相当热门。
现在已经有非常多的手机或是手持装置都支持 SDIO 的功能(SD 标准原本就是针对 mobile device 而制定),而且许多 SDIO 外围也都被开发出来,让手机外接外围更加容易,并且开发上更有弹性(不需要内建外围)。目前常见的 SDIO 外围(SDIO 卡)有:
- Wi-Fi card(无线网络卡)
- CMOS sensor card(照相模块)
- GPS card
- GSM/GPRS modem card
- Bluetooth card
- Radio/TV card(很好玩)
SDIO 的应用将是未来嵌入式系统最重要的接口技术之一,并且也会取代目前 GPIO 式的 SPI 接口。
SD/SDIO 的传输模式
SD 传输模式有以下 3 种:
- SPI mode(required)
- 1-bit mode
- 4-bit mode
SDIO 同样也支持以上 3 种传输模式。依据 SD 标准,所有的 SD(记忆卡)与 SDIO(外围)都必须支持 SPI mode,因此 SPI mode 是「required」。此外,早期的 MMC 卡(使用 SPI 传输)也能接到 SD 插糟(SD slot),并且使用 SPI mode 或 1-bit mode 来读取。
SD 的 MMC Mode
SD 也能读取 MMC 内存,虽然 MMC 标准上提到,MMC 内存不见得要支持 SPI mode(但是一定要支持 1-bit mode),但是市面上能看到的 MMC 卡其实都有支持 SPI mode。因此,我们可以把 SD 设定成 SPI mode 的传输方式来读取 MMC 记忆卡。
SD 的 MMC Mode 就是用来读取 MMC 卡的一种传输模式。不过,SD 的 MMC Mode 虽然也是使用 SPI mode,但其物理特性仍是有差异的:
- MMC 的 SPI mode 最大传输速率为 20 Mbit/s;
- SD 的 SPI mode 最大传输速率为 25 Mbit/s。
为避免混淆,有时也用 SPI/MMC mode 与 SPI/SD mode 的写法来做清楚区别。
Linux 的 SD/MMC 驱动程序
Linux 2.6.17 正式加入 SD/MMC 驱动程序,「官方版」的 release 当然只能在 ARM 平台上使用,若不讨论 host controller 的支持,目前的 Linux SD/MMC/SDIO 支持状况(Core API)如下(Open source compatible for SD/MMC/SDIO):
1. 支援 MMC。Open source 的实作即是 SD-MMC 的驱动程序。
2. Core API 「可以做到」支持 SD/SPI mode only,因为有办法做到支持 SPI mode,当然 1-bit mode 也「可以想办法」做出来。将 1-bit mode 扩充至 4-bit mode,网络上虽然有人做,不过会有版权问题。
3. SDIO 目前只看到 Atheros Wi-Fi card 的支持(可在 sourceforge 上找到,已正式释出 source code)。
4. 完整的 SD stack 是要付钱的,请特别注意,SD Card Association product license agreement 并「不」允许 open source 的驱动程序实作。所以也不用再问,为什么没有 open source 的 SD 驱动程序了;Linux 是无罪的!
请特别留意的是,以上所述是「官方」的正式支持,并不包含玩家所分享的各种 patch。
=================================================================================================
=================================================================================================
=================================================================================================
=================================================================================================