Maskinvaruresurser för User-Mode SPB-kringutrustningsdrivrutiner

Kodexemplen i det här avsnittet visar hur umdf-drivrutinen ( User-Mode Driver Framework ) för en kringutrustningsenhet på en enkel kringutrustningsbuss (SPB) hämtar de maskinvaruresurser som krävs för att använda enheten. I de här resurserna ingår den information som drivrutinen använder för att upprätta en logisk anslutning till enheten. Ytterligare resurser kan omfatta ett avbrott samt en eller flera GPIO-ingångs- eller utgångsstift. (En GPIO-pin är en pin-kod på en allmän I/O-styrenhet som är konfigurerad som indata eller utdata. Mer information finns i GPIO-styrenhetsdrivrutiner.) Till skillnad från en enhet som är minnesmappad kräver inte en SPB-ansluten kringutrustning ett block med systemminnesadresser för att mappa sina register till.

Den här drivrutinen implementerar ett IPnpCallbackHardware2-gränssnitt och registrerar det här gränssnittet med UMDF under anropet till drivrutinens IDriverEntry::OnDeviceAdd-metod . Ramverket anropar metoderna i IPnpCallbackHardware2-gränssnittet för att meddela drivrutinen om ändringar i enhetens energitillstånd.

När strömmen återställs till den SPB-anslutna kringutrustningsenheten anropar drivrutinsramverket IPnpCallbackHardware2::OnPrepareHardware-metoden för att meddela drivrutinen att enheten måste vara förberedd för användning. Under det här anropet tar drivrutinen emot två listor med maskinvaruresurser som indataparametrar. Parametern pWdfResourcesRaw pekar på listan över rådataresurser och parametern pWdfResourcesTranslated pekar på listan över översatta resurser. Båda parametrarna är pekare till IWDFCmResourceList-objekt . De översatta resurserna innehåller det anslutnings-ID som SPB-kringutrustningsdrivrutinen behöver för att upprätta en logisk anslutning till den SPB-anslutna kringutrustningsenheten. Mer information finns i Anslutnings-ID:er för SPB-kringutrustning.

För att en UMDF-kringutrustningsdrivrutin ska kunna ta emot anslutnings-ID:n i resurslistan måste INF-filen som installerar drivrutinen innehålla följande direktiv i avsnittet WDF-specifik DDInstall :

UmdfDirectHardwareAccess = AllowDirectHardwareAccess Mer information om det här direktivet finns i Ange WDF-direktiv i INF Files.

Följande kodexempel visar hur drivrutinens OnPrepareHardware-metod hämtar anslutnings-ID:t från parametern pWdfResourcesTranslated .

BOOLEAN fConnectIdFound = FALSE;
BOOLEAN fDuplicateFound = FALSE;
LARGE_INTEGER connectionId = 0;
ULONG resourceCount;

resourceCount = pWdfResourcesTranslated->GetCount();

// Loop through the resources and save the relevant ones.
for (ULONG ix = 0; ix < resourceCount; ix++)
{
    PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor;

    pDescriptor = pWdfResourcesTranslated->GetDescriptor(ix);

    if (pDescriptor == NULL)
    {
        hr = E_POINTER;
        break;
    }

    // Determine the resource type.
    switch (pDescriptor->Type)
    {
    case CmResourceTypeConnection:
        {
            // Check against the expected connection types.
            UCHAR Class = pDescriptor->u.Connection.Class;
            UCHAR Type = pDescriptor->u.Connection.Type;

            if (Class == CM_RESOURCE_CONNECTION_CLASS_SERIAL)
            {
                if (Type == CM_RESOURCE_CONNECTION_TYPE_SERIAL_I2C)
                {
                    if (fConnIdFound == FALSE)
                    {
                        // Save the SPB connection ID.
                        connectionId.LowPart = pDescriptor->u.Connection.IdLowPart;
                        connectionId.HighPart = pDescriptor->u.Connection.IdHighPart;
                        fConnectIdFound = TRUE;
                    }
                    else
                    {
                        fDuplicateFound = TRUE;
                    }
                }
            }

            if (Class == CM_RESOURCE_CONNECTION_CLASS_GPIO)
            {
                // Check for GPIO pin resource.
                ...
            }
        }
        break;

    case CmResourceTypeInterrupt:
        {
            // Check for interrupt resources.
            ...
        }
        break;

    default:
        // Ignore all other resource descriptors.
        break;
    }
}

