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的方法。


LINUX MMC子系統分析(四) MMC HOST模塊分析

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即可)


LINUX MMC子系統分析(四) MMC HOST模塊分析

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協議相關的文檔)


LINUX MMC子系統分析(四) MMC HOST模塊分析

mmc_ios

該結構體主要定義mmc總線相關的參數,主要包括時鐘頻率、電源、總線模式、電源狀態、總線帶寬、支持的信號電壓值等等這些參數的設置可通過mmc_host_ops->set_ios實現

LINUX MMC子系統分析(四) MMC HOST模塊分析

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驅動基本上不需要實現。


LINUX 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 不同版本的協議,其功能有所不同:
  5. 若card支持poweroff notify機制,則進入poweroff狀態;
  6. 若card支持sleep狀態,則進入sleep狀態,針對mmc rev>=1.3的情況;
  7. card不支持以上兩種狀態,則向card發送deselect命令

5.針對power_restore接口,即為mmc_power_restore接口,該接口目前即調用mmc_init_card,根據mmc 協議,完成mmc card的初始化操作。

LINUX MMC子系統分析(四) MMC HOST模塊分析

以上即是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的釋放;
  2. 調用device_initialize進行mmc_host->class_dev的初始化,主要設置該class_dev所依附的device_kset及kobj_type等(該接口是設備驅動模型中的接口,想詳細瞭解的朋友,請參考之前寫的文章),通過設置該class_dev屬於mmc_host_class;
  3. 初始化mmc host的塊大小、段大小等信息。
  4. 初始化host->detect隊列,並設置該隊列對應的處理接口為mmc_rescan,用於mmc/sd卡的檢測,具體應用如下:
  5. 若該mmc_host支持卡的在位檢測(一般通過cd引腳檢測,並配置成中斷模式),則在中斷處理函數中可調用mmc_detect_change,喚醒該延遲工作隊列,即調用mmc_rescan實現卡的rescan;
  6. 若mmc_host不支持卡的在位檢測功能(即不存在cd引腳檢測),則將mmc_host設置為poll模式,在poll模式下,當在執行mmc_add_host時執行一次mmc_rescan時,在mmc_rescan的結尾根據該poll模式,設置延遲調度該隊列的時間為1s,則該延遲工作隊列以1s為週期進行卡的rescan。


LINUX MMC子系統分析(四) 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操作。


LINUX MMC子系統分析(四) MMC HOST模塊分析

經過以上兩個接口後,mmc_host即完成了與mmc_host_class、device_kset的關聯,即完成了mmc_host與設備驅動模型間的關聯,數據結構之間的關聯如下(關於下圖中devices_kset、kref、kobj、kobj_type、kobj_sysfs_drient等數據結構的說明,請參考之前寫的sysfs與設備驅動模型相關的文章)。

LINUX MMC子系統分析(四) MMC HOST模塊分析

Mmc host移除

Mmc host移除的接口為mmc_remove_host,該接口實現的功能,可分為如下幾種:

  1. 調用device_del,註銷該mmc_host對應的class_dev,同時藉助device模型的device_release接口,最終調用mmc_host_classdev_release接口,釋放mmc_host對應的動態內存,完成mmc_host的釋放操作。
  2. 調用mmc_stop_host接口,完成如下幾個功能:
  3. 調用mmc_host->bus_ops->remove,即mmc_remove接口(此處針對mmc/sd,針對sdio,則不是該接口),實現mmc_card對應的device類型成員的註銷,解除與mmc_bus、mmc_driver的綁定(同時也會去除mmc block device的註銷);
  4. 調用mmc_power_off、mmc_release_host,關閉mmc controller;
  5. 調用mmc_bus_put,主要用於解除mmc_host與mmc_host_ops的綁定;


LINUX MMC子系統分析(四) 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驅動,相對而言不會太複雜。


分享到:


相關文章: