В данной статье дается описание того, как получить информацию о настройке и размещении (такую как BusNumber, DeviceNumber и Function Number) устройства PCI (Peripheral Component Interconnect) из драйвера, являющегося частью стека драйверов требуемого устройства, куда также входят фильтр драйвера или его функция.
В Windows NT 4.0 драйверы получают информацию путем сканирования шины и вызова таких процедур API, как HalGetBusData и HalGetBusDataByOffset. В Windows 2000 шины устройств контролируются при помощи соответствующих драйверов, а не при помощи ядра операционной системы. Поэтому все API, используемые для предоставления информации о шине, не нужны в Windows 2000.
В Windows 2000 драйверу не нужно запрашивать устройство для получения ресурсов. Драйвер получает ресурсы от менеджера "Plug and Play" при помощи запроса IRP_MN_START_DEVICE. Обычно правильно написанный драйвер не будет запрашивать подобную информацию для корректного функционирования. Если по некоторым причинам драйверу требуется такая информация, то в нижепреведенном примере показывается, как получить информацию о ресурсах. Драйвер должен быть частью стека драйверов, так как это требование лежит в основе структуры PDO (physical device objects) устройства для отправки запроса PnP.
Следующий пример кода демонстрирует, как получить информацию о настройке:
NTSTATUS
ReadWriteConfigSpace(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG ReadOrWrite, // 0 для чтения 1 для записи
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;
//
// Установка статуса в состояние "ошибка", если драйвер шины
// установился некорректно.
//
irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
status = IoCallDriver( targetObject, irp );
if (status == STATUS_PENDING) {
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
status = ioStatusBlock.Status;
}
End:
//
// Завершение со связями
//
ObDereferenceObject( targetObject );
return status;
}Так как Вы можете послать только пакеты запроса PnP (IRP) на уровень PASSIVE_LEVEL, Вы не можете использовать вышерпиведенную функцию для получения информации с уровня DISPATCH_LEVEL.
Вы можете выполнить следующие действия для получения доступа к пространству настроек уровня DISPATCH_LEVEL:
- Отправьте запрос IRP_MN_QUERY_INTERFACE на уровень PASSIVE_LEVEL для получения интерфейса структуры прямого доступа (BUS_INTERFACE_STANDARD) от драйвера шины PCI. Сохраните его в неперемещаемой области памяти (обычно это DeviceExtension).
- Вызовите процедуры SetBusData и GetBusData для получения доступа к пространству уровня DISPATCH_LEVEL.
- Драйвер шины PCI получает ссылку на интерфейс перед возвратом, поэтому Вы должны очистить ссылку на интерфейс после того, как необходимость в ней отпадет.
- Используйте следующую функцию для получения BUS_INTERFACE_STANDARD на уровне PASSIVE_LEVEL:
NTSTATUS
GetPCIBusInterfaceStandard(
IN PDEVICE_OBJECT DeviceObject,
OUT PBUS_INTERFACE_STANDARDBusInterfaceStandard
)
/*++
Описание программы:
Эта программа получает стандартную информацию шинного интерфейса из PDO.
Аргументы:
DeviceObject - Объект устройства для запроса данной информации.
BusInterface - Устанавливает указатель на получаемую информацию.
Возвращаемые значения:
Статус NT.
--*/
{
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;
//
// Установка статуса в состояние "ошибка", если драйвер шины
// установился некорректно.
//
irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
status = IoCallDriver( targetObject, irp );
if (status == STATUS_PENDING) {
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
status = ioStatusBlock.Status;
}
End:
//
// Завершение со связями
//
ObDereferenceObject( targetObject );
return status;
}
Следующий пример кода показывает, как использовать интерфейс функции прямого вызова для получения данных шины.
bytes = busInterfaceStandard.GetBusData(<BR/>
busInterfaceStandard.Context,
PCI_WHICHSPACE_CONFIG,
Buffer
Offset,
Length);После того, как необходимость в интерфейсе отпадет, используйте следующий код, чтобы снять ссылку с интерфейса. Не следует вызывать любой интерфейс программ после удаления ссылки на него.
(busInterfaceStandard.InterfaceDereference)(
(PVOID)busInterfaceStandard.Context);Используйте функцию "IoGetDeviceProperty" из PDO требуемого устройства для получения информации о шине, функции и номере устройства, как это показано ниже:
ULONG propertyAddress, length;
USHORT FunctionNumber; DeviceNumber;
//
// Получение параметра BusNumber. Пожалуйста, сначала прочтите предостережение.
//
IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyBusNumber,
sizeof(ULONG),
(PVOID)&BusNumber,
&length);
//
// Получение параметра DevicePropertyAddress
//
IoGetDeviceProperty(PhysicalDeviceObject,
DevicePropertyAddress,
sizeof(ULONG),
(PVOID)&propertyAddress,
&length);
//
// Для PCI параметр DevicePropertyAddress содержит номер устройства
// в старшем слове, а номер функции в младшем слове
//
FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
Важно:
Номера шины PCI могут быть динамическими и изменяться в любой момент. Поэтому нежелательно получать прямой доступ к порту PCI, используя эту информацию или на основании номера шины. Это может привести к сбою в системе.
Код статьи: 253232 - Последнее изменение :: 5 августа 2002 г. - Редакция: 1.0
Информация в данной статье относится к следующим продуктам.
- Microsoft Win32 Device Driver Kit for Windows 2000
| kbhowto kboswin2000 kbwdm kbgrpdsntddk kbddk KB253232 |