當前位置:首頁 > 公眾號精選 > 嵌入式微處理器
[導讀][導讀] Linux設(shè)備林林總總,嵌入式開發(fā)一個繞不開的話題就是設(shè)備驅(qū)動開發(fā),在做具體設(shè)備驅(qū)動開發(fā)之前,有必要對Linux設(shè)驅(qū)動模型有一個相對清晰的認識,將會幫助驅(qū)動開發(fā),明白具體驅(qū)動接口操作符相應(yīng)都做些什么。 個人對于驅(qū)動模型的理解概括起來就是一句話:

[導讀] Linux設(shè)備林林總總,嵌入式開發(fā)一個繞不開的話題就是設(shè)備驅(qū)動開發(fā),在做具體設(shè)備驅(qū)動開發(fā)之前,有必要對Linux設(shè)驅(qū)動模型有一個相對清晰的認識,將會幫助驅(qū)動開發(fā),明白具體驅(qū)動接口操作符相應(yīng)都做些什么。

個人對于驅(qū)動模型的理解概括起來就是一句話:利用面向?qū)ο缶幊趟枷耄瑢崿F(xiàn)設(shè)備分層管理軟件體系結(jié)構(gòu)

注:代碼分析基于linux-5.4.31

為啥要驅(qū)動模型

隨著系統(tǒng)結(jié)構(gòu)演化越來越復雜,Linux內(nèi)核對設(shè)備描述衍生出一般性的抽象描述,形成一個分層體系結(jié)構(gòu),從而引入了設(shè)備驅(qū)動模型。這樣描述還是不夠讓人理解,來看一下這些需求就好理解些:

  • Linux內(nèi)核可以在各種體系結(jié)構(gòu)和硬件平臺上運行,因此需要最大限度地提高代碼在平臺之間的可重用性。
  • 分層實現(xiàn)也實現(xiàn)了軟件工程的高內(nèi)聚-低耦合的設(shè)計思想。低耦合體現(xiàn)在對外提供統(tǒng)一的抽象訪問接口,高內(nèi)聚將相關(guān)度緊密的集中抽象實現(xiàn)。
  • Linux內(nèi)核驅(qū)動程序模型是先前在內(nèi)核中使用的所有不同驅(qū)動程序模型的統(tǒng)一。它旨在通過將一組數(shù)據(jù)和操作整合到全局可訪問的數(shù)據(jù)結(jié)構(gòu)中,來擴展基于基礎(chǔ)總線來橋接設(shè)備驅(qū)動程序。

傳統(tǒng)的驅(qū)動模型為它們所控制的設(shè)備實現(xiàn)了某種類似于樹的結(jié)構(gòu)(有時只是一個列表)。不同類型的總線之間沒有任何一致性。

驅(qū)動模型抽象了啥

當前驅(qū)動程序模型為描述總線和總線下可能出現(xiàn)的設(shè)備提供了一個通用的、統(tǒng)一的模型。統(tǒng)一總線模型包括一組所有總線都具有的公共屬性和一組公共回調(diào),如總線探測期間的設(shè)備發(fā)現(xiàn)、總線關(guān)閉、總線電源管理等。

通用的設(shè)備和橋接接口反映了現(xiàn)代計算機的目標:即執(zhí)行無縫設(shè)備“即插即用”,電源管理和熱插拔的能力。特別是,英特爾和微軟規(guī)定的模型(即ACPI)可確保與x86兼容的系統(tǒng)上幾乎任何總線上的幾乎所有設(shè)備都可以在此范式下工作。當然,雖然大多數(shù)總線都支持其中大多數(shù)操作,但并不是每條總線都能夠支持所有此類操作。

那么哪些通用需求被抽象出來了呢?

  • 電源系統(tǒng)和系統(tǒng)關(guān)機,對于電源管理與系統(tǒng)關(guān)機對于設(shè)備相關(guān)的操作進行抽象實現(xiàn)。關(guān)機為什么要被抽象出來管理,比如設(shè)備操作正在進行此時系統(tǒng)收到關(guān)機指令,那么在設(shè)備模型層就會遍歷系統(tǒng)設(shè)備硬件,確保系統(tǒng)正確關(guān)機。

  • 用戶空間訪問:sysfs虛擬文件系統(tǒng)實現(xiàn)與設(shè)備模型對外的訪問抽象,這也是為什么說Linux 設(shè)備也是文件的由來。實際從軟件架構(gòu)層面看,這其實是一個軟件橋接模塊,抽象出統(tǒng)一用戶訪問接口,橋接了設(shè)備驅(qū)動。

  • 熱插拔管理:熱插拔管理機制定義統(tǒng)一的抽象接口操作符kset_hotplug_ops,不同設(shè)備利用操作符實現(xiàn)差異化。

  • 設(shè)備類型:設(shè)備分類機制,從高層級抽象描述設(shè)備類型,具體可以在sysfs下面體現(xiàn)。

用戶空間訪問

