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

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

  1. static void __init msm7x2x_init(void)
  2. -> static void __init msm7x27a_init_mmc(void)
  3. -> msm_add_sdcc(1, &sdc1_plat_data); //devices-msm7627a.c中,其中sdc1_plat_data结构体中定义了平台相关的一些资源,比如检测脚号等,当然我们这里没有定义检测脚号。
  4. -> pdev = msm_sdcc_devices[controller-1];
  5. pdev->dev.platform_data = plat;
  6. return platform_device_register(pdev);  //在这里会向内核的platform bus总线上挂载SD卡的平台设备

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

  1. static int __init mmc_init(void)
  2. -> ret = mmc_register_bus();//向系统中注册MMC BUS
  3. ret = mmc_register_host_class();//向系统中添加mmc_host这个class类
  4. ret = sdio_register_bus();//向系统中注册SDIO BUS,我们所使用的SD卡没有使用这个SDIO BUS,至于原因我还不清楚,有待继续学习。

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

  1. static int __init mmc_blk_init(void)
  2. ->res=register_blkdev(MMC_BLOCK_MAJOR,"mmc");   //申请块设备号
  3. res = mmc_register_driver(&mmc_driver); //向系统中注册mmc_driver,会msm_sdcc.c中注册的mmc_device相匹配后会调probe函数static int mmc_blk_probe(struct mmc_card *card)来申请一个块设备文件,最终SD卡所有的驱动都是通过这个块设备文件来调用的,也就是说,这个块设备文件是KERNEL与上层的接口。

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

  1. static int msmsdcc_probe(struct platform_device *pdev)
  2. -> struct mmc_platform_data *plat = pdev->dev.platform_data
  3. for (i = 0; i < pdev->num_resources; i++) //获取平台相关信息
  4. mmc=mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); //分配mmc_host结构体,同时嵌入msmsdcc_host结构体,这样方便以后由这两个结构体互相找到对方。mmc_host这个结构体是串联整个SD卡驱动的核心,需要特别注意。同时mmc_alloc_host这个函数很重要,稍后再来分析。
  5. host = mmc_priv(mmc);
  6. host->mmc = mmc;  //这里就是在两个结构体中相互转换                                                            <p>     /*  …….  */    中间这段代码主要是从内核空间到用户空间的映射,以及设置一些时钟</p><p>     mmc->ops =&msmsdcc_ops; //设置mmc_host的操作函数</p><p>     mmc->caps|= plat->mmc_bus_width;</p><p>     ret =request_irq(core_irqres->start, msmsdcc_irq, IRQF_SHARED, DRIVER_NAME "(cmd)", host); //申请中断,我们由于没有使用中断脚,所以这里不会调用</p><p>     mmc_add_host(mmc);//向系统中添加mmc_host设备,稍后再分析这个函数</p>

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

  1. <p>struct mmc_host *mmc_alloc_host(int extra, structdevice *dev)</p><p> -> struct mmc_host*host;</p><p>    host =kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);//这里要注意,我们观察mmc_host结构体会发现结构体的最后一个成员unsigned long private[0] ____cacheline_aligned 没有实际意思,仅表示一个地址,而我们正是利用这一点,将mmc_host结构体与上面传进来的msmsdcc_host结构体联系起来的。</p><p>    dev_set_name(&host->class_dev,"mmc%d", host->index);</p><p>    host->parent= dev;</p><p>    host->class_dev.parent= dev;</p><p>    host->class_dev.class= &mmc_host_class; <span style="font-family: KaiTi_GB2312; ">//这一段会在sys/class/mmc_host/下建立mmc%d的一个文件</span></p><p>    INIT_DELAYED_WORK(&host->detect,mmc_rescan);//初始化一个工作队列,延时函数为mmc_rescan,这个函数非常重要,后面再分析。</p><p>    host->max_segs= 1;</p><p>    host->max_seg_size= PAGE_CACHE_SIZE; <span style="font-family: KaiTi_GB2312; ">//后面这些代码是对host进行一个默认的设置,有些设置可能会被上文中的probe函数替换掉</span></p>

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

  1. int mmc_add_host(struct mmc_host *host)
  2. -> err = device_add(&host->class_dev);
  3. -> dev_set_name(dev, "%s", dev->init_name);
  4. error = device_create_file(dev, &uevent_attr);
  5. error = bus_add_device(dev);
  6. //是不是有一种很亲切的感觉呢,对了,这里就是在添加一个mmc_host的devices,会与block.c中注册的mmc_driver相匹配
  7. mmc_start_host(host);
  8. -> mmc_power_off(host);
  9. -> mmc_set_ios(host);
  10. -> host->ops->set_ios(host, ios);//看到了吗,调用的是msm_sdcc.c中设置的struct mmc_host_ops msmsdcc_ops中的set_ios设置寄存器
  11. mmc_detect_change(host, 0);
  12. -> mmc_schedule_delayed_work(&host->detect, delay); //这里调用host的工作队列,而这里delay就是上面添加的mmc_rescan函数,即调用此函数

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

  1. void mmc_rescan(struct work_struct *work)
  2. -> struct mmc_host *host = container_of(work, struct mmc_host, detect.work);//这个函数在LINUX里经常会用到,是内核黑客为了方便我们由一个结构体里一个成员的指针来得到整个结构体的指针所写的一个函数,非常有用
  3. if (host->bus_ops && host->bus_ops->detect && !host->bus_dead && !(host->caps & MMC_CAP_NONREMOVABLE)) //这段是在系统唤醒的时候(由于在开机时已经设置了bus_ops)才会调用,所以KERNEL刚起的时候不会调用
  4. mmc_rescan_try_freq(host, host->f_min)
  5. -> mmc_power_up(host);//与上文分析的power_down类似
  6. sdio_reset(host)//好像是让SDIO总线回到初始状态,我不是太清楚
  7. mmc_go_idle(host)
  8. -> cmd.opcode = MMC_GO_IDLE_STATE//即发送CMD0使SD卡处于IDLE状态
  9. mmc_send_if_cond(host, host->ocr_avail)
  10. -> cmd.opcode = SD_SEND_IF_COND//这个命令是专门为SD2.0协议的设备初始化使用的,只有SD2.0才支持这个命令
  11. if (!mmc_attach_sdio(host))
  12. if (!mmc_attach_sd(host))
  13. if (!mmc_attach_mmc(host)) //这里依次判断外设是SDIO卡,SD卡或MMC卡中的哪一种,由于三种设备的协议会有一些差别,所以判断出来是哪一种设备后才好调用相应的操作函数

