Delen via


Verkrijgen van apparaatconfiguratie-informatie op IRQL = DISPATCH_LEVEL

De methode die wordt geïllustreerd in de sectie Apparaatconfiguratiegegevens ophalen bij IRQL = PASSIVE_LEVEL maakt gebruik van I/O-aanvraagpakketten (IRP's) en is daarom alleen geldig voor stuurprogramma's die worden uitgevoerd op IRQL = PASSIVE_LEVEL. Stuurprogramma's die worden uitgevoerd op IRQL = DISPATCH_LEVEL moeten een businterface gebruiken om apparaatconfiguratieruimtegegevens te verkrijgen. Als u deze gegevens wilt verkrijgen, kunt u een busspecifieke interface of de door het systeem geleverde busonafhankelijke businterface gebruiken, BUS_INTERFACE_STANDARD.

Met de GUID_BUS_INTERFACE_STANDARD-interface (gedefinieerd in wdmguid.h) kunnen apparaatstuurprogramma's directe aanroepen uitvoeren naar routines van bovenliggende busstuurprogramma's in plaats van I/O-aanvraagpakketten (IRP) te gebruiken om te communiceren met het busstuurprogramma. Met deze interface kunnen stuurprogramma's met name toegang krijgen tot routines die het busstuurprogramma biedt voor de volgende functies:

  • Busadressen vertalen
  • Een DMA-adapterstructuur ophalen in gevallen waarin de busadapter DMA ondersteunt
  • De busconfiguratieruimte voor een bepaald apparaat in de bus lezen en instellen

Als u deze interface wilt gebruiken, stuurt u een IRP_MN_QUERY_INTERFACE IRP naar uw busstuurprogramma met InterfaceType = GUID_BUS_INTERFACE_STANDARD. De buschauffeur levert een aanwijzer naar een BUS_INTERFACE_STANDARD structuur die aanwijzers bevat naar de afzonderlijke routines van de interface.

Het verdient de voorkeur om waar mogelijk BUS_INTERFACE_STANDARD te gebruiken, omdat een busnummer niet nodig is om configuratiegegevens op te halen bij het gebruik van BUS_INTERFACE_STANDARD, terwijl stuurprogramma's vaak het busnummer moeten identificeren bij het ophalen van busspecifieke interfaces. Busnummers voor sommige bussen, zoals PCI, kunnen dynamisch veranderen. Daarom moeten stuurprogramma's niet afhankelijk zijn van het busnummer om rechtstreeks toegang te krijgen tot de PCI-poorten. Als u dit doet, kan dit leiden tot systeemfouten.

Er zijn drie stappen vereist voor toegang tot de configuratieruimte van een PCI-apparaat op IRQL = DISPATCH_LEVEL:

  1. Verzend een IRP_MN_QUERY_INTERFACE aanvraag bij IRQL = PASSIVE_LEVEL om de interfacestructuur (BUS_INTERFACE_STANDARD) van het PCI-busstuurprogramma op te halen. Sla dit op in een niet-gepagineerde geheugenpool (meestal in een apparaatuitbreiding).

  2. Roep de BUS_INTERFACE_STANDARD interfaceroutines, SetBusData en GetBusData, aan om toegang te krijgen tot de PCI-configuratieruimte op IRQL = DISPATCH_LEVEL.

  3. Dereferentie van de interface. Het PCI Bus-stuurprogramma houdt een referentietelling bij op de interface voordat het wordt geretourneerd. Het stuurprogramma dat toegang heeft tot de interface moet deze derefereren, wanneer deze niet meer nodig is.

In het volgende codevoorbeeld ziet u hoe u deze drie stappen implementeert:

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;
}

In het volgende codefragment ziet u hoe u de GetBusData-interfaceroutine gebruikt om de configuratieruimtegegevens op te halen (stap 2).

 bytes = busInterfaceStandard.GetBusData(
                    busInterfaceStandard.Context,
                    PCI_WHICHSPACE_CONFIG,
                    Buffer
                    Offset,
                    Length);

Wanneer de driver de interface heeft afgerond, kan het code gebruiken die vergelijkbaar is met het volgende codefragment om de interface te dereferen (stap 3). Stuurprogramma's mogen geen interfaceroutines aanroepen na het derefereren van de interface.

    (busInterfaceStandard.InterfaceDereference)(
                    (PVOID)busInterfaceStandard.Context);

De interface synchroniseert de toegang van de beller tot de bushardware met de toegang van het PCI-busstuurprogramma. De ontwikkelaar van de stuurprogramma hoeft zich geen zorgen te maken over het creëren van spinlocks om te voorkomen dat er strijd is met het PCI-busstuurprogramma voor toegang tot de bushardware.

Houd er rekening mee dat als alles wat nodig is bus-, functie- en apparaatnummers zijn, meestal niet nodig is om naar een businterface te gaan om deze informatie te verkrijgen. Deze gegevens kunnen indirect worden opgehaald door de PDO van het doelapparaat als volgt door te geven aan de functie 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);