1. 程式人生 > >Linux裝置、匯流排和驅動之間的關係

Linux裝置、匯流排和驅動之間的關係

(一)、驅動、匯流排和裝置的主要資料結構

include/linux/device.h)


/driver/base/base.h

 

(include/device.h)





匯流排中的那兩條連結串列是怎麼形成的。核心要求每次出現一個裝置就要向匯流排彙報,或者說註冊,每次出現一個驅動,也要向匯流排彙報,或者說註冊。比如系統初始化的時候,會掃描連線了哪些裝置,併為每一個裝置建立起一個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 繫結好。如果找不到,沒有關係,等待吧!

(二)、驅動註冊的程式碼遊走








其中 ptr是指向正被使用的某型別變數指標;

type是包含ptr指向的變數型別的結構型別;membertype結構體中的成員,型別與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值減去這個偏移量,就得到這個結構變數的地址了(亦指標)。



(三)、設備註冊程式碼

以USB檢測為例





中間省略了一部分程式碼:



中間省略N行






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

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

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

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

4.1驅動driver端


4.2裝置device端