热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mmc子系统研究

目录结构,文件介绍mmc子系统目录为主要包含3个部分的内容cardcorehost3个目录的内容,作用分别为:card层:

目录结构,文件介绍

mmc 子系统目录为
card  core  host  Kconfig  Makefile
主要包含3个部分的内容 card core host 3个目录的内容,作用分别为:
card层:将sd卡实现为块设备
core层:实现不同的协议和规范,为host层的驱动提供了接口函数
host层:手动实现具体的mmc和sd设备

下面将通过代码具体介绍,这几层是如何实现上述功能的


块设备驱动介绍


基本概念


  1. 块设备与字符设备的区别:
    字符设备按照字符流的方式被有序访问,如串口和键盘就都属于字符设备,如果一个硬件设备是以字符流的方式访问的话,那就应该将它归于字符设备,反过来,如果一个设备是随机(无序的)访问的,那么它就属于块设备。根本区别是它们能否可以被随机访问,也就是说,能否在访问设备时随意的从一个位置跳转到另一个位置。块设备只能以块为单位接受输入和返回输出,而字符设备以字节为单位,只能被顺序读写
    从实现角度来看,字符设备的实现比较简单,内核例程和用户态API一一对应,这种映射关系由字符设备的file_operations维护。块设备接口则相对复杂,读写API没有直接到块设备层,而是直接到文件系统层,然后再由文件系统层发起读写请求
  2. bio 请求数据
    bio,就是关于描述需要读取信息的请求,很多bio合起来就是request,而管理request的就是请求队列

块设备关键步骤:


  1. 注册并申请门牌号: register_blkdev
  2. 申请仓库:alloc_disk
  3. 申请仓库的关卡:alloc_queue
  4. 注册仓库的加工处理函数:blk_queue_make_request

块设备与mmc子系统之间的关系


card层

既然card层实现了块设备,那么我们应该可以从代码中看到,card层必须实现块设备的关键步骤
在card/block.c这个文件中分析probe函数可以得到:

mmc_blk_probe(struct mmc_card *card)-->> mmc_blk_alloc(card)-->> mmc_blk_alloc_req()-->> alloc_disk(perdev_minors);-->> mmc_init_queue(&md->queue, card, &md->lock, subname)-->> blk_init_queue(mmc_request_fn, lock)-->> blk_alloc_queue_node(GFP_KERNEL, node_id);-->> blk_init_queue_node(rfn, lock, NUMA_NO_NODE);-->> blk_init_allocated_queue(uninit_q, rfn, lock);-->> blk_queue_make_request(q, blk_queue_bio);-->> mmc_add_disk(md)

因此可以看出card层,实现了有关块设备的功能。


core层

core层实现的是tf卡的协议:

int mmc_attach_sd(struct mmc_host *host)-->> err = mmc_sd_init_card(host, rocr, NULL);-->> err = mmc_sd_get_cid(host, ocr, cid, &rocr);-->> err = mmc_send_if_cond(host, ocr);-->> int mmc_send_if_cond(struct mmc_host *host, u32 ocr)-->> mmc_wait_for_cmd(host, &cmd, 0);-->> mmc_wait_for_req(host, &mrq);-->> __mmc_start_req(host, mrq);-->> mmc_start_request(host, mrq)-->> __mmc_start_request(host, mrq);-->> host->ops->request(host, mrq);-->> sdhci_send_command (寄存器层面的操作)-->> mmc_wait_for_req_done(host, mrq);

以attach 函数,读取sd卡的id为例,以上为函数调用关系,那么sd的命令在函数
其中mmc_send_if_cond的实现为

int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
{struct mmc_command cmd &#61; {0};int err;static const u8 test_pattern &#61; 0xAA;u8 result_pattern;/* * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND* before SD_APP_OP_COND. This command will harmlessly fail for* SD 1.0 cards.*/cmd.opcode &#61; SD_SEND_IF_COND;cmd.arg &#61; ((ocr & 0xFF8000) !&#61; 0) << 8 | test_pattern;cmd.flags &#61; MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;err &#61; mmc_wait_for_cmd(host, &cmd, 0); if (err)return err;if (mmc_host_is_spi(host))result_pattern &#61; cmd.resp[1] & 0xFF;elseresult_pattern &#61; cmd.resp[0] & 0xFF;if (result_pattern !&#61; test_pattern)return -EIO;return 0;
}

可以看到在这里组装了&#xff0c;cmd&#xff0c;其中命令为SD_SEND_IF_COND

/* This is basically the same command as for MMC with some quirks. */
#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
#define SD_SWITCH_VOLTAGE 11 /* ac R1 */

这些命令即为&#xff0c;sd卡协议的命令


host层

在core层实现的协议&#xff0c;最终如何操作寄存器&#xff0c;真正读取到sd卡的数据&#xff0c;需要通过host层去实现&#xff0c;实现的主要方式为&#xff0c;实现static const struct mmc_host_ops这个结构体。

static const struct mmc_host_ops sdhci_ops &#61; { .request &#61; sdhci_request,.post_req &#61; sdhci_post_req,.pre_req &#61; sdhci_pre_req,.set_ios &#61; sdhci_set_ios,.get_cd &#61; sdhci_get_cd,.get_ro &#61; sdhci_get_ro,.hw_reset &#61; sdhci_hw_reset,.enable_sdio_irq &#61; sdhci_enable_sdio_irq,.start_signal_voltage_switch &#61; sdhci_start_signal_voltage_switch,.prepare_hs400_tuning &#61; sdhci_prepare_hs400_tuning,.execute_tuning &#61; sdhci_execute_tuning,.select_drive_strength &#61; sdhci_select_drive_strength,.card_event &#61; sdhci_card_event,.card_busy &#61; sdhci_card_busy,
};

画图总结

在这里插入图片描述
vfs 请求数据mmc 处理的流程为

static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)-->> mmc_start_req(card->host, areq, (int *) &status);-->> __mmc_start_data_req(host, areq->mrq);-->> mmc_start_request(host, mrq);-->> __mmc_start_request(host, mrq);-->> host->ops->request(host, mrq);-->> sdhci_send_command &#xff08;寄存器层面的操作&#xff09;

参考的博客

https://blog.csdn.net/t1506376703/article/details/109967119
https://blog.csdn.net/ooonebook/article/details/60883208
https://blog.csdn.net/u011013137/article/details/9092711
https://blog.csdn.net/u013836909/article/details/120913254


有待搞清楚的问题

1、vfs层通过mmc 请求数据&#xff0c;请求完成之后&#xff0c;是如何通知应用程序的&#xff0c;目前查到的资料是通过block的bi_end_io回调函数实现的&#xff0c;这个函数如何使用&#xff0c;在代码里面哪里体现的&#xff1f;


推荐阅读
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
author-avatar
拾味馆南湖店微博_328
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有