以下整理自Jollen 筆記(非教學文件),許多地方未能清楚交待,這部份有請大家自行補齊了。以下整理自Jollen笔记(非教学文件),许多地方未能清楚交待,这部份有请大家自行补齐了。 本文分享給有志研究Linux MMC驅動程式實作(MMC Core)的朋友參考。本文分享给有志研究Linux MMC驱动程式实作(MMC Core)的朋友参考。 以下分析基於Linux 2.6.17.7,更新版本的kernel 加入了許多patch(例如Linux 2.6.19 的SDHC patch ),這些更新內容不在討論之列。以下分析基于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(open source)的SD/MMC/SDIO支援现况概要 」所提到的,目前的Linux SD/MMC/SDIO 「严格来说」,只支援MMC记忆卡,如果是要插上SD记忆卡,使用上则会有诸多限制。
由Linux 驅動程式的角度來看,單就MMC 的部份來分析的話,Linux 的SD/MMC 驅動程式層包含以下實作( Kconfig ):由Linux驱动程式的角度来看,单就MMC的部份来分析的话,Linux的SD/MMC驱动程式层包含以下实作( Kconfig ):
- CONFIG_MMC CONFIG_MMC
- CONFIG_MMC_BLOCK CONFIG_MMC_BLOCK
相關檔案位於drivers/mmc/目錄,我們由Makefile來找到實作檔案:相关档案位于drivers/mmc/目录,我们由Makefile来找到实作档案:
# # # Core # Core # # obj-$(CONFIG_MMC) += mmc_core.o obj-$(CONFIG_MMC) += mmc_core.o # # # Media drivers # Media drivers # # obj-$(CONFIG_MMC_BLOCK) += mmc_block.o obj-$(CONFIG_MMC_BLOCK) += mmc_block.o # # # Host drivers # Host drivers # # obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_ARMMMCI) += mmci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_PXA) += pxamci.o obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_IMX) += imxmmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
Host controller 驅動程式的部份先不討論,MMC Core API 層的實作檔案整理如下: Host controller驱动程式的部份先不讨论,MMC Core API层的实作档案整理如下:
- drivers/mmc/mmc.c :主要的MMC command 與protocol 實作。 drivers/mmc/mmc.c :主要的MMC command与protocol实作。
- drivers/mmc/mmc_queue.c :I/O Request Queue 的實作。 drivers/mmc/mmc_queue.c :I/O Request Queue的实作。
- drivers/mmc/mmc_sysfs.c :Linux 2.6 的kobject與sysfs實作。 drivers/mmc/mmc_sysfs.c :Linux 2.6的kobject与sysfs实作。
- drivers/mmc/mmc_block.c :區塊層架構實作,即interface to user-space 的file operation 部份。 drivers/mmc/mmc_block.c :区块层架构实作,即interface to user-space的file operation部份。
由此可知,MMC Core 層包含以下原始程式碼:由此可知,MMC Core层包含以下原始程式码:
- drivers/mmc/mmc.c drivers/mmc/mmc.c
- drivers/mmc/mmc_queue.c drivers/mmc/mmc_queue.c
- drivers/mmc/mmc_sysfs.c drivers/mmc/mmc_sysfs.c
區塊層部份, mmc_block.c以devfs 的方式向kernel 註冊:区块层部份, mmc_block.c以devfs的方式向kernel注册:
static struct mmc_driver mmc_driver = { static struct mmc_driver mmc_driver = { .drv = { .drv = { .name = "mmcblk", .name = "mmcblk", }, }, .probe = mmc_blk_probe, .probe = mmc_blk_probe, .remove = mmc_blk_remove, .remove = mmc_blk_remove, .suspend = mmc_blk_suspend, .suspend = mmc_blk_suspend, .resume = mmc_blk_resume, .resume = mmc_blk_resume, }; }; static int __init mmc_blk_init(void) static int __init mmc_blk_init(void) { { int res = -ENOMEM; int res = -ENOMEM; res = register_blkdev(major, "mmc"); res = register_blkdev(major, "mmc"); if (res < 0) { if (res < 0) { printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n", printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n", major, res); major, res); goto out; goto out; } } if (major == 0) if (major == 0) major = res; major = res; devfs_mk_dir("mmc"); devfs_mk_dir("mmc"); return mmc_register_driver(&mmc_driver); return mmc_register_driver(&mmc_driver); out: out: return res; return res; } } ... ... module_init(mmc_blk_init); module_init(mmc_blk_init);
mmc_register_driver()向MMC Core 層註冊,接著MMC Core 再對kobject做註冊。 mmc_register_driver()向MMC Core层注册,接着MMC Core再对kobject做注册。 學過Linux 2.6 驅動程式的朋友都曉得,Core API 層必須呼叫driver_register()向kobject註冊為Driver ;對於底層(machine-dependent)的host controller 驅動程式而言,則必須向kobject註冊為Platform Driver 。学过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)。由于kobject会callback fops的probe method,所以mmc_blk_probe()函数就是MMC区块层的进入点(entry point)。 所以,MMC 區塊層的一切動作就要由mmc_blk_probe()函數看起。所以,MMC区块层的一切动作就要由mmc_blk_probe()函数看起。 Linux 2.6.17.7 的MMC 區塊層使用到大家所熟悉的genhd.c層。 Linux 2.6.17.7的MMC区块层使用到大家所熟悉的genhd.c层。
至於Linux 區塊層驅動程式最重要的「初始化I/O request queue」動作,則是同樣在mmc_blk_probe()階段呼叫到MMC Core 層的mmc_init_queue()來完成。至于Linux区块层驱动程式最重要的「初始化I/O request queue」动作,则是同样在mmc_blk_probe()阶段呼叫到MMC Core层的mmc_init_queue()来完成。
了解Linux 的MMC 整體架構後,便能開始深入研究「規格的實作」部份。了解Linux的MMC整体架构后,便能开始深入研究「规格的实作」部份。