EMMC 驱动

本文详细介绍了Linux系统中EMMC驱动的工作原理和流程,包括块设备驱动的基础知识、驱动程序分析,以及从卡的检测到数据读取的整个过程。通过分析EMMC驱动的各个层次,如区块层、核心层和主机控制器层,揭示了Linux块设备驱动的构架,特别是对mmc_alloc_host、mmc_add_host、mmc_rescan等关键函数的作用进行了深入解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        块设备是Linux最复杂的设备之一,但是作为执着于知其然的Geek,我们总会把代码翻个遍,把道理弄个透。当然了,快速地学习一种新的东西,方法是最重要的,个人觉得: 内核当中 MMC/SD 卡驱动程序构架是学习EMMC 驱动程序的重点,只有理解了它才能真正理解该块设备驱动程序,同时才能真正理解 LINUX 块设备驱动程序。

 

一.需要的基础知识:

1.       LINUX 设备驱动的基本结构。

2.       块设备驱动程序的基本构架(相信研究过 LDD3 当中的 sbull 的人应该都不成问题,如果只是走马观花的话,那可得好好再补补了)

3.       LINUX 设备驱动模型。

4.       EMMC的原理,是Nand Flash的基础上加上一个负责:ECC、负载均衡和坏块管理功能的controler。

 

二.驱动程序分析

       首先,说明一下EMMC驱动涉及到的文件。另外,我们重点是分析驱动程序的基本构架,所以不同内核版本的差异并不是很大。 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 函数的,可是在哪里呢?没有看到,那是不是这个 s3cmci_driver_2410 当中给的 probe 函数就不执行了???当然不是, mci 接口一般都是硬件做好的(我认为是这样),所以在系统启动时一定会有调用 platform_device­_register 对板上的资源进行注册,如果没有这个硬件资源,那我们这个驱动也就没有用了。好,我们就假定是有 mci 接口的,而且也有与 s3cmci_driver_2410 对应的硬件资源注册了,那自己就会去跑 probe 函数。来看一下 s3cmci_driver_2410:

static struct platform_driver s3cmci_driver_2410 = {

       .driver.name    = "s3c2410-sdi",

       .probe            = s3cmci_probe_2410,

       .remove          = s3cmci_remove,

       .suspend  = s3cmci_suspend,

       .resume          = s3cmci_resume,

};

 

我们到 s3cmci_probe_2410 函数中看,还是干脆直接看 s3cmci_probe 算了:

static int s3cmci_probe(struct platform_device *pdev, int is2440) // 来自 /host/s3cmci.c

{

       struct mmc_host   *mmc;

       struct s3cmci_host       *host;

 

       int ret;

……

       mmc = mmc_alloc_host (sizeof(struct s3cmci_host), &pdev->dev);

       if (!mmc) {

              ret = -ENOMEM;

              goto probe_out;

       }

……

       mmc->ops     = &s3cmci_ops;

……

       ret = mmc_add_host (mmc);

       if (ret) {

              dev_err(&pdev->dev, "failed to add mmc host./n");

              goto free_dmabuf;

       }

……

       platform_set_drvdata(pdev, mmc);

       return 0;

……

}

 

这个函数很长,做的事件也很多,但我们关心的整个驱动的构架 / 流程,所以过滤掉一些细节的东西,只看 2 个最重要的函数: mmc_alloc_host 、 mmc_add_host 。函数命名已经很形象了,前者是申请一个 mmc_host ,而后者是添加一个 mmc_host 。中间还有一个操作,就是给 mmc 的 ops  成员赋上了 s3cmci_ops 这个值。申请 mmc_host 当然很简单,就是申请一个结构体(我们暂且这样认为,因为他里面还做的其它事情,后面会看到),而添加又是添加到哪里去呢?看 mmc_add_host 函数:

int mmc_add_host(struct mmc_host *host) // 来自 core/host.c

{

       int err;

……

       err = device_add(&host->class_dev);

       if (err)

              return err;

 

       mmc_start_host(host);

       return 0;

}

 

很简单,就是增加了一个 device ,然后就调用 mmc_start_host 了,那就先跳过 device_add 这个动作,来看 mmc_start_host:

void mmc_start_host(struct mmc_host *host) // 来自 /host/core.c

{

       mmc_power_off(host);                // 掉电一下

       mmc_detect_change(host, 0);              // ???

}

看上去只有两行代码,不过浓缩才是精华, mmc_power_off(host) 光看名子都知道是在干什么,先跳过,来看 mmc_detect_change

### EMMC驱动开发概述 EMMC(嵌入式多媒体卡)是一种广泛应用于移动备中的存储技术。对于EMMC驱动的开发,理解其工作原理至关重要。EMMC通过特定协议与主机通信,在硬件层面涉及复杂的信号交互过程[^1]。 在Linux操作系统环境下,EMMC驱动程序主要负责初始化EMMC控制器、配置寄存器以及实现数据传输功能。为了简化应用程序访问物理存储介质的过程,高层抽象接口被计出来,使得开发者可以更方便地操作EMMC备[^2]。 针对不同应用场景下的需求差异,编写高效的EMMC驱动需要考虑多个方面: - **性能优化**:减少不必要的读写延迟,提高吞吐量; - **稳定性保障**:确保长时间稳定运行,防止意外掉电等情况造成的数据丢失; - **兼容性支持**:适配多种型号的EMMC芯片,满足多样化的产品线要求; ```c // 示例代码片段展示如何探测并注册EMMC备到系统总线上 static int emmc_probe(struct platform_device *pdev) { struct mmc_host *host; host = mmc_alloc_host(sizeof(*host), &pdev->dev); if (!host) return -ENOMEM; // 初始化EMMC控制器... mmc_add_host(host); dev_info(&pdev->dev, "EMMC device probed\n"); return 0; } ``` #### 工具链与调试技巧 当遇到EMMC相关问题时,利用合适的工具链可以帮助快速定位错误根源。常见的工具有JTAG调试器用于实时监控内部状态变化,或者借助开源项目如`mmc-utils`来辅助测试和验证新编写的驱动逻辑是否正确无误[^3]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值