由于具有系統(tǒng)中所有設(shè)備的完整分層視圖,因此將完整的分層視圖導出到用戶空間變得相對容易。這是通過實現(xiàn)名為sysfs虛擬文件系統(tǒng)來完成的。

sysfs的自動掛載通常是通過/etc/fstab文件中的以下條目來完成的:

none   /sys	sysfs  defaults	 0 0

對于Debian系統(tǒng)而言,可能在/lib/init/fstab采用下面的形式掛載:

none  /sys    sysfs    nodev,noexec,nosuid    0 0

當然也可以采用手動方式掛載:

# mount -t sysfs sysfs /sys

當將設(shè)備插入樹中時,都會為其創(chuàng)建一個目錄。該目錄可以填充在發(fā)現(xiàn)的每個層(全局層,總線層或設(shè)備層)中。

全局層當前創(chuàng)建兩個文件-'name'和'power'。前者報告設(shè)備名稱。后者報告設(shè)備的當前電源狀態(tài)。它還將用于設(shè)置當前電源狀態(tài)。

總線層為探測總線時發(fā)現(xiàn)的設(shè)備創(chuàng)建文件。例如,PCI層當前為每個PCI設(shè)備創(chuàng)建“ irq”和“resource”文件。

特定于設(shè)備的驅(qū)動程序也可以在其目錄中導出文件,以暴露特定于設(shè)備的數(shù)據(jù)或可用接口。

驅(qū)動模型實現(xiàn)

先來梳理一下內(nèi)部幾個主要與驅(qū)動模型相關(guān)的數(shù)據(jù)結(jié)構(gòu):

./include/linux/Device.h 定義設(shè)備驅(qū)動主要數(shù)據(jù)結(jié)構(gòu)

  • bus_type:抽象描述總線類型,如USB/PCI/I2C/MMC等
  • device_driver:實現(xiàn)具體連接在總線上的設(shè)備驅(qū)動。
  • device:描述連接在總線上的設(shè)備

./include/linux/Kobject.h中定義了隱藏在后臺的類似于基類的數(shù)據(jù)結(jié)構(gòu):

  • kset:可以認為是kobject的頂層容器類。每個kset內(nèi)部都包含了自己的kobject.
  • kobject:在 sysfs 中出現(xiàn)的每個對象都對應(yīng)一個 kobject, 它和內(nèi)核交互來創(chuàng)建它的可見表述,每一個 kobject 對應(yīng) 文件系統(tǒng) /sys 里的一個 目錄,目錄的名字就是結(jié)構(gòu)體中的 name

bus_type

bus_type用以驅(qū)動總線,具體的驅(qū)動USB/I2C/PCI/MMC等:

  • 注冊總線,利用bus_register注冊總線,bus_unregister刪除總線。如下例子,每種總線須定義一個bus_type對象,并利用bus_register注冊總線,或bus_unregister刪除總線。
/*i2c-core-base.c*/
struct bus_type i2c_bus_type = {
 .name  = "i2c",
 .match  = i2c_device_match,
 .probe  = i2c_device_probe,
 .remove  = i2c_device_remove,
 .shutdown = i2c_device_shutdown,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
static int __init i2c_init(void)
{
 int retval;

 retval = of_alias_get_highest_id("i2c");

 down_write(&__i2c_board_lock);
 if (retval >= __i2c_first_dynamic_bus_num)
  __i2c_first_dynamic_bus_num = retval + 1;
 up_write(&__i2c_board_lock);
    /*注冊I2C總線*/
 retval = bus_register(&i2c_bus_type);
 if (retval)
  return retval;

 is_registered = true;

#ifdef CONFIG_I2C_COMPAT
 i2c_adapter_compat_class = class_compat_register("i2c-adapter");
 if (!i2c_adapter_compat_class) {
  retval = -ENOMEM;
  goto bus_err;
 }
#endif
 retval = i2c_add_driver(&dummy_driver);
 if (retval)
  goto class_err;

 if (IS_ENABLED(CONFIG_OF_DYNAMIC))
  WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier));
 if (IS_ENABLED(CONFIG_ACPI))
  WARN_ON(acpi_reconfig_notifier_register(&i2c_acpi_notifier));

 return 0;

class_err:
#ifdef CONFIG_I2C_COMPAT
 class_compat_unregister(i2c_adapter_compat_class);
bus_err:
#endif
 is_registered = false;
    /*錯誤時刪除總線*/
 bus_unregister(&i2c_bus_type);
 return retval;
}
  • 注冊適配器驅(qū)動程序(USB控制器,I2C適配器等),以檢測連接的設(shè)備,并提供與設(shè)備的通信機制
  • 圖中的match函數(shù)接口用于將驅(qū)動程序與設(shè)備進行匹配。match回調(diào)的目的是使總線有機會通過比較驅(qū)動程序支持的設(shè)備ID與特定設(shè)備的設(shè)備ID來確定特定驅(qū)動程序是否支持特定設(shè)備,而不會犧牲特定于總線的功能或類型安全性 。當向總線注冊驅(qū)動程序時,將遍歷總線的設(shè)備列表,并為每個沒有與之關(guān)聯(lián)的驅(qū)動程序的設(shè)備調(diào)用match回調(diào)。
  • 提供API函數(shù)以實現(xiàn)適配器驅(qū)動以及設(shè)備驅(qū)動。
  • 同時dev_pm_ops *pm實現(xiàn)對于總線的功耗管理接口抽象。對于特定總線實現(xiàn)這個操作符對應(yīng)的函數(shù)。
