LINUX MMC子系统分析之四 MMC host模块概述

       本章主要介绍mmc host相关的内容,包括mmc子系统提供的mmc host相关的接口,以及mmc host与mmc card等子模块的关联等内容。我们按如下几部分进行介绍:

一、相关的数据结构体及关联关系

二、mmc host相关的接口

三、完成一个mmc host驱动需要哪些步骤

 

相关的数据结构及关联

        该模块最重要的数据结构为mmc_host,用于描述一个mmc controller,而围绕着mmc controller又定义了相应的数据结构,用于描述mmc controller的各种行为(包括针对该mmc controller的访问方法抽象而来的数据结构mmc_host_ops、该mmc controller相关的参数抽象而来的数据结构体mmc_ios、针对mmc card相关的电源管理及在位检测方法抽象而来的数据结构mmc_bus_ops)等。

        这些结构体之间的关联如下图所示,这些数据结构以mmc_host为核心,围绕着mmc_host定义了相应的数据结构与方法。它们之间的关联简要说明如下:

  1. mmc_host、mmc_card之间的绑定关系,当通过中断/poll机制检测到mmc_card后,即完成它们之间的绑定工作(通常mmc_rescan完成mmc_card的在位检测等等);
  2. mmc_host的总线相关的参数均定义于mmc_ios中,通过该类型的变量,即可完成mmccontroller的总线配置等;
  3. mmc_host借助mmc_bus_ops中的成员,即可完成针对mmc_card的sleep/awake,即完成mmc card的休眠与唤醒,也支持mmc card的remove,实现mmc card的注销等等功能;
  4. 针对mmc_controller而访问方法,抽象了mmc_bus_ops结构体,该结构体的成员实现mmc_controller的访问方法(主要是request接口),这类似于i2c模块的transfer以及spi模块的spi_sync/spi_async方法,均是controller访问device的方法。

 

 

 

 

mmc_host数据结构

如下mmc_host的定义,该结构体的内容较多,此处忽略了些,主要的定义内容如下:

  1. 定义device类型的变量,主要用来使用设备模型相关的接口,以及在sysfs/下完成对应设备目录及属性文件的创建以及用于与用户层通信相关的event、纳入mmc host class中等等,此处的变量用于借助设备模型与系统中注册的设备、class完成关联等;
  2. 定义mmc_host_ops类型的变量,用于定义本mmc_host的操作接口(包括与mmc card通信的接口request、卡检测相关的接口等);
  3. 定义块设备相关的参数,包括段大小、块大小等等;
  4. 定义mmc_host的能力集相关的参数,包括4bit数据模式、mmc high speed mode、sd high speed mode、spi mode、8bit data、noneremovable mode(emmc mode)、cd与wp引脚的active high/low等等;
  5. 定义mmc_ios类型的变量,主要用于记录该mmc host的总线时钟频率、位宽、模式、电压等信息;
  6. 定义mmc_card类型的变量,主要用于mmc_host与mmc_card的绑定;
  7. 定义mmc_slot类型的变量,主要用于实现卡的在位检测等(目前该成员基本上不使用,只需cd引脚或者poll模式即可进行mmc card的在位检测等),这也是卡的在位检测的一种手段,不过目前大多数mmc_host驱动基本上不使用该变量;
  8. Mmc card检测相关的延迟工作队列(主要用于mmc_rescan机制使用,在mmc_alloc_host中即设置该工作队列的callback为mmc_rescan,该机制支持poll、中断两种方式,针对中断方式,则在各mmc_host的cd引脚对应的中断处理函数中调用mmc_detect_change接口即调度该工作队列的callback;针对poll机制,则只需设置mmc_host的caps变量,置位MMC_CAP_NEEDS_POLL即可)

 

 

Mmc card

该结构体变量的定义如下,主要内容如下:

  1. host完成mmc_card与mmc_host的绑定;
  2. dev完成将该mmc_card与系统中的设备、总线、驱动的关联(即完成与系统设备驱动总线的关联与绑定操作);
  3. 卡类型与卡状态记录
  4. 卡相关的寄存器信息记录(主要从mmc card中读取),包括cid、csd、scr、ssr等内容
  5. Mmc card的分区信息,主要完成块设备的创建(由mmc driver实现)
  6. 若为sdio设备,则有cccr、cis等(关于sdio的部分,请参考sdio协议相关的文档)

 

mmc_ios

      该结构体主要定义mmc总线相关的参数,主要包括时钟频率、电源、总线模式、电源状态、总线带宽、支持的信号电压值等等这些参数的设置可通过mmc_host_ops->set_ios实现

 

 

 

mmc_host_ops

该数据结构定义了mmc_host的操作方法,主要包括如下:

  1. 若mmc_host支持enable、disable,则需要实现这两个接口(可参考mmc_controller的用户手册);
  2. pre_req、request、post_req主要定义了mmc controller访问mmc card的方法,mmc controller驱动至少应完成request接口的定义
  3. set_ios接口主要用于设置mmc_controller总线相关的参数,mmc_host需要完成该接口的定义;
  4. get_ro用于获取mmc card 的读写权限,若mmc controller提供检测mmc card读写权限的功能,则需要提供该接口
  5. get_cd为卡是否在位的检测接口(该接口非必须),可查看mmc controller的用户手册,确定是否支持;
  6. init_card接口为mmc card初始化接口,这个主要是对mmc card/mmc controller一些特定的初始化参数,若没有需要特殊对待项,该接口不需要事先;
  7. 剩下几个接口,大多数驱动也没有实现,这几个接口可参考具体的mmc协议,大多数的mmc host驱动基本上不需要实现。

 

mmc_bus_ops

       该接口主要是针对mmc card的sleep/awake的操作,因mmc card也需要进行sleep/awake等接口,这些接口类似于设备驱动的电源管理(suspend/resume)相关的接口。该结构体中的成员,不需要我们进行实现,mmc子系统已经完成,mmc子系统根据mmc各协议版本针对sleep/awake的支持情况,实现对应的操作:

  1. 若为mmc 4.3及以上的协议,则支持sleep/awake接口;
  2. remove接口实现mmc card的移除操作,主要是解除mmc card与mmc host的绑定,并将mmc card从mmc 总线上移除;
  3. detect/alive主要是卡在位检测以及卡是否移除检测;
  4. 针对suspend/resume接口,针对mmc 不同版本的协议,其功能有所不同:
    1. 若card支持poweroff notify机制,则进入poweroff状态;
    2. 若card支持sleep状态,则进入sleep状态,针对mmc rev>=1.3的情况;
    3. card不支持以上两种状态,则向card发送deselect命令
  1. 针对power_restore接口,即为mmc_power_restore接口,该接口目前即调用mmc_init_card,根据mmc 协议,完成mmc card的初始化操作。

 

 

 

        以上即是mmc host相关的数据结构及其关联。上面没有介绍mmc_request、mmc_command等结构体,这些结构体主要是用于传输mmc相关的命令和数据,这些结构体主要用于完成数据传输的,此处不再详述。

 

 

Mmc host相关的接口

        我们主要从两个方面进行介绍mmc host相关的接口:mmc host的添加、mmc host的移除。我们等下就从这两个方面进行入手。在前面我们已经介绍了mmc_host数据结构及其关联,因此针对mmc host的添加而言,需要对mmc host相关的参数进行初始化,主要包括块设备相关参数的配置、cd/wp相关的接口定义、mmc_host_ops中相应函数的实现(包括request、set_ios、get_ro、get_cd)等,然后调用mmc_add_host将该host对应的device注册至系统的device_kset中,并与mmc_host_class关联。

 

Mmc host的添加

针对mmc host的添加,主要涉及mmc_alloc_host、mmc_add_host这两个接口。

mmc_alloc_host接口分析

该接口主要用于申请一个mmc_host类型的内存空间,并对申请的mmc_host进行初始化,主要内容如下:

  1. 此mmc_host类型变量的内存是动态申请的,该mmc_host内存的释放与否由引用计数mmc_host->class_dev.kobject.kref决定,

   当引用计数为0时,则调用kobject->kobj_type->release进行释放,该接口最终调用mmc_host_class->dev_release接口,实现mmc_host的释放

  1. 调用device_initialize进行mmc_host->class_dev的初始化,主要设置该class_dev所依附的device_kset及kobj_type等(该接口是设备驱动模型中的接口,想详细了解的朋友,请参考之前写的文章),通过设置该class_dev属于mmc_host_class。
  2. 初始化host->detect队列,并设置该队列对应的处理接口为mmc_rescan,用于mmc/sd卡的检测,具体应用如下:
    1. 若该mmc_host支持卡的在位检测(一般通过cd引脚检测,并配置成中断模式),则在中断处理函数中可调用mmc_detect_change,唤醒该延迟工作队列,即调用mmc_rescan实现卡的rescan;
    2. 若mmc_host不支持卡的在位检测功能(即不存在cd引脚检测),则将mmc_host设置为poll模式,在poll模式下,当在执行mmc_add_host时执行一次mmc_rescan时,在mmc_rescan的结尾根据该poll模式,设置延迟调度该队列的时间为1s,则该延迟工作队列以1s为周期进行卡的rescan。

 

  1. 初始化mmc host的块大小、段大小等信息。

 

      针对mmc_alloc_host接口,比较重要的即为上述3中的host->detect队列的初始化,通过对该队列的设置,则可以接入mmc子系统的mmc rescan流程,实现mmc card的rescan功能。

 

 

 

