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

Переводы статьи Переводы статьи
Код статьи: 253232 - Vizualiza?i produsele pentru care se aplic? acest articol.
Данная статья была ранее опубликована под номером RU253232
Развернуть все | Свернуть все

Аннотация

В данной статье дается описание того, как получить информацию о настройке и размещении (такую как 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 г. - Revision: 1.0
Информация в данной статье относится к следующим продуктам.
  • Microsoft Win32 Device Driver Kit for Windows 2000
Ключевые слова: 
kbhowto kboswin2000 kbwdm kbgrpdsntddk kbddk KB253232

Отправить отзыв

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com