Linux裝置模型中,Bus(匯流排)是一類特殊的裝置,它是連線處理器和其它裝置之間的通道(channel)。為了方便裝置模型的實現,核心規定,系統中的每個裝置都要連線在一個Bus上,這個Bus可以是一個內部Bus、虛擬Bus或者Platform Bus

devicedevice driverLinux驅動開發的基本概念。Linux kernel的思路很簡單:驅動開發,就是要開發指定的軟體(driver)以驅動指定的裝置,所以kernel就為裝置和驅動它的driver定義了兩個資料結構,分別是devicedevice_driver(本文以http://www.wowotech.net/device_model/device_and_driver.html,http://www.wowotech.net/device_model/bus.html為基礎,結合自己的理解和4.1核心的修改)。

bus_type

核心通過struct bus_type結構,抽象Bus

 

name,該bus的名稱,會在sysfs中以目錄的形式存在,如platform bussysfs中表現為"/sys/bus/platform”。

dev_name,該名稱和下面講到的struct device結構中的init_name有關。對有些裝置而言,允許將裝置的名字留空。這樣當設備註冊到核心後,裝置模型的核心邏輯就會用"bus->dev_name+device ID”的形式,為這樣的裝置生成一個名稱。

dev_attrs,被下邊的groups取代

bus_groupsdev_groupsdrv_groups,一些預設的attribute,可以在busdevice或者device_driver新增到核心時,自動為它們新增相應的attribute

dev_rootdev_root裝置為bus的預設父裝置(Default device to use as the parent),但在核心實際實現中,和一個叫sub system的功能有關。

match,一個由具體的bus driver實現的回撥函式。當任何屬於該Busdevice或者device_driver新增到核心時,核心都會呼叫該介面,如果新加的devicedevice_driver匹配上了彼此的話,該介面要返回非零值,此時Bus模組的核心邏輯就會執行後續的處理。

uevent,一個由具體的bus driver實現的回撥函式。當任何屬於該Busdevice,發生新增、移除或者其它動作時,Bus模組的核心邏輯就會呼叫該介面,以便bus driver能夠修改環境變數。

proberemove,這兩個回撥函式,和device_driver中的非常類似,但它們的存在是非常有意義的。可以想象一下,如果需要probe(其實就是初始化)指定的device話,需要保證該device所在的bus是被初始化過、確保能正確工作的。這就要就在執行device_driverprobe前,先執行它的busproberemove的過程相反。

並不是所有的bus都需要proberemove介面的,因為對有些bus來說(例如platform bus),它本身就是一個虛擬的匯流排,無所謂初始化,直接就能使用,因此這些busdriver就可以將這兩個回撥函式留空。

shutdownsuspendresume,和proberemove的原理類似,電源管理相關的實現。

onlineoffline,和屬於這個匯流排裝置的online屬性相關。

pm,電源管理相關的邏輯。

iommu_ops,匯流排的IOMMU相關操作,IOMMUMMU功能類似,可以給裝置一個核心空間的地址(或叫匯流排地址),而不限於可以直接訪問的常規記憶體區域。

p,一個struct subsys_private型別的指標,kobject隱藏在這個結構後面。這個結構也很重要。

device

 

device結構很複雜,這裡將會選一些對理解裝置模型非常關鍵的欄位進行說明。

parent,該裝置的父裝置,一般是該裝置所從屬的buscontroller等裝置。

p,一個用於裝置的私有資料結構指標,儲存子裝置連結串列,新增父節點,鄰居節點和匯流排連結串列等。

kobj,該資料結構對應的struct kobject

init_name,該裝置的名稱。

在裝置模型中,名稱是一個非常重要的變數,任何註冊到核心中的裝置,都必須有一個合法的名稱,可以在初始化時給出,也可以由核心根據bus name + device ID”的方式創造。見bus_type.dev_name的說明。

typestruct device_type結構是新版本核心新引入的一個結構,它和struct device關係,非常類似stuct kobj_typestruct kobject之間的關係。

bus,該device屬於哪個匯流排。

driver,該device對應的device driver

platform_data,一個指標,用於儲存具體的平臺相關的資料。linux經常用來儲存一些單板相關的資料,來描述包含哪些裝置,以及它們如何互聯。以便大幅減少BSP的程式碼量和驅動中ifdef的使用。

powerpm_domain,電源管理相關的邏輯,後續會由電源管理專題講解。

pins"PINCTRL”功能。

numa_node"NUMA”功能。

devt,裝置號。在這裡,該變數主要用於在sys檔案系統中,為每個具有裝置號的device,建立/sys/dev/*下的對應目錄,如下:



class,該裝置屬於哪個class。這從側面說明了classdevice的集合。

groups,該裝置的預設attribute集合。將會在設備註冊時自動在sysfs中建立對應的檔案。

device_driver

 

name,該driver的名稱。和device結構一樣,該名稱非常重要,和devicedriver的匹配有關。

bus,該driver所驅動裝置的匯流排裝置。核心要保證在driver執行前,裝置所依賴的匯流排能夠正確初始化。

ownermod_name,核心module相關的變數。

suppress_bind_attrs,通過sysfs啟用bindunbindattribute,如下:

# ls /sys/bus/platform/drivers/switch-gpio/                                                  

    bind   uevent    unbind

kernel中,bind/unbind是從使用者空間手動的為driver繫結/解繫結指定的裝置的機制。

proberemove,這兩個介面函式用於實現driver邏輯的開始和結束。在裝置模型的結構下,只有driverdevice同時存在時,才需要開始執行driver的程式碼邏輯。這也是proberemove兩個介面名稱的由來:檢測到了裝置和移除了裝置(就是為熱拔插起的!)。

shutdownsuspendresumepm,電源管理相關的內容。

groups,和struct device結構中的同名變數類似,driver也可以定義一些預設attribute,這樣在將driver註冊到核心中時,核心裝置模型部分的程式碼會自動將這些attribute新增到sysfs中。

p,私有資料的指標。

subsys_private

舊的linux存在獨立的子系統資料結構subsystem2.6.35拋棄了這個資料結構。轉而用subsys_private表示。

什麼是子系統?無論是bus,還是class,還是一些虛擬的子系統,它都構成了一個“子系統(sub-system)”,該子系統會包含形形色色的devicedevice_driver,就像一個獨立的王國一樣,存在於核心中。而這些子系統的表現形式,就是/sys/bus(或/sys/class,或其它)目錄下面的子目錄,每一個子目錄,都是一個子系統(如/sys/bus/spi/)。從子系統的角度看bus和後面的class很類似,它們都用subsys_private表示子系統。

 

subsysdevices_ksetdrivers_kset是三個kset。其中subsys,代表了本bus(如/sys/bus/spi),它下面可以包含其它的kset或者其它的kobjectdevices_ksetdrivers_kset則是bus下面的兩個kset(如/sys/bus/spi/devices/sys/bus/spi/drivers),分別包括本bus下所有的devicedevice_driverbus_typekobject的關係通過subsys成員體現。通過巨集to_subsys_private(obj)可以看出。

interface用於儲存該bus下所有的interfaceinterface抽象了此類子系統的專有功能。

klist_devicesklist_drivers,分別儲存了本bus下所有的devicedevice_driver的指標,以方便查詢。

drivers_autoprobe,用於控制該bus下的drivers或者device是否自動probe

busclass,分別儲存上層的bus或者class指標。

device_private

 

klist_childre,包含此裝置所有的子裝置。

knode_parent,連入父裝置的klist_children時所用的節點。

knode_driver,連入驅動的裝置連結串列所用的節點,driver_privateklist_devices節點。

knode_bus,連入匯流排的裝置連結串列時所用的節點,subsys_privateklist_devices的節點。

deferred_probedeferred_probe_list的入口,deferred_probe_list用來重新繫結那些暫時不能獲得device全部資源的驅動,這種情況常常是因為某一個驅動需要另一個驅動首先probe

device,指向包含device_privatedevice

driver_private

 

kboj,結構對應的kobject

klist_devices,包含此驅動可以驅動的裝置。

knode_bus,連入bus的驅動連結串列的節點,代表subsys_privateklist_drivers的節點。

mkobj,核心module相關變數。

driver,指向包含driver_privatedriver

device_type

 

name,表示該型別的名稱,當該型別的裝置新增到核心時,核心會發出"DEVTYPE=name’”型別的uevent,告知使用者空間某個型別的裝置available了。

groups,該型別裝置的公共attribute集合。設備註冊時,會同時註冊這些attribute。這就是面向物件中“繼承”的概念。

uevent,所有相同型別的裝置,會有一些共有的uevent需要傳送,由該介面實現。

release,如果device結構沒有提供release介面,就要查詢它所屬的type是否提供,用於釋放device變數所佔的空間。

bus_typedevicedevice_driverkobject的關係

devicedevice_driver的角度看

 

devicedevice_driver直接繼承kobjectbus_type通過subsys_privatekobject發生聯絡。圖中ksetkobject的關係是從kset與包含在它裡邊的kobject的角度看的,與前面ksetkobjcet的關係角度不同。由此可見,匯流排、裝置和驅動是建立在kobject基礎上的,藉由kobjectkset建立層次關係。

bus_typedevicedevice_driver的關係

 

一個device_driver可以支援多個devicebus_type通過subsys_privatedevice_driverdevice發生關聯。

bus_typedevicedevice_driversysfs的關係

匯流排,裝置和裝置驅動與sysfs的對應關係相對簡單直觀。

核心資料結構或成員

sysfs對應表現形式

bus_type.name

/sys/bus下的目錄名

bus_type.dev_name

裝置委託給匯流排給其一個名字,如果裝置沒有起名,與device_id一起作為/sys/devices下的目錄名

device.name

/sys/devices下的目錄名

driver.name

/sys/devices下的目錄名


.