作者:拾味馆南湖店微博_328 | 来源:互联网 | 2023-09-07 09:38
目录结构,文件介绍 mmc 子系统目录为 主要包含3个部分的内容 card core host 3个目录的内容,作用分别为: card层:将sd卡实现为块设备 core层:实现不同的协议和规范,为host层的驱动提供了接口函数 host层:手动实现具体的mmc和sd设备
下面将通过代码具体介绍,这几层是如何实现上述功能的
块设备驱动介绍 基本概念 块设备与字符设备的区别: 字符设备按照字符流的方式被有序访问,如串口和键盘就都属于字符设备,如果一个硬件设备是以字符流的方式访问的话,那就应该将它归于字符设备,反过来,如果一个设备是随机(无序的)访问的,那么它就属于块设备。根本区别是它们能否可以被随机访问,也就是说,能否在访问设备时随意的从一个位置跳转到另一个位置。块设备只能以块为单位接受输入和返回输出,而字符设备以字节为单位,只能被顺序读写 从实现角度来看,字符设备的实现比较简单,内核例程和用户态API一一对应,这种映射关系由字符设备的file_operations维护。块设备接口则相对复杂,读写API没有直接到块设备层,而是直接到文件系统层,然后再由文件系统层发起读写请求 bio 请求数据 bio,就是关于描述需要读取信息的请求,很多bio合起来就是request,而管理request的就是请求队列 块设备关键步骤: 注册并申请门牌号: register_blkdev 申请仓库:alloc_disk 申请仓库的关卡:alloc_queue 注册仓库的加工处理函数: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; 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 ; else result_pattern &#61; cmd. resp[ 0 ] & 0xFF ; if ( result_pattern !&#61; test_pattern) return - EIO; return 0 ; }
可以看到在这里组装了&#xff0c;cmd&#xff0c;其中命令为SD_SEND_IF_COND
# define SD_SEND_RELATIVE_ADDR 3 # define SD_SEND_IF_COND 8 # define SD_SWITCH_VOLTAGE 11
这些命令即为&#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;