下面以mmc_attach_sd为例来分析:

  1. int mmc_attach_sd(struct mmc_host *host)
  2. -> err = mmc_send_app_op_cond(host, 0, &ocr)  //发送CMD41来获取SD卡所支持的电压范围
  3. mmc_sd_attach_bus_ops(host)
  4. -> bus_ops = &mmc_sd_ops //设置host->bus_ops
  5. mmc_sd_init_card(host, host->ocr, NULL)
  6. -> err = mmc_sd_get_cid(host, ocr, cid, &rocr)
  7. -> err = mmc_all_send_cid(host, cid) //发送CMD2以获取卡的身份信息
  8. card = mmc_alloc_card(host, &sd_type) //分配一张SD结构的card
  9. mmc_send_relative_addr(host, &card->rca)//获取卡的相对地址
  10. err = mmc_sd_get_csd(host, card) //获取卡的寄存器的信息,包括 block 长度,卡容量等信息
  11. err = mmc_select_card(card) //发送 CMD7, 选中目前 RADD 地址上的卡,任何时候总线上只有一张卡被选中,进入了传输状态
  12. err = mmc_sd_setup_card(host, card, oldcard != NULL)
  13. -> err = mmc_app_send_scr(card, card->raw_scr)
  14. if (host->ops->get_ro) //判断是否有写保护,若有设置为只读卡
  15. err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4) //设置传输模式的总线宽度

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

