SD卡驱动分析--基于高通平台

时间:2021-09-04 22:36:56
Android下的SD卡驱动与标准LINUX下的SD卡驱动好像没有太大的区别,这里就以高通的ANDROID 2.3以代表,来简要分析一下LINUX下SD卡驱动的写法。由于小弟的技术有限,分析的有错的地方,请大家指正,可以共同学习


     一.最先来理清一下SD、MMC与SDIO的一些基本概念:    

               (1)  MMC:(Multi Media Card)是较早的一种记忆卡标准,目前已经被 SD 标准所取代。

     (2)  SD:(Secure Digital Memory Card) 是一种 flash memory card 的标准,也就是一般常见的 SD 记卡,已完全兼容MMC标准。

     (3)  SDIO:(Secure Digital Input and Output Card)安全数字输入输出卡。SDIO是在SD标准上定义了一种外设接口,通过SD的I/O接脚来连接外围设备,并且通过SD上的 I/O数据接位与这些外围设备进行数据传输。是目前较热门的技术,目前有很多WIFI、GPS、Bluetooth、radio等模块都有了SDIO接口,也可以被称为“SDIO卡”。

     (4)  接口的工作模式:工作模式是对CPU的控制器来说的,也就是说,CPU可以能过设置一些寄存器来将自身控制器设成置满足外挂设备要求的一种工作方式,即:SDIO工作模式、传统的SD模式以及MMC工作模式。这几种模式我的理解就是对应上面1-3三点的不同的外接设备。因为这三种设备的传输协议是有区别的。兼容关系是:“SDIO卡”> “SD卡”> “MMC卡”,反过来刚不成立。 

     (5) 接口的传输方式:传输方式也是针对CPU的控制器来讲的,一般的CPU控制器都会支持三种传输模式,即:SPI模式、1线模式、4线模式。那么如何才可以保证CPU工作在我们要求的模式以及传输方式呢?就是通过写CPU的控制寄存器来完成的。比如下面会提到的函数msmsdcc_set_ios(struct mmc_host *mmc,struct mmc_ios *ios).

     (6) MMC/SD卡初始化时的指令以及各种状态:在网上找到以下的图片,可以很清楚的反映出SD卡初始化的指令,后面介绍代码时所发送的指令其实也是按照这个顺序来发送的:

                                   SD卡驱动分析--基于高通平台


     二.Android(LINUX)下SD卡驱动的结构层次

     我们知道,LINUX的驱动很喜欢分层,就像IIC以及输入子系统等驱动一样,LINUX下的SD卡驱动也是分了层次的,在我们的代码的kernel/drivers/mmc目录下包含了三个子目录,分别是:host、card、core三个部分:

     HOST部分是针对不同主机的驱动程序,这一部是驱动程序工程师需要根据自己的特点平台来完成的,不过高通发布的CODEBASE里已经帮我们把这部分做好了。

     CORE 部分: 这是整个MMC 的核心存,这部分完成了不同协议和规范的实现,并为HOST 层的驱动提供了接口函数。

     CARD部分:因为这些记忆卡都是块设备,当然需要提供块设备的驱动程序,这部分就是实现了将你的SD 卡如何实现为块设备的。整个SD卡驱动的调用关系可以用如下的图来表示:

                     SD卡驱动分析--基于高通平台                      


     SD卡的一些基本概念这里就讲完了,下一节就主要开始分析代码喽。

三.下面分析一下高通的android2.3的代码中SD卡驱动的流程。

          在kernel中,SD卡是作为平台设备加入到内核中去的,在/kernel/arch/arm/mach-msm/devices-msm7627a.c中:

    

          同时KERNEL启动的过程中在kernel/drivers/mmc/core/core.c文件内会调用static int __init mmc_init(void)函数:

    

    在/kernel/drivers/mmc/card/block.c中调用:

  


    在kernel/drivers/mmc/host/msm_sdcc.c文件中调用static int__init msmsdcc_init(void),向内核中注册struct platform_driver msmsdcc_driver,这个platform_driver,与之前注册的platform_devices相匹配后调用probe函数:

  /*  …….  */ 中间这段代码主要是从内核空间到用户空间的映射,以及设置一些时钟

  mmc->ops =&msmsdcc_ops; //设置mmc_host的操作函数

  mmc->caps|= plat->mmc_bus_width;

  ret =request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME "(cmd)", host); //申请中断,我们由于没有使用中断脚,所以这里不会调用

   mmc_add_host(mmc);//向系统中添加mmc_host设备,稍后再分析这个函数


 

    然后我们来分析刚才提到的mmc_alloc_host函数:

 

struct mmc_host *mmc_alloc_host(int extra, structdevice *dev)

 -> struct mmc_host*host;

   host =kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);//这里要注意,我们观察mmc_host结构体会发现结构体的最后一个成员unsigned long private[0] ____cacheline_aligned 没有实际意思,仅表示一个地址,而我们正是利用这一点,将mmc_host结构体与上面传进来的msmsdcc_host结构体联系起来的。

   dev_set_name(&host->class_dev,"mmc%d", host->index);

   host->parent= dev;

   host->class_dev.parent= dev;

   host->class_dev.class= &mmc_host_class; //这一段会在sys/class/mmc_host/下建立mmc%d的一个文件

   INIT_DELAYED_WORK(&host->detect,mmc_rescan);//初始化一个工作队列,延时函数为mmc_rescan,这个函数非常重要,后面再分析。

   host->max_segs= 1;

   host->max_seg_size= PAGE_CACHE_SIZE; //后面这些代码是对host进行一个默认的设置,有些设置可能会被上文中的probe函数替换掉

   

   还记得之前在msm_sdcc.c中的msmsdcc_probe函数快结束的时候有mmc_add_host(mmc)这样一个函数吗?下面我们就来分析这个函数:


    好了,刚才说了很多的mmc_rescan函数也等不及了,快来一睹它的真容吧:


    下面以mmc_attach_sd为例来分析:


    到此为止,就完成了整个SD卡起动初始化的过程,在启动初始化完成之后,以后系统要调用SD卡的相动,都会通过之前注册的块设备来一步步的向下调用。

http://blog.csdn.net/dacaozuo/article/details/8163777