天天看點

Linux裝置、總線和驅動之間的關系

(一)、驅動、總線和裝置的主要資料結構

(include/linux/device.h)

Linux裝置、總線和驅動之間的關系

(/driver/base/base.h)

Linux裝置、總線和驅動之間的關系

(include/device.h)

Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系

總線中的那兩條連結清單是怎麼形成的。核心要求每次出現一個裝置就要向總線彙報,或者說注冊,每次出現一個驅動,也要向總線彙報,或者說注冊。比如系統初始化的時候,會掃描連接配接了哪些裝置,并為每一個裝置建立起一個structdevice 的變量,每一次有一個驅動程式,就要準備一個tructdevice_driver 結構的變量。把這些變量統統加入相應的連結清單,device 插入devices 連結清單,driver 插入drivers 連結清單。這樣通過總線就能找到每一個裝置,每一個驅動。

裝置和驅動又是如何聯系?

原來是把每一個要用的裝置在計算機啟動之前就已經插好了,插放在它應該在的位置上,然後計算機啟動,然後作業系統開始初始化,總線開始掃描裝置,每找到一個裝置,就為其申請一個structdevice 結構,并且挂入總線中的devices 連結清單中來,然後每一個驅動程式開始初始化,開始注冊其struct device_driver 結構,然後它去總線的devices 連結清單中去尋找(周遊),去尋找每一個還沒有綁定驅動的裝置,structdevice 中的structdevice_driver 指針仍為空的裝置,然後它會去觀察這種裝置的特征,看是否是他所支援的裝置,如果是,那麼調用一個叫做device_bind_driver 的函數,然後他們就結為了秦晉之好。換句話說,把structdevice 中的structdevice_driverdriver 指向這個驅動,而struct device_driver driver 把struct device 加入他的那structklist klist_devices連結清單中來。就這樣,bus、device 和driver,這三者之間或者說他們中的兩兩之間,就給聯系上了。知道其中之一,就能找到另外兩個。

但現在情況變了,出現了一種新的名詞,叫熱插拔。裝置可以在計算機啟動以後在插入或者拔出計算機了。裝置可以在任何時刻出現,而驅動也可以在任何時刻被加載,是以,出現的情況就是,每當一個structdevice 誕生,它就會去bus 的drivers連結清單中尋找自己的另一半,反之,每當一個struct device_driver 誕生,它就去bus的devices 連結清單中尋找它的那些裝置。如果找到了合适的,那麼OK,和之前那種情況一下,調device_bind_driver 綁定好。如果找不到,沒有關系,等待吧!

(二)、 驅動注冊的代碼遊走

Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系

其中 ptr是指向正被使用的某類型變量指針;type是包含ptr指向的變量類型的結構類型;member是type結構體中的成員,類型與ptr指向的變量類型一樣。功能是計算傳回包含ptr指向的變量所在的type類型結構變量的指針。(比較拗口)該宏的實作思路:計算type結構體成員member在結構體中的偏移量,然後ptr的位址減去這個偏移量,就得出type結構變量的首位址。該宏的實作方法:1、通過typeof關鍵字定義一個與type結構體的member成員相同的類型的變量__mptr且将ptr值賦給它。            

2、用宏offsetof(type,member),擷取member成員在type結構中的偏移量(原型:offsetof(TYPE,MEMBER)((size_t)&(TYPE *)0)->MEMBER). 定義在stddef.h.)            

3、最後将__mptr值減去這個偏移量,就得到這個結構變量的位址了(亦指針)。

Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系

(三)、裝置注冊代碼

以USB檢測為例

Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系

中間省略了一部分代碼:

Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系

中間省略N行

Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系

(四)、探測函數probe的尋根

很多驅動都會有probe函數,probe函數不像read和write函數那樣是經過調用才執行,probe函數會在驅動安裝或裝置被發現的時候執行,這就會設計到兩方面的内容,probe函數到底是怎樣實作的呢?

經過之前的代碼遊走之後,可以發現,在驅動安裝過程中會調用driver_attach函數,通過該函數去檢測對應總線上是否有該驅動所對應的dev裝置,如果有就執行驅動中的probe函數。

對于裝置,當裝置被發現之後最終也會執行一個叫device_attach函數,通過該函數去尋找對應總線中的裝置驅動,當找到對應的裝置驅動之後就去執行驅動中的probe函數。

4.1驅動driver端

Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系

4.2裝置device端

Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系
Linux裝置、總線和驅動之間的關系

繼續閱讀