SD卡驱动分析(二)的更多相关文章

  1. SD卡驱动分析(一)

    Android下的SD卡驱动与标准LINUX下的SD卡驱动好像没有太大的区别,这里就以高通的ANDROID 2.3以代表,来简要分析一下LINUX下SD卡驱动的写法.由于小弟的技术有限,分析的有错的地 ...

  2. sd 卡驱动--基于高通平台

    点击打开链接 内容来自以下博客: http://blog.csdn.net/qianjin0703/article/details/5918041 Linux设备驱动子系统第二弹 - SD卡 (有介绍 ...

  3. 使用FreeRTOS在SD卡驱动使用非系统延时导致上电重启不工作的情况

    一.问题描述在一个使用FreeRTOS的工程中,只做了SD卡的驱动,由于RTOS使用了Systick,故非系统延时函数使用的是 DWT中的时钟周期(CYCCNT)计数功能,但是在SD卡驱动中使用了这个 ...

  4. [MMC]Linux MMC/SD/SDIO驱动分析

    转自:http://www.cnblogs.com/cslunatic/p/3678045.html 一.SD/MMC/SDIO概念区分 SD(SecureDigital)与 MMC(Multimed ...

  5. linux驱动基础系列--Linux mmc sd sdio驱动分析

    前言 主要是想对Linux mmc子系统(包含mmc sd sdio)驱动框架有一个整体的把控,因此会忽略某些细节,同时里面涉及到的一些驱动基础,比如平台驱动.块设备驱动.设备模型等也不进行详细说明原 ...

  6. tiny4412 --Uboot移植(6) SD卡驱动,启动内核

    开发环境:win10 64位 + VMware12 + Ubuntu14.04 32位 工具链:linaro提供的gcc-linaro-6.1.1-2016.08-x86_64_arm-linux-g ...

  7. NUC972当检测到sd卡时,在sd卡驱动中操作gpio开启sd卡的电源,解决sd卡因低电压有时识别不正常的问题

    1.根据硬件原理图,找到对应控制sd卡电源的gpio引脚,并在sd卡驱动文件中定义操作改该引脚的宏 2.在sd卡检测函数中,使用glib增加开sd卡电源的操作,如此当sd卡每次被检测到时,驱动中就会自 ...

  8. Linux SD卡驱动开发(四) —— SD 控制器之真正的硬件操作

    前面对SD卡控制器有了一个主要的介绍.事实上SD控制器层更过的意义是为core层提供一种操作SD卡硬件的一种方法.当然不同的控制器对硬件控制的方法不尽同样,可是他们终于都能像core层提交一个统一的封 ...

  9. (linux)MMC 卡驱动分析

    最近花时间研究了一下 MMC 卡驱动程序,开始在网上找了很多关于 MMC 卡驱动的分析文章,但大都是在描述各个层,这对于初学者来讲帮助并不大,所以我就打算把自己的理解写下来,希望对大家有用.个人觉得理 ...

随机推荐

  1. paper 33 :[教程] 如何使用libsvm进行分类

    文章来源:http://www.matlabsky.com/thread-12379-1-1.html 这篇文章的讲解的真的是言简意赅,很简单的例子就把这个入门的门槛降低了不少,目前的情况是,我都晓得 ...

  2. paper 30 :libsvm的参数说明

    English: libsvm_options: -s svm_type : set type of SVM (default 0) 0 -- C-SVC 1 -- nu-SVC 2 -- one-c ...

  3. 在IIS站点中Adomd.net集成认证账号问题

    最近在做一个Asp.net项目的时候 ,在C#代码里面用到了Adomd.net去连接SSAS服务器做MDX查询,开发完成后将Asp.net代码部署到IIS后发现Adomd.net老是连接不到SSAS服 ...

  4. Servlet工作原理(转)

    Servlet运行在Servlet容器中,由容器负责Servlet实例的查找及创建工作,并按照Servlet规范的规定调用Servlet的一组方法,这些方法也叫生命周期的方法.具体调用过程如下图所示: ...

  5. android 应用架构随笔四(View、ViewGroup)

    View表示了用户界面的基本构建模块. 一个View占用了屏幕上的一个矩形区域并且负责界面绘制和事件处理.手机屏幕上所有看得见摸得着的都是View. Activity是四大组件中唯一一个用来和用户进行 ...

  6. api-ms-win-crt-runtimel1-1-0.dll缺失的解决方案

    api-ms-win-crt-runtime就是MFC的运行时环境的库, 在windows上编译也是用微软的visual studio C++编译的软件, 底层也会用到微软提供的C++库和runtim ...

  7. JSP直接连接sql2008数据库并显示

    <%@ page contentType="text/html; charset=utf-8" language="java" errorPage=&qu ...

  8. 使用磁盘为Linux添加swap

    一.SWAP 说明 1.SWAP 概述 当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用.那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放 ...

  9. MySQL对于数据库应该如何如何配置安全问题了

    mysql 是完全网络化的跨平台关系型数据库系统,同时是具有客户机/服务器体系结构的分布式数据库管理系统.它具有功能强.使用简便.管理方便.运行速度快.安全可靠性强等优点,用户可利用许多语言编写访问m ...

  10. 提高PHP性能的实用方法+40个技巧优化您的PHP代码

    1.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的"函数" ...