Linux裝置模型(一) 概覽

yangjizhen1533發表於2020-12-12

參考文章:http://www.wowotech.net/linux_kenrel/13.html

1. 簡介

為了降低裝置多樣性帶來的Linux驅動開發的複雜度,以及裝置熱拔插處理、電源管理等,Linux核心提出了裝置模型的概念。裝置模型將硬體裝置歸納、分類,然後抽象出一套標準的資料結構和介面。

2. Linux裝置模型概覽

Linux裝置模型是一個複雜的資料結構,圖2.1是Linux裝置模型示意圖。
Linux裝置模型使用一系列抽象,提供統一的裝置管理檢視,這些抽象包括:Bus,Class,Device,Device Driver
在這裡插入圖片描述

基於上述4個抽象資料結構,驅動的開發,就簡化為對核心所規定的資料結構的填充和實現。
圖2.2 列出了Linux裝置模型相關技術點。對於Linux驅動工程師來說,想要理解Linux裝置模型,這些技術點是需要深刻學習理解的。
實際上,對於上層使用者,只需要關心Bus,Class,Device,Device Driver。而對於Kobject,sysfs,uevent,上層使用者是不需要關心的。
在這裡插入圖片描述
先簡單說一下Kobject,sysfs,uevent:
Kobject是Linux裝置模型的基礎資料結構,Bus,Class,Device,Device Driver 這4個資料結構都包含有Kobject相關資料結構。
sysfs是一個基於RAM的檔案系統,它和Kobject一起,可以將Kernel的資料結構匯出到使用者空間,以檔案目錄結構的形式,提供對這些資料結構(以及資料結構的屬性)的訪問支援。正是通過sysfs檔案系統,將Bus,Class,Device,Device Driver的資訊展示給了使用者,通過修改/sys目錄下裝置的檔案容,即可以直接修改裝置對應的引數。
uevent用於在Kobject狀態發生改變時,例如增加、移除等,通知使用者空間程式。使用者空間程式收到這樣的事件後,會做相應的處理。

3. Bus, Class, Device和Device Driver的概念

Linux裝置模型是抽象出來的模型,那麼我們來看看它是對什麼做了抽象。
先來看一個嵌入式系統常見的硬體拓撲圖。
在這裡插入圖片描述

Bus(匯流排):Linux認為(可以參考include/linux/device.h中struct bus_type的註釋),匯流排是CPU和一個或多個裝置之間資訊互動的通道。而為了方便裝置模型的抽象,所有的裝置都應連線到匯流排上(無論是CPU內部匯流排、虛擬的匯流排還是“Platform Bus”)。

注1:什麼是Platform Bus?
在計算機中有這樣一類裝置,它們通過各自的裝置控制器,直接和CPU連線,CPU可以通過常規的定址操作訪問它們(或者說訪問它們的控制器)。這種連線方式,並不屬於傳統意義上的匯流排連線。但裝置模型應該具備普適性,因此Linux就虛構了一條Platform Bus,供這些裝置掛靠。

注2:區分I2C控制器、I2C裝置。(SPI也是類似的,要區分SPI控制器和SPI裝置)
對於ARM Core而言,I2C控制器、I2C裝置都是裝置。如圖3.1所示, I2C控制器是連線到Platform Bus的。而 I2C Bus Device是連線到I2C Bus的。而我們通常寫的裝置驅動,是連線到 I2C Bus 上的 I2C Bus Device 驅動

思考:
幾乎所有的文章都說Platform Bus是不存在的,是虛構的。
但是,對於瞭解嵌入式硬體架構(以ARM架構為例)的人而言,在圖3.1 嵌入式硬體拓撲圖中,Platform Bus就是AMBA匯流排(可能是AXI、AHB、APB、相關Bridge)的抽象。如果這樣說,Platform Bus就不是虛構的,是對硬體的Bus抽象。
當然,這是我自己的一個思考,也不知道是否正確。Linux裝置模型設計精巧,作為菜鳥,我可能沒有理解到大師們的設計理念。

Class(分類):在Linux裝置模型中,Class的概念非常類似物件導向程式設計中的Class(類),它主要是集合具有相似功能或屬性的裝置,這樣就可以抽象出一套可以在多個裝置之間共用的資料結構和介面函式。因而從屬於相同Class的裝置的驅動程式,就不再需要重複定義這些公共資源,直接從Class中“繼承”即可。

注:此處的“繼承”僅僅是資料結構的巢狀,不是C++語言裡的繼承概念。
Linux裝置模型僅僅是借鑑了物件導向的程式設計思想,並不是真的物件導向。當然也就不存在什麼建構函式、解構函式、封裝、多型等相關技術點,切記生搬硬套。

Device(裝置):抽象系統中所有的硬體裝置,描述它的名字、屬性、從屬的Bus、從屬的Class等資訊。

Device Driver(驅動):Linux裝置模型用Driver抽象硬體裝置的驅動程式,它包含裝置初始化、電源管理相關的介面實現。而Linux核心中的驅動開發,基本都圍繞該抽象進行(實現所規定的介面函式)。

4. Linux裝置模型的核心思想

Linux裝置模型的核心思想是(通過xxx手段,實現xxx目的):

  1. 用Device(struct device)和Device Driver(struct device_driver)兩個資料結構,分別從“有什麼用”和“怎麼用”兩個角度描述硬體裝置。這樣就統一了編寫裝置驅動的格式,使驅動開發從論述題變為填空體,從而簡化了裝置驅動的開發。

  2. 同樣使用Device和Device Driver兩個資料結構,實現硬體裝置的即插即用(熱拔插)。
    在Linux核心中,只要任何Device和Device Driver具有相同的名字,核心就會執行Device Driver結構中的初始化函式(probe),該函式會初始化裝置,使其為可用狀態。
    而對大多數熱拔插裝置而言,它們的Device Driver一直存在核心中。當裝置沒有插入時,其Device結構不存在,因而其Driver也就不執行初始化操作。當裝置插入時,核心會建立一個Device結構(名稱和Driver相同),此時就會觸發Driver的執行。這就是即插即用的概念。

  3. 通過"Bus–>Device”型別的樹狀結構(見2.1章節的圖例)解決裝置之間的依賴,而這種依賴在開關機、電源管理等過程中尤為重要。
    試想,一個裝置掛載在一條匯流排上,要啟動這個裝置,必須先啟動它所掛載的匯流排。很顯然,如果系統中裝置非常多、依賴關係非常複雜的時候,無論是核心還是驅動的開發人員,都無力維護這種關係。
    而裝置模型中的這種樹狀結構,可以自動處理這種依賴關係。啟動某一個裝置前,核心會檢查該裝置是否依賴其它裝置或者匯流排,如果依賴,則檢查所依賴的物件是否已經啟動,如果沒有,則會先啟動它們,直到啟動該裝置的條件具備為止。而驅動開發人員需要做的,就是在編寫裝置驅動時,告知核心該裝置的依賴關係即可。

  4. 使用Class結構,在裝置模型中引入物件導向的概念,這樣可以最大限度地抽象共性,減少驅動開發過程中的重複勞動,降低工作量。

5. 小結

將在後面的文章裡,逐一介紹圖2.2列出的技術點 Bus,Class,Device,Device Driver,Kobject,sysfs,uevent。

6. 說明

圖3.1中,Camera通過兩條線連線到ARM Core:
一條是直接連線到Camera控制器,可以理解為MIPI CSI介面,Camera資料直接吐到CSI介面。
一條是通過I2C Bus連線到ARM Core,可以理解為Camera的控制訊號。

相關文章