一個驅(qū)動程序為它所控制的每個設(shè)備產(chǎn)生設(shè)備對象,設(shè)備對象代表驅(qū)動程序的設(shè)備。從PnP的角度看有三種設(shè)備對象:
n 物理設(shè)備對象(PDO)---代表一個總線驅(qū)動程序的總線上的設(shè)備
n 功能設(shè)備對象(FDO)---代表一個功能驅(qū)動程序的設(shè)備
n 過濾程序設(shè)備對象(Filter DO)---代表一個過濾器驅(qū)動程序的設(shè)備
這三種設(shè)備對象都是DEVICE_OBJECT類型,但是使用方式不同并有不同的設(shè)備擴(kuò)展。
通過產(chǎn)生一設(shè)備對象(IoCreateDevice)并將其附著到設(shè)備堆棧(IoAttachDeviceToDevice_Stack),驅(qū)動程序?qū)⑵浔旧硖砑拥教幚碓O(shè)備的I/O驅(qū)動程序堆棧,IoAttachDeviceToDeviceStack決定設(shè)備堆棧當(dāng)前的頂層和附著新的設(shè)備對象到設(shè)備堆棧的頂層。
圖1.7給出了設(shè)備對象的可能種類,該設(shè)備對象可附著于設(shè)備堆棧里,表示處理一個設(shè)備的I/O請求的驅(qū)動程序。
這一部分描述了每一類的設(shè)備對象并注意到何時產(chǎn)生該類。參看第2章獲得關(guān)于在必要的PnP驅(qū)動程序例程里產(chǎn)生設(shè)備對象的細(xì)節(jié)信息,要獲得PnP設(shè)備枚舉的更多信息,參見第2部分。
開始于圖1.7的底部:
n 總線驅(qū)動程序為總線上它所枚舉的每個設(shè)備產(chǎn)生PDO。
當(dāng)總線驅(qū)動程序枚舉其設(shè)備時,它為每個子設(shè)備產(chǎn)生PDO。總線驅(qū)動程序枚舉一設(shè)備為PnP管理器的BusRelations響應(yīng)一個IRP_MN_QUERY_DEVICE_RELATIONS請求。如果自從最近一次總線驅(qū)動程序響應(yīng)BusRelations的查詢關(guān)系請求以來(或者這是機(jī)器被引導(dǎo)以來第一次查詢關(guān)系)設(shè)備已經(jīng)添加到總線上,則總線驅(qū)動程序為每個子設(shè)備產(chǎn)生一個PDO。
PDO表示了總線驅(qū)動程序的設(shè)備,其他內(nèi)核模式系統(tǒng)組件也和它一樣,如電源管理器、PnP管理器和I/O管理器。
一個設(shè)備其他的驅(qū)動程序附著于PDO頂端的設(shè)備對象,但是PDO一直在設(shè)備堆棧的底端。
n 可選擇的總線過濾器驅(qū)動程序為它們過濾的每個設(shè)備產(chǎn)生過濾程序DO。
當(dāng)PnP管理器在BusRelations列表里發(fā)現(xiàn)一個新設(shè)備時,它決定是否有該設(shè)備的任何總線過濾器驅(qū)動程序。如果是這樣的話,對每個這樣的驅(qū)動程序PnP管理器確保它們被裝載(如果需要調(diào)用DriverEntry)并調(diào)用驅(qū)動程序AddDevice例程。如果總線過濾器驅(qū)動程序為這個設(shè)備過濾操作,過濾器驅(qū)動程序產(chǎn)生一個設(shè)備對象并附著它到AddDevice例程里的設(shè)備堆棧上。如果不止一個總線過濾器驅(qū)動程序存在,且與這個設(shè)備相關(guān),每個這樣的過濾器驅(qū)動程序產(chǎn)生并附著于它自己的設(shè)備對象。
n 可選擇的,低層過濾器驅(qū)動程序為它們過濾的每個設(shè)備產(chǎn)生過濾程序DO。
如果一可選擇的低層過濾器驅(qū)動程序由于這個設(shè)備的原因而存在,PnP管理器確信在總線驅(qū)動程序和任何總線過濾器驅(qū)動程序之后裝載了這樣的驅(qū)動程序。PnP管理器調(diào)用過濾器驅(qū)動程序的AddDevice例程,在它的AddDevice例程里,低層的過濾器驅(qū)動程序為設(shè)備產(chǎn)生一個過濾程序DO且附著它到設(shè)備堆棧里。如果不止一個低層過濾器驅(qū)動程序存在,每個這樣的驅(qū)動程序?qū)a(chǎn)生并附著它自己的過濾程序DO。
n 功能驅(qū)動程序為設(shè)備產(chǎn)生一個FDO。
PnP管理器確信已安裝了設(shè)備的功能驅(qū)動程序并調(diào)用功能驅(qū)動程序的AddDevice例程,功能驅(qū)動程序產(chǎn)生一個FDO并附著它到設(shè)備堆棧里。
n 可選擇的,頂層過濾器驅(qū)動程序為它們過濾的每個設(shè)備產(chǎn)生過濾程序DO。
如果任何可選擇的,頂層過濾器驅(qū)動程序為設(shè)備而存在,PnP管理器確信在功能驅(qū)動程序調(diào)用它們的AddDevice例程之后被安裝,每個這樣的過濾器驅(qū)動程序附著它的設(shè)備對象到設(shè)備堆棧。
總之,設(shè)備堆棧包括每一驅(qū)動程序的設(shè)備對象,該驅(qū)動程序參與了特定設(shè)備的I/O處理。父總線驅(qū)動程序有一個PDO,功能驅(qū)動程序有一個FDO,每一個可選擇的過濾器驅(qū)動程序有一個過濾程序DO。
注意到所有的設(shè)備---總線適配器/控制器設(shè)備和非總線設(shè)備---在它們的設(shè)備堆棧里有一個PDO和FDO。總線適配器/控制器的PDO由父總線的總線驅(qū)動程序產(chǎn)生。例如,如果一個SCSI適配器插入一個PCI總線,PCI總線驅(qū)動程序為SCSI適配器產(chǎn)生一個PDO。
如果一個設(shè)備正以原始模式使用,則沒有功能驅(qū)動程序或過濾器驅(qū)動程序(沒有FDO或過濾程序DO)。此時還有父總線驅(qū)動程序的一個PDO和零個或更多總線過濾程序DO。
要獲取哪一個驅(qū)動程序例程負(fù)責(zé)產(chǎn)生和附著設(shè)備對象的信息,參看第2章。
設(shè)備堆棧和一些額外信息構(gòu)成了一個devnode設(shè)備。在一個設(shè)備的devnode里,PnP管理器保留諸如是否設(shè)備已經(jīng)啟動和哪一個驅(qū)動程序,如有,登記通知設(shè)備上的改變。內(nèi)核調(diào)試程序!devnode命令顯示了關(guān)于一個devnode的信息。