Linux設備模型中三個很重要的概念就是總線,設備,驅(qū)動.即bus,device,driver,而實際上內(nèi)核中也定義了這么一些數(shù)據(jù)結構,他們是 struct bus_type,struct device,struct device_driver,這三個重要的數(shù)據(jù)結構都來自一個地方,include/linux/device.h.我們知道總線有很多種,pci總線,scsi總線,usb 總線,所以我們會看到 Linux 內(nèi)核代碼中出現(xiàn)pci_bus_type,scsi_bus_type,usb_bus_type,他們都是struct bus_type類型的變量.而struct bus_type結構中兩個非常重要的成員就是 struct kset drivers 和 struct kset devices.kset 和另一個叫做 kobject正是 Linux Kernel 2.6中設備模型的基本元素,但此處我們卻不愿多講,因為暫時不用去認識他們.我們的生命中會遇見許許多多的人和事,但更多的人和事與我們只是擦肩而過,只是我們生命中的過客而已.在我們?nèi)松碾娪爸?他們也許只有一個鏡頭,甚至那一個鏡頭后來也被剪輯掉了.這里我們只需要知道,drivers 和 devices 的存在,讓struct bus_type與兩個鏈表聯(lián)系了起來,一個是 devices 的鏈表,一個是drivers 的鏈表,也就是說,知道一條總線所對應的數(shù)據(jù)結構,就可以找到這條總線所關聯(lián)的設備有哪些,又有哪些支持這類設備的驅(qū)動程序.
而要實現(xiàn)這些,就要求每次出現(xiàn)一個設備就要向總線匯報,或者說注冊,每次出現(xiàn)一個驅(qū)動,也要向總線報,或者說注冊.比如系統(tǒng)初始化的時候,會掃描連接了哪些設備,并為每一個設備建立起一個 struct device的變量,每一次有一個驅(qū)動程序,就要準備一個 struct device_driver結構的變量.把這些變量統(tǒng)統(tǒng)加入相應的鏈表,device插入devices鏈表,driver插入drivers鏈表. 這樣通過總線就能找到每一個設備,每一個驅(qū)動.
然而,假如計算機里只有設備卻沒有對應的驅(qū)動,那么設備無法工作.反過來,倘若只有驅(qū)動卻沒有設備,驅(qū)動也起不了任何作用.在他們遇見彼此之前,雙方都如同路埂的野草,一個飄啊飄,一個搖啊搖,誰也不知道未來在哪里,只能在生命的風里飄搖.于是總線上的兩張表里就慢慢的就掛上了那許多孤單的靈魂.devices 開始多了,drivers 開始多了,他們像是兩個來自世界,devices 們彼此取暖,drivers 們一起狂歡,但他們有一點是相同的,都只是在等待屬于自己的那個另一半.
看代碼的我,一直好奇的想知道,他們是否和我們現(xiàn)實中一樣,有些人注定是等別人,而有些人是注定被人等的.
struct bus_type中為 devices 和 drivers 準備了兩個鏈表,而代表 device的結構體struct device中又有兩個成員,struct bus_type *bus 和struct device_driver *driver,同樣,代表driver 的結構體 struct device_driver同樣有兩個成員,struct bus_type *bus和 struct list_head devices,struct device和 struct device_driver的定義和 struct bus_type一樣,在 include/linux/device.h 中.憑一種男人的直覺,可以知曉,struct device中的 bus記錄的是這個設備連在哪條總線上,driver記錄的是這個設備用的是哪個驅(qū)動,反過來,struct device_driver中的bus代表的也是這個驅(qū)動屬于哪條總線,devices記錄的是這個驅(qū)動支持的那些設備,沒錯,是devices(復數(shù)),而不是device(單數(shù)),因為一個驅(qū)動程序可以支持一個或多個設備,反過來一個設備則只會綁定給一個驅(qū)動程序.
于是我們想知道,關于 bus,關于 device,關于 driver,他們是如何建立聯(lián)系的呢?換言之,這三個數(shù)據(jù)結構中的指針是如何被賦值的?絕對不可能發(fā)生的事情是,一旦為一條總線申請了一個struct bus_type的數(shù)據(jù)結構之后,它就知道它的devices鏈表和drivers鏈表會包含哪些東西,這些咚咚一定不會是先天就有的,只能是后天填進來的.而具體到usb 系統(tǒng),完成這個工作的就是usb core.usb core的代碼會進行整個 usb 系統(tǒng)的初始化,比如申請struct bus_type usb_bus_type,然后會掃描 usb 總線,看線上連接了哪些usb設備,或者說 root hub上連了哪些usb設備,比如說連了一個usb鍵盤,那么就為它準備一個struct device,根據(jù)它的實際情況,為這個struct device賦值,并插入devices鏈表中來.又比如root hub上連了一個普通的hub,那么除了要為這個hub 本身準備一個 struct device以外,還得繼續(xù)掃描看這個 hub上是否又連了別的設備,有的話繼續(xù)重復之前的事情,這樣一直進行下去,直到完成整個掃描,最終就把
usb_bus_type中的 devices鏈表給建立了起來. 那么 drivers鏈表呢?這個就不用bus方面主動了,而該由每一個 driver 本身去 bus上面登記,或者說掛牌。
bus上的兩張鏈表記錄了每一個device和driver,那么device和driver這兩者之間又是如何聯(lián)系起來的
呢?此刻,必須拋出這樣一個問題,先有device還是 driver?
很久很久以前,在那激情燃燒的歲月里,先有的是device,每一個要用的device在計算機啟動之前就已經(jīng)插
好了,插放在它應該在的位置上,然后計算機啟動,然后操作系統(tǒng)開始初始化,總線開始掃描設備,每找到一個設備,就為其申請一個struct device結構,并且掛入總線中的devices鏈表中來,然后每一個驅(qū)動程序開始初始化,開始注冊其struct device_driver結構,然后它去總線的devices鏈表中去尋找(遍歷),去尋找每一個還沒有綁定driver的設備,即struct device中的struct device_driver指針仍為空的設備,然后它會去觀察這種設備的特征,看是否是他所支持的設備,如果是,那么調(diào)用一個叫做device_bind_driver的函數(shù),然后他們就結為了秦晉之好.換句話說,把struct device中的struct device_driver driver指向這個driver,而struct device_driver driver把struct device加入他的那張struct list_headdevices鏈表中來.就這樣,bus,device,和driver,這三者之間或者說他們中的兩兩之間,就給聯(lián)系上了.知道其中之一,就能找到另外兩個.一榮俱榮,一損俱損.
但現(xiàn)在情況變了,在這紅蓮綻放的日子里,在這櫻花傷逝的日子里,出現(xiàn)了一種新的名詞,叫熱插拔.device
可以在計算機啟動以后在插入或者拔出計算機了.因此,很難再說是先有device還是先有driver了.因為都有可能.device可以在任何時刻出現(xiàn),而driver也可以在任何時刻被加載,所以,出現(xiàn)的情況就是,每當一個
struct device誕生,它就會去bus 的drivers鏈表中尋找自己的另一半,反之,每當一個一個struct
device_driver誕生,它就去bus的devices鏈表中尋找它的那些設備.如果找到了合適的,那么ok,和之前
那種情況一下,調(diào)用device_bind_driver綁定好.如果找不到,沒有關系,等待吧,等到曇花再開,等到風景看
透,心中相信,這世界上總有一個人是你所等的,只是還沒有遇到而已.