struct dev_pm_ops {
 int (*prepare)(struct device *dev);
 void (*complete)(struct device *dev);
 int (*suspend)(struct device *dev);
 int (*resume)(struct device *dev);
 int (*freeze)(struct device *dev);
 int (*thaw)(struct device *dev);
 int (*poweroff)(struct device *dev);
 int (*restore)(struct device *dev);
 int (*suspend_late)(struct device *dev);
 int (*resume_early)(struct device *dev);
 int (*freeze_late)(struct device *dev);
 int (*thaw_early)(struct device *dev);
 int (*poweroff_late)(struct device *dev);
 int (*restore_early)(struct device *dev);
 int (*suspend_noirq)(struct device *dev);
 int (*resume_noirq)(struct device *dev);
 int (*freeze_noirq)(struct device *dev);
 int (*thaw_noirq)(struct device *dev);
 int (*poweroff_noirq)(struct device *dev);
 int (*restore_noirq)(struct device *dev);
 int (*runtime_suspend)(struct device *dev);
 int (*runtime_resume)(struct device *dev);
 int (*runtime_idle)(struct device *dev);
};
  • iommu_ops 操作符提供總線相關(guān)的IOMMU抽象。
  • 設(shè)備驅(qū)動注冊到總線上時,將在sysfs管理總線/設(shè)備/設(shè)備驅(qū)動的層次關(guān)系,以PCI為例:
/*在總線上注冊的驅(qū)動程序會在總線的驅(qū)動程序目錄中獲得一個目錄*/
/sys/bus/pci/
        |-- devices
        `-- drivers
            |-- Intel ICH
            |-- Intel ICH Joystick
            |-- agpgart
            `-- e100
/*在該類型的總線上發(fā)現(xiàn)的每個設(shè)備都會在總線的設(shè)備目錄中獲得到物理層次結(jié)構(gòu)中該設(shè)備目錄的符號鏈接*/
/sys/bus/pci/
          |-- devices
          |   |-- 00:00.0 -> ../../../root/pci0/00:00.0
          |   |-- 00:01.0 -> ../../../root/pci0/00:01.0
          |   `-- 00:02.0 -> ../../../root/pci0/00:02.0
          `-- drivers
  • 總線屬性:bus_groups/設(shè)備屬性dev_groups/驅(qū)動屬性drv_groups。

device

  • 作用:抽象描述具體的設(shè)備

  • 設(shè)備注冊:發(fā)現(xiàn)設(shè)備的總線驅(qū)動程序使用下面的函數(shù)來向內(nèi)核注冊設(shè)備

int device_register(struct device * dev);
  • 利用device_unregister()從總線上刪除設(shè)備

device_driver

  • 作用:抽象描述連接在總線上的具體設(shè)備的驅(qū)動
  • 驅(qū)動注冊,通過下面的函數(shù)將設(shè)備驅(qū)動程序注冊
int driver_register(struct device_driver *drv);
  • 使用它使用以下命令從驅(qū)動程序目錄中添加和刪除屬性
  int driver_create_file(struct device_driver *, const struct driver_attribute *);
  void driver_remove_file(struct device_driver *, const struct driver_attribute *);

class

  • 作用:抽象設(shè)備的高層視圖,描述的是設(shè)備的集合。抽象了同類型的設(shè)備的底層實現(xiàn)細節(jié)。比如所有的網(wǎng)絡(luò)接口都位于/sys/class/net下
  • struct subsys_private *p描述類鏈表

kobject/kset

  • kobject類似于面向?qū)ο笾械膬?nèi)核基類,內(nèi)核利用它將各個對象連接起來組成分層的機構(gòu)體系,其parent指針將形成一個樹狀分層結(jié)構(gòu)。
  • kset內(nèi)部包含了kobject。重心在描述對象的聚集于集合。這也是set一詞的含義。每一個kset添加到系統(tǒng)中,都將在sysfs中創(chuàng)建一個目錄
  • kobject/kset一起實現(xiàn)了sysfs虛擬文件系統(tǒng)中設(shè)備/總線/設(shè)備驅(qū)動樹狀分層結(jié)構(gòu)的最關(guān)鍵的底層實現(xiàn)由來。

總體上而言:

通過上面一些關(guān)鍵數(shù)據(jù)結(jié)構(gòu)關(guān)系分析,總線設(shè)備驅(qū)動模型最終目的是實現(xiàn)如下這樣一個分層驅(qū)動模型。

END



本文授權(quán)轉(zhuǎn)載自公眾號“嵌入式客棧”,作者逸珺

免責聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

嵌入式ARM

掃描二維碼,關(guān)注更多精彩內(nèi)容

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