I föregående kodexempel kopieras anslutnings-ID:t för en SPB-ansluten kringutrustning till en variabel med namnet connectionId. I följande kodexempel visas hur du införlivar anslutnings-ID:t i ett namn på enhetssökvägen som kan användas för att identifiera kringutrustningen.

WCHAR szTargetPath[100];
HRESULT hres;

// Create the device path using the well-known resource hub
// path name and the connection ID.
//
// TODO: Replace this hardcoded string with the appropriate
//       helper method from Reshub.h when available.
hres = StringCbPrintfW(&szTargetPath[0],
                       sizeof(szTargetPath),
                       L"\\\\.\\RESOURCE_HUB\\%0*I64x",
                       (size_t)(sizeof(LARGE_INTEGER) * 2),
                       connectionId.QuadPart);
if (FAILED(hres))
{
     // Error handling
     ...
}

I föregående kodexempel skrivs sökvägsnamnet för den SPB-anslutna kringutrustningsenheten till matrisen szTargetPath . I följande kodexempel används det här enhetssökvägsnamnet för att öppna en filreferens till den SPB-anslutna kringutrustningsenheten.

UMDF_IO_TARGET_OPEN_PARAMS openParams;

openParams.dwShareMode = 0;
openParams.dwCreationDisposition = OPEN_EXISTING;
openParams.dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED;
hres = pRemoteTarget->OpenFileByName(&szTargetPath[0],
                                     (GENERIC_READ | GENERIC_WRITE),
                                     &openParams);
if (FAILED(hres))
{
    // Error handling
    ...
}

I föregående kodexempel är variabeln pRemoteTarget en pekare till ett IWDFRemoteTarget-objekt . Om anropet till metoden IWDFRemoteTarget::OpenFileByName lyckas kan drivrutinen för den SPB-anslutna kringutrustningsenheten använda objektet IWDFRemoteTarget för att skicka I/O-begäranden till kringutrustningsenheten. Innan drivrutinen skickar en läs-, skriv- eller IOCTL-begäran till kringutrustningen anropar drivrutinen IWDFRemoteTarget::FormatRequestForRead, IWDFRemoteTarget::FormatRequestForWrite eller IWDFRemoteTarget::FormatRequestForIoctl-metoden för att formatera I/O-begäran. Gränssnittet IWDFRemoteTarget ärver dessa tre metoder från gränssnittet IWDFIoTarget. Därefter anropar drivrutinen IWDFIoRequest::Send-metoden för att skicka I/O-begäran till den SPB-anslutna kringutrustningsenheten.

I följande kodexempel anropar SPB-kringutrustningsdrivrutinen metoden Skicka för att skicka en IRP_MJ_WRITE begäran till den SPB-anslutna kringutrustningsenheten.

HRESULT hres;
IWDFMemory *pInputMemory = NULL;
IWDFRemoteTarget *pWdfIoRequest = NULL;

// Create a new I/O request.
if (SUCCEEDED(hres))
{
    hres = pWdfDevice->CreateRequest(NULL, 
                                     pWdfDevice, 
                                     &pWdfIoRequest);
    if (FAILED(hres))
    {
        // Error handling
        ...
    }
}

// Allocate memory for the input buffer.
if (SUCCEEDED(hres))
{
    hres = pWdfDriver->CreatePreallocatedWdfMemory(pInBuffer, 
                                                   inBufferSize, 
                                                   NULL,
                                                   pWdfIoRequest,
                                                   &pInputMemory);
    if (FAILED(hres))
    {
        // Error handling
        ...
    }

    // After this call, the parent holds the only reference.
    pWdfMemory->Release();
}