mmc_add_host接口

该接口主要完成将mmc_host对应的class_dev注册至系统的device_kset中,并完成与mmc_host_class的关联操作。该接口主要完成如下两个功能:

  1. 调用device_add接口,完成mmc_host与系统device_kset、mmc_host_class的关联,经过此步骤后则在sysfs目录下完成该mmc_host对应kobject的目录创建以及相关的属性文件的创建,并完成与mmc_host_class的关联;
  2. 调用mmc_start_host接口,从而调用mmc_detect_change接口,唤醒mmc_host->detect队列,从而执行mmc_rescan接口,执行一次mmc rescan操作。

 

 

        经过以上两个接口后,mmc_host即完成了与mmc_host_class、device_kset的关联,即完成了mmc_host与设备驱动模型间的关联,数据结构之间的关联如下(关于下图中devices_kset、kref、kobj、kobj_type、kobj_sysfs_drient等数据结构的说明,请参考之前写的sysfs与设备驱动模型相关的文章)。

 

 

 

Mmc host移除

Mmc host移除的接口为mmc_remove_host,该接口实现的功能,可分为如下几种:

  1. 调用mmc_stop_host接口,完成如下几个功能:
    1. 调用mmc_host->bus_ops->remove,即mmc_remove接口(此处针对mmc/sd,针对sdio,则不是该接口),实现mmc_card对应的device类型成员的注销,解除与mmc_bus、mmc_driver的绑定(同时也会去除mmc block device的注销);
    2. 调用mmc_power_off、mmc_release_host,关闭mmc controller;
    3. 调用mmc_bus_put,主要用于解除mmc_host与mmc_host_ops的绑定;
    4. 调用device_del,注销该mmc_host对应的class_dev,同时借助device模型的device_release接口,最终调用mmc_host_classdev_release接口,释放mmc_host对应的动态内存,完成mmc_host的释放操作。

 

 

 

以上便是mmc_host的添加与移除的接口。

 

完成一个mmc host驱动需要哪些步骤

一、mmc_host_ops相关的接口实现

实现mmc_host_ops中各函数指针,针对mmc_host_ops,如下几个接口需要重点关注:

  1. 必须要实现的函数为request(该接口为mmc controller的通信方法);
  2. set_ios(该接口用于设置mmc controller的总线相关的参数:总线位宽、总线模式等等,可参考mmc_ios数据结构),
  3. get_ro接口主要用于判断一个mmc_card是否是只读的(该接口不是必须的);
  4. get_cd接口主要用于卡的在位检测的,可根据硬件设计决定是否需要实现该接口;
  5. enable/disable为使能/去使能mmc controller接口,这个与具体的mmc controller有关;

 

二、platform driver的实现(该platform driver也不是必须的,但目前大多数设备驱动基本上以platform driver为主)

    针对一个 mmc host driver,在目前的内核中(不管是否使用设备树),一般创建一个platform driver驱动,该驱动与mmc host对应的platform device关联,而在platform driver的probe接口中,进行mmc host的创建与添加操作。

 

三、platform driver的probe接口中实现mmc host的添加:

  1. 调用mmc_alloc_host接口,申请一个mmc_host类型的变量,并进行初始化;
  2. 对mmc_host进行设置,包括设置mmc_host的caps(如emmc,则设置MMC_CAP_NONREMOVABLE)、若不支持卡在位检测引脚,则设置mmc_host的caps的MMC_CAP_NEEDS_POLL位等;
  3. 设置mmc_host的ops为上述一中定义的变量;
  4. 调用mmc_add_host,将该mmc_host注册至系统,并完成一次mmc rescan操作。

 

 

          针对mmc host驱动而言,大致即为以上步骤,当然了针对mmc controller的复杂程度以及mmc controller通信相关的dma等操作,mmc host驱动的编写可能不是那么简单,但知道上述流程后,并参考其他厂家的host驱动,相对而言不会太复杂。

 

发布了140 篇原创文章 · 获赞 30 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/lickylin/article/details/104717986