pci端口是什么_PCI端口扫描
如何获取 PCI 设备的配置和位置信息
更多信息在Windows NT 4.0 上,驱动程序通过扫描总线,并调用 HalGetBusData 和 HalGetBusDataByOffset 这两个 API...在Windows NT 4.0 上,驱动程序通过扫描总线,并调用 HalGetBusData 和 HalGetBusDataByOffset 这两个 API 来获取此信息。在 Windows 2000 和更高版本的 Windows 操作系统中,控制硬件总线的则是它们各自的总线驱动程序,而不是 HAL。因此,在 Windows 2000 和更高版本的 Windows 操作系统中,过去用于提供总线相关信息的所有 Hal API 都已过时。 在Windows 2000 和更高版本的 Windows 操作系统中,驱动程序无须查询设备即可查找资源。驱动程序通过即插即用 (PnP) 管理器的 IRP_MN_START_DEVICE 请求来获取这些资源。通常,正确编写的驱动程序不需要任何这类信息就能正常工作。如果由于某种原因,驱动程序需要获取这些信息,请参照下面的代码示例来获取资源。驱动程序应当是设备驱动程序堆栈的一部分,因为它需要设备的基础物理设备对象 (PDO) 才能发送 PnP 请求。 NTSTATUS ReadWriteConfigSpace( IN PDEVICE_OBJECT DeviceObject, IN ULONG ReadOrWrite, // 0 for read 1 for write IN PVOID Buffer, IN ULONG Offset, IN ULONG Length ) { KEVENT event; NTSTATUS status; PIRP irp; IO_STATUS_BLOCK ioStatusBlock; PIO_STACK_LOCATION irpStack; PDEVICE_OBJECT targetObject; PAGED_CODE(); 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 ); if (ReadOrWrite == 0) { irpStack-MinorFunction = IRP_MN_READ_CONFIG; }else { irpStack-MinorFunction = IRP_MN_WRITE_CONFIG; } irpStack-Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG; irpStack-Parameters.ReadWriteConfig.Buffer = Buffer; irpStack-Parameters.ReadWriteConfig.Offset = Offset; irpStack-Parameters.ReadWriteConfig.Length = Length; // // 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; } 由于只能在 PASSIVE_LEVEL 级别发送 PnP I/O 请求数据包 (IRP),因此不能使用上面的函数在 DISPATCH_LEVEL 级别获取配置信息。 可以执行下列步骤以在 DISPATCH_LEVEL 级别访问配置空间: 在PASSIVE_LEVEL 级别发送一个 IRP_MN_QUERY_INTERFACE,以便从 PCI 总线驱动程序获取直接调用接口结构 (BUS_INTERFACE_STANDARD)。将该结构存储在非分页池内存中(通常存储在 DevcieExtension 中)。 调用SetBusData 和 GetBusData,以便在 DISPATCH_LEVEL 级别访问配置空间。 由于PCI 总线驱动程序将在它返回之前获取接口上的引用计数,因此当不再需要该接口时,必须取消对它的引用。 请使用以下函数在 PASSIVE_LEVEL 级别获取 BUS_INTERFACE_STANDARD: 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; } 以下代码说明了如何使用接口直接调用函数获取总线数据。 bytes = busInterfaceStandard.GetBusData(BR/ busInterfaceStandard.Context, PCI_WHICHSPACE_CONFIG, Buffer Offset, Length); 如果不再需要该接口,请使用以下代码取消对其的引用。取消对该接口的引用之后,请勿调用任何接口例程。 (busInterfaceStandard.InterfaceDereference)( (PVOID)busInterfaceStandard.Context); 请对目标设备的 PDO 使用 IoGetDeviceProperty 函数,以获取总线号、功能号和设备号,如下所示: ULONG propertyAddress, length; USHORT FunctionNumber; DeviceNumber; // // Get the BusNumber. Please read the warning to follow. // 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); 重要说明:PCI 总线编号可能是动态的,会随时发生变化。因此,不建议根据总线编号或使用该信息来直接访问 PCI 端口。这可能会引发系统故障。