// Format the I/O request for a write operation.
if (SUCCEEDED(hres))
{
    hres = pRemoteTarget->FormatRequestForWrite(pWdfIoRequest,
                                                NULL,
                                                pInputMemory, 
                                                NULL, 
                                                0);
    if (FAILED(hres))
    {
        // Error handling
        ...
    }
}

// Send the request to the SPB controller.
if (SUCCEEDED(hres))
{
    ULONG Flags = fSynchronous ? WDF_REQUEST_SEND_OPTION_SYNCHRONOUS : 0;

    // Set the I/O completion callback.
    if (!fSynchronous)
    {
        pWdfIoRequest->SetCompletionCallback(pCallback, NULL);
    }

    hres = pWdfIoRequest->Send(pRemoteTarget, Flags, 0);
    if (FAILED(hres))
    {
        // Error handling
        ...
    }
}

if (fSynchronous || FAILED(hres))
{
    pWdfIoRequest->DeleteWdfObject();
    SAFE_RELEASE(pWdfIoRequest);
}

Föregående kodexempel gör följande:

  1. Variabeln pWdfDevice är en pekare till IWDFEnhetsgränssnittet för det ramverksenhetsobjekt som representerar den SPB-anslutna kringutrustningsenheten. Metoden IWDFDevice::CreateRequest skapar en I/O-begäran och kapslar in den här begäran i IWDFIoRequest-gränssnittsinstansen som pekas på av variabeln pWdfIoRequest .
  2. Variabeln pWdfDriver är en pekare till IWDFDriver-gränssnittet för ramverksdrivrutinsobjektet som representerar SPB-kringutrustningsdrivrutinen. Variablerna pInBuffer och inBufferSize anger adressen och storleken på indatabufferten som innehåller data för skrivbegäran. Metoden IWDFDriver::CreatePreallocatedWdfMemory skapar ett ramverksminnesobjekt för indatabufferten och anger det IWDFIoRequest-objekt som pekar på pWdfIoRequest som minnesobjektets överordnade objekt (så att minnesobjektet släpps automatiskt när dess överordnade objekt släpps). När drivrutinen anropar metoden Release för att frigöra sin lokala referens till minnesobjektet, innehåller den överordnade filen den enda referensen till det här objektet.
  3. Variabeln pWdfRemoteTarget är den fjärrmålpekare som hämtades från OpenFileByName-anropet i ett tidigare kodexempel. Metoden IWDFRemoteTarget::FormatRequestForWrite formaterar I/O-begäran för en skrivåtgärd.
  4. Variabeln fSynchronous är TRUE om skrivbegäran ska skickas synkront och är FALSE om den ska skickas asynkront. Variabeln pCallback är en pekare till ett tidigare skapat IRequestCallbackRequestCompletion-gränssnitt . Om begäran ska skickas asynkront registrerar anropet till metoden IWDFIoRequest::SetCompletionCallback det här gränssnittet. Senare anropas metoden IRequestCallbackRequestCompletion::OnCompletion för att meddela drivrutinen när begäran slutförs asynkront.
  5. Metoden Send skickar den formaterade skrivbegäran till den SPB-anslutna kringutrustningsenheten. Variabeln Flags anger om skrivbegäran ska skickas synkront eller asynkront.
  6. Om begäran skickas synkront tar metoden IWDFIoRequest::D eleteWdfObject bort både I/O-begärandeobjektet som pekas på av pWdfIoRequest och det underordnade objektet som pekas på av pInputMemory. Gränssnittet IWDFIoRequest ärver den här metoden från IWDFObject-gränssnittet. Om begäran skickas asynkront bör anropet till metoden DeleteWdfObject ske senare i drivrutinens OnCompletion-metod .

En alternativ implementering av föregående kodexempel kan skapa IWDFIoRequest - och IWDFMemory-objekt under drivrutinsinitieringen och upprepade gånger använda samma objekt i stället för att skapa och ta bort nya objekt varje gång en I/O-begäran skickas. Mer information finns i IWDFIoRequest2::Reuse och IWDFMemory::SetBuffer.

Dessutom kan en alternativ implementering inspektera I/O-statuskoden från I/O-begäran om Skicka-anropet lyckas. Mer information finns i IWDFIoRequest::GetCompletionParams.