Condividi tramite


Uso della struttura SPB_TRANSFER_LIST per IOCTLs personalizzati

Se il driver del controller SPB (Simple Peripheral Bus) supporta una o più richieste di I/O personalizzate (IOCTL), usare la struttura SPB_TRANSFER_LIST per descrivere i buffer di lettura e scrittura in queste richieste. Questa struttura offre un modo uniforme per descrivere i buffer in una richiesta ed evitare il sovraccarico di copia del buffer associato alle operazioni di I/O METHOD_BUFFERED.

Se le richieste IOCTL personalizzate usano la struttura SPB_TRANSFER_LIST , il driver del controller SPB deve chiamare il metodo SpbRequestCaptureIotherTransferList per acquisire questi buffer nel contesto del processo dell'origine della richiesta. Il driver può chiamare il metodo SpbRequestGetTransferParameters per accedere a questi buffer.

Le richieste di IOCTL_SPB_FULL_DUPLEX e IOCTL_SPB_EXECUTE_SEQUENCE , definite come parte dell'interfaccia richiesta I/O spB, usano la struttura SPB_TRANSFER_LIST per descrivere i buffer di lettura e scrittura. La struttura SPB_TRANSFER_LIST per una richiesta di IOCTL_SPB_FULL_DUPLEX descrive sia il buffer di scrittura che il buffer di lettura (in tale ordine) nella richiesta. La struttura SPB_TRANSFER_LIST per una richiesta di IOCTL_SPB_EXECUTE_SEQUENCE può descrivere una sequenza arbitraria di buffer di lettura e scrittura.

Analogamente, è possibile definire gli IOCTLs personalizzati per richiedere alle strutture SPB_TRANSFER_LIST di usare una combinazione di buffer di lettura e scrittura e specificare qualsiasi ordinamento dei buffer nell'elenco che potrebbe essere necessario.

Il driver Kernel-Mode Driver Foundation (KMDF) per un dispositivo periferico SPB chiama un metodo come WdfIoTargetSendIoctlSynchronously per inviare una richiesta IOCTL a un controller SPB. Questo metodo include parametri InputBuffer e OutputBuffer . I driver per alcuni tipi di dispositivi possono usare questi due parametri per puntare rispettivamente al buffer di scrittura e al buffer di lettura per una richiesta IOCTL. Tuttavia, per inviare una richiesta IOCTL a un controller SPB, il driver del dispositivo spB imposta il parametro InputBuffer per puntare a un descrittore di memoria che punta a una struttura SPB_TRANSFER_LIST . Questa struttura descrive tutti i buffer di lettura o scrittura necessari per l'operazione di controllo I/O. Il driver imposta il parametro OutputBuffer su NULL.

Analogamente, il driver User-Mode Driver Foundation (UMDF) per un dispositivo periferica SPB chiama un metodo come IWDFIoTarget::FormatRequestForIoctl per formattare una richiesta di I/O per un'operazione di controllo I/O. Questo metodo include parametri pInputMemory e pOutputMemory . I driver per alcuni tipi di dispositivi possono usare questi due parametri per puntare al buffer di scrittura e al buffer di lettura per una richiesta IOCTL. Tuttavia, per inviare una richiesta IOCTL a un controller SPB, il driver del dispositivo periferica SPB imposta il parametro pInputMemory per puntare a un oggetto di memoria contenente una struttura SPB_TRANSFER_LIST . Questa struttura descrive tutti i buffer di lettura o scrittura necessari per l'operazione di controllo I/O. Il driver imposta il parametro pOutputMemory su NULL.

Controllo dei parametri e acquisizione del buffer

Quando l'estensione del framework SPB (SpbCx) riceve una richiesta di IOCTL_SPB_EXECUTE_SEQUENCE , SpbCx passa questa richiesta al driver del controller SPB chiamando la funzione EvtSpbControllerIoSequence del driver. Prima di questa chiamata, SpbCx controlla la struttura di SPB_TRANSFER_LIST che descrive i buffer nella richiesta. SpbCx acquisisce questi buffer nel contesto del processo dell'origine della richiesta. I buffer nella memoria in modalità utente possono essere accessibili solo nel processo in cui è allocata la memoria. SpbCx verifica inoltre se i valori dei parametri nella richiesta sono validi.

