在 IRQL = DISPATCH_LEVEL取得裝置組態資訊
在 IRQL = 取得裝置設定資訊 = PASSIVE_LEVEL 一節中說明的方法會使用 I/O 要求封包 (IRP) ,因此僅適用于在 IRQL = PASSIVE_LEVEL上執行的驅動程式。 在 IRQL = DISPATCH_LEVEL執行的驅動程式必須使用匯流排界面來取得裝置設定空間資料。 若要取得此資料,您可以使用匯流排特定的介面或系統提供的與匯流排無關的匯流排界面, BUS_INTERFACE_STANDARD。
) 中 wdmguid.h
定義的GUID_BUS_INTERFACE_STANDARD介面 (可讓設備磁碟機直接呼叫父匯流排驅動程式常式,而不是使用 I/O 要求封包, (IRP) 與匯流排驅動程式通訊。 特別是,此介面可讓驅動程式存取匯流排驅動程式針對下列函式所提供的常式:
- 翻譯匯流排位址
- 在匯流排配接器支援 DMA 的情況下,擷取 DMA 配接器結構
- 讀取和設定匯流排上特定裝置的匯流排設定空間
若要使用此介面,請使用 InterfaceType = GUID_BUS_INTERFACE_STANDARD,將IRP_MN_QUERY_INTERFACE IRP 傳送至匯流排驅動程式。 匯流排驅動程式會提供BUS_INTERFACE_STANDARD結構的指標,其中包含介面個別常式的指標。
最好盡可能使用 BUS_INTERFACE_STANDARD ,因為使用 BUS_INTERFACE_STANDARD時不需要擷取組態資訊,而驅動程式在擷取匯流排特定介面時通常必須識別匯流排號碼。 某些公車的匯流排號碼,例如 PCI,可能會動態變更。 因此,驅動程式不應該依賴匯流排號碼直接存取 PCI 埠。 這樣做可能會導致系統失敗。
在 IRQL = DISPATCH_LEVEL存取 PCI 裝置的設定空間時,需要三個步驟:
在 IRQL = PASSIVE_LEVEL 傳送 IRP_MN_QUERY_INTERFACE 要求,以從 PCI 匯流排驅動程式取得直接呼叫介面結構 (BUS_INTERFACE_STANDARD) 。 將此儲存在非分頁集區記憶體 (通常位於裝置擴充功能) 中。
呼叫 BUS_INTERFACE_STANDARD 介面常式 SetBusData 和 GetBusData,以存取 IRQL = DISPATCH_LEVEL的 PCI 組態空間。
取值 介面。 PCI 匯流排驅動程式在傳回介面之前,會先取得介面的參考計數,因此存取介面的驅動程式必須在不再需要之後將其取值。
下列程式碼範例示範如何實作下列三個步驟:
NTSTATUS
GetPCIBusInterfaceStandard(
IN PDEVICE_OBJECT DeviceObject,
OUT PBUS_INTERFACE_STANDARD BusInterfaceStandard
)
/*++
Routine Description:
This routine gets the bus interface standard information from the PDO.
Arguments:
DeviceObject - Device object to query for this information.
BusInterface - Supplies a pointer to the retrieved information.
Return Value:
NT status.
--*/
{
KEVENT event;
NTSTATUS status;
PIRP irp;
IO_STATUS_BLOCK ioStatusBlock;
PIO_STACK_LOCATION irpStack;
PDEVICE_OBJECT targetObject;
Bus_KdPrint(("GetPciBusInterfaceStandard entered.\n"));
KeInitializeEvent(&event, NotificationEvent, FALSE);
targetObject = IoGetAttachedDeviceReference(DeviceObject);
irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
targetObject,
NULL,
0,
NULL,
&event,
&ioStatusBlock);
if (irp == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto End;
}
irpStack = IoGetNextIrpStackLocation( irp );
irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
irpStack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
irpStack->Parameters.QueryInterface.Version = 1;
irpStack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterfaceStandard;
irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
// Initialize the status to error in case the bus driver does not
// set it correctly.
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
status = IoCallDriver(targetObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatusBlock.Status;
}
End:
// Done with reference
ObDereferenceObject(targetObject);
return status;
}
下列程式碼片段示範如何使用 GetBusData 介面常式來取得設定空間資料, (步驟 2) 。
bytes = busInterfaceStandard.GetBusData(
busInterfaceStandard.Context,
PCI_WHICHSPACE_CONFIG,
Buffer
Offset,
Length);
當驅動程式使用 介面完成時,可以使用類似下列程式碼片段的程式碼來取值介面, (步驟 3) 。 在取消參考介面之後,驅動程式不得呼叫介面常式。
(busInterfaceStandard.InterfaceDereference)(
(PVOID)busInterfaceStandard.Context);
介面會將呼叫端對匯流排硬體的存取與 PCI 匯流排驅動程式的存取同步。 驅動程式寫入器不需要擔心建立微調鎖定,以避免與 PCI 匯流排驅動程式爭用以存取匯流排硬體。
請注意,如果需要的都是匯流排、函式和裝置號碼,通常不需要使用匯流排界面來取得這項資訊。 您可以將目標裝置的 PDO 傳遞至 IoGetDeviceProperty 函式 ,以間接擷取此資料,如下所示:
ULONG propertyAddress, length;
USHORT FunctionNumber, DeviceNumber;
// Get the BusNumber. Be warned that bus numbers may be
// dynamic and therefore subject to change unpredictably!!!
IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyBusNumber,
sizeof(ULONG),
(PVOID)&BusNumber,
&length);
// Get the DevicePropertyAddress
IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyAddress,
sizeof(ULONG),
(PVOID)&propertyAddress,
&length);
// For PCI, the DevicePropertyAddress has device number
// in the high word and the function number in the low word.
FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);