<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:842818293; mso-list-type:hybrid; mso-list-template-ids:2112632884 -2073644442 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l0:level1 {mso-level-tab-stop:18.0pt; mso-level-number-position:left; margin-left:18.0pt; text-indent:-18.0pt;} @list l1 {mso-list-id:1002007686; mso-list-type:hybrid; mso-list-template-ids:-769992682 1233822532 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l1:level1 {mso-level-tab-stop:18.0pt; mso-level-number-position:left; margin-left:18.0pt; text-indent:-18.0pt;} @list l2 {mso-list-id:1371537776; mso-list-type:hybrid; mso-list-template-ids:-1736295852 1907118408 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l2:level1 {mso-level-tab-stop:18.0pt; mso-level-number-position:left; margin-left:18.0pt; text-indent:-18.0pt;} @list l3 {mso-list-id:1395010415; mso-list-type:hybrid; mso-list-template-ids:330434622 -1773224718 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l3:level1 {mso-level-text:(%1); mso-level-tab-stop:36.0pt; mso-level-number-position:left; text-indent:-36.0pt;} @list l4 {mso-list-id:1737976426; mso-list-type:hybrid; mso-list-template-ids:1438571354 110250062 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;} @list l4:level1 {mso-level-tab-stop:18.0pt; mso-level-number-position:left; margin-left:18.0pt; text-indent:-18.0pt;} ol {margin-bottom:0cm;} ul {margin-bottom:0cm;} -->
MMC 卡驱动分析
最近花时间研究了一下 MMC 卡驱动程序,开始在网上找了很多关于 MMC 卡驱动的分析文章,但大都是在描述各个层,这对于初学者来讲帮助并不大,所以我就打算把自己的理解写下来,希望对大家有用。个人觉得理解 LINUX 内核当中 MMC/SD 卡驱动程序构架是学习 MMC 卡驱动程序的重点,只有理解了它的基本框架或流程才能真正理解一个块设备驱动程序的写法,同时才能真正理解 LINUX 设备驱动模型是如何发挥作用的。
一.需要的基础知识:
1. LINUX 设备驱动的基本结构。
2. 块设备驱动程序的基本构架(相信研究过 LDD3 当中的 sbull 的人应该都不成问题,如果只是走马观花的话,那可得好好再补补了)
3. LINUX 设备驱动模型。
二.驱动程序分析
首先,来明确一下我们需要分析的文件。下面的文件均来自 linux-2.6.24 源码,我们重点是分析驱动程序的基本构架,所以不同内核版本的差异并不是很大。 MMC/SD 卡驱动程序位于 drivers/mmc 目录下,我们只列出我们分析过程涉及到的几个文件:
Card/
block.c
queue.c/queue.h
core/
bus.c/bus.h
core.c/core.h
host.c/host.h
mmc.c
mmc_ops.c/mmc_ops.h 拿 MMC 卡来分析, SD 卡驱动程序流程类似。
host/
s3cmci.c/s3cmci.h 以 S3C24XX 的 MMC/SD 卡控制器为例,其它类型的控制器类似。
LINUX 当中对目录的划分是很有讲究的,这些文件被分布在 3 个目录下,正好对应 MMC/SD 驱动程序的 3 个层次(关于层的划分这里浏览一下,有个概念即可,当我们分析完了后再回头来看,你会觉得很形象):
(1) 区块层
主要是按照 LINUX 块设备驱动程序的框架实现一个卡的块设备驱动,这 block.c 当中我们可以看到写一个块设备驱动程序时需要的 block_device_operations 结构体变量的定义,其中有 open/release/request 函数的实现,而 queue.c 则是对内核提供的请求队列的封装,我们暂时不用深入理解它,只需要知道一个块设备需要一个请求队列就可以了。
(2) 核心层
核心层封装了 MMC/SD 卡的命令,例如存储卡的识别,设置,读写。例如不管什么卡都应该有一些识别,设置,和读写的命令,这些流程都是必须要有的,只是具体对于不同的卡会有一些各自特有的操作。 Core.c 文件是由 sd.c 、 mmc.c 两个文件支撑的, core.c 把 MMC 卡、 SD 卡的共性抽象出来,它们的差别由 sd.c 和 sd_ops.c 、 mmc.c 和 mmc_ops.c 来完成。
(3) 主机控制器层
主机控制器则是依赖于不同的平台的,例如 s3c2410 的卡控制器和 atmel 的卡控制器必定是不一样的,所以要针对不同的控制器来实现。以 s3cmci.c 为例,它首先要进行一些设置,例如中断函数注册,全能控制器等等。然后它会向 core 层注册一个主机( host ),用结构 mmc_host_ops 描述,这样核心层就可以拿着这个 host 来操作 s3c24xx 的卡控制器了,而具体是 s3c24xx 的卡控制器还是 atmel 的卡控制器, core 层是不用知道的。
驱动程序层次图
好了,对这几个目录有一个大概认识以后,我们来看几个重要的数据结构:
struct mmc_host 用来描述卡控制器
struct mmc_card 用来描述卡
struct mmc_driver 用来描述 mmc 卡驱动
struct mmc_host_ops 用来描述卡控制器操作集,用于从主机控制器层向 core 层注册操作函数,从而将 core 层与具体的主机控制器隔离。也就是说 core 要操作主机控制器,就用这个 ops 当中给的函数指针操作,不能直接调用具体主控制器的函数。
第一阶段:
从 s3cmci_init 开始往下看
static int __init s3cmci_init(void)
{
platform_driver_register(&s3cmci_driver_2410);
}
有 platform_driver_register 函数,根据设备模型的知识,我们知道那一定会有对应的 platform_device_register