Quando SpbCx riceve una richiesta IOCTL_SPB_FULL_DUPLEX o una richiesta IOCTL personalizzata, SpbCx passa questa richiesta al driver del controller SPB chiamando la funzione di callback EvtSpbControllerIother del driver. Prima di effettuare questa chiamata, SpbCx non verifica la convalida dei valori dei parametri nella richiesta e non acquisisce i buffer della richiesta nel contesto dell'origine. Il controllo dei parametri e l'acquisizione del buffer per queste richieste è responsabilità del driver del controller SPB.

Se un driver del controller SPB supporta la richiesta di IOCTL_SPB_FULL_DUPLEX o supporta qualsiasi richiesta IOCTL personalizzata che usa la struttura SPB_TRANSFER_LIST per i buffer, il driver deve implementare una funzione di callback EvtIoInCallerContext . Il driver fornisce un puntatore a questa funzione come parametro di input nella chiamata al metodo SpbControllerSetIotherCallback che registra la funzione evtSpbControllerIother callback del driver. Quando SpbCx riceve una richiesta IOCTL_SPB_FULL_DUPLEX o una richiesta IOCTL personalizzata, SpbCx chiama la funzione EvtIoInCallerContext del driver nel contesto dell'origine. Se la richiesta IOCTL usa la struttura SPB_TRANSFER_LIST , la funzione EvtIoInCallerContext chiama il metodo SpbRequestCaptureIotherTransferList per acquisire i buffer nella richiesta. La funzione EvtIoInCallerContext potrebbe anche eseguire un'elaborazione preliminare della richiesta.

Nell'esempio di codice seguente viene illustrata una funzione EvtIoInCallerContext implementata da un driver controller SPB.

VOID
EvtIoInCallerContext(
    _In_  WDFDEVICE   SpbController,
    _In_  WDFREQUEST  FxRequest
    ) 
{
    NTSTATUS status = STATUS_SUCCESS;
    WDF_REQUEST_PARAMETERS fxParams;
  
    WDF_REQUEST_PARAMETERS_INIT(&fxParams);
    WdfRequestGetParameters(FxRequest, &fxParams);

    if ((fxParams.Type != WdfRequestTypeDeviceControl) &&
        (fxParams.Type != WdfRequestTypeDeviceControlInternal))
    {
        status = STATUS_NOT_SUPPORTED;
        goto exit;
    }

    //
    // The driver should check for custom IOCTLs that it handles.
    // If the IOCTL is not recognized, complete the request with a
    // status of STATUS_NOT_SUPPORTED.
    //

    switch (fxParams.Parameters.DeviceIoControl.IoControlCode)
    {
        ...

    default:
        status = STATUS_NOT_SUPPORTED;
        goto exit;
    }

    //
    // The IOCTL is recognized. Capture the buffers in the request.
    //

    status = SpbRequestCaptureIoOtherTransferList((SPBREQUEST)FxRequest);

    //
    // If the capture fails, the driver must complete the request instead
    // of placing it in the SPB controller's request queue.
    //

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

    status = WdfDeviceEnqueueRequest(SpbController, FxRequest);

    if (!NT_SUCCESS(status))
    {
        goto exit;
    }

exit:

    if (!NT_SUCCESS(status))
    {
        WdfRequestComplete(FxRequest, status);
    }
}

Nell'esempio switch di codice precedente l'istruzione verifica che la richiesta contenga un IOCTL riconosciuto dal driver del controller SPB. Per brevità, il corpo dell'istruzione switch non viene visualizzato. Successivamente, la chiamata al metodo SpbRequestCaptureIotherTransferList acquisisce i buffer nella richiesta. Se questa chiamata ha esito positivo, la richiesta viene aggiunta alla coda di I/O del controller SPB. In caso contrario, la richiesta viene completata con un codice di stato di errore.

Per un esempio di codice che mostra il controllo dei parametri da una funzione EvtSpbControllerIother , vedere Gestione delle richieste di IOCTL_SPB_FULL_DUPLEX.