Как получить информацию о настройке и расположении устройства PCI

Аннотация

В данной статье дается описание того, как получить информацию о настройке и размещении (такую как 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:

  1. Отправьте запрос IRP_MN_QUERY_INTERFACE на уровень PASSIVE_LEVEL для получения интерфейса структуры прямого доступа (BUS_INTERFACE_STANDARD) от драйвера шины PCI. Сохраните его в неперемещаемой области памяти (обычно это DeviceExtension).

  2. Вызовите процедуры SetBusData и GetBusData для получения доступа к пространству уровня DISPATCH_LEVEL.

  3. Драйвер шины PCI получает ссылку на интерфейс перед возвратом, поэтому Вы должны очистить ссылку на интерфейс после того, как необходимость в ней отпадет.

  4. Используйте следующую функцию для получения 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

Отзывы и предложения