共用方式為


使用自訂 IOCTL 的SPB_TRANSFER_LIST結構

如果您的簡單周邊匯流排 (SPB) 控制器驅動程式支援一或多個自訂 I/O 控制項 (IOCTL) 要求,請使用 SPB_TRANSFER_LIST 結構來描述這些要求的讀取和寫入緩衝區。 此結構提供一致的方式來描述要求中的緩衝區,並避免與METHOD_BUFFERED I/O 作業相關聯的緩衝區複製額外負荷。

如果您的自訂 IOCTL 要求使用 SPB_TRANSFER_LIST 結構,SPB 控制器驅動程式必須呼叫 SpbRequestCaptureIoOtherTransferList 方法,以在要求來源器的處理常式內容中擷取這些緩衝區。 您的驅動程式可以呼叫 SpbRequestGetTransferParameters 方法來存取這些緩衝區。

IOCTL_SPB_FULL_DUPLEXIOCTL_SPB_EXECUTE_SEQUENCE要求,這些要求定義為SPB I/O 要求介面的一部分,請使用SPB_TRANSFER_LIST結構來描述其讀取和寫入緩衝區。 IOCTL_SPB_FULL_DUPLEX要求的SPB_TRANSFER_LIST結構描述寫入緩衝區和讀取緩衝區 (,順序) 要求。 IOCTL_SPB_EXECUTE_SEQUENCE要求的SPB_TRANSFER_LIST結構可以描述任意序列的讀取和寫入緩衝區。

同樣地,您可以定義自訂 IOCTL,以要求其 SPB_TRANSFER_LIST 結構使用一些讀取和寫入緩衝區的組合,並在可能需要的清單中指定緩衝區的任何順序。

Kernel-Mode Driver Foundation (SPB 周邊裝置的 KMDF) 驅動程式會呼叫 WdfIoTargetSendIoctlSynchronously 之類的方法,以將 IOCTL 要求傳送至 SPB 控制器。 這個方法具有 InputBufferOutputBuffer 參數。 某些裝置類型的驅動程式可能會使用這兩個參數分別指向 IOCTL 要求的寫入緩衝區和讀取緩衝區。 不過,若要將 IOCTL 要求傳送至 SPB 控制器,SPB 周邊設備磁碟機會將 InputBuffer 參數設定為指向指向 SPB_TRANSFER_LIST 結構的記憶體描述元。 此結構描述 I/O 控制作業所需的任何讀取或寫入緩衝區。 驅動程式會將 OutputBuffer 參數設定為 Null。

同樣地,SPB 周邊裝置的 User-Mode Driver Foundation (UMDF) 驅動程式會呼叫 IWDFIoTarget::FormatRequestForIoctl 等方法來格式化 I/O 控制作業的 I/O 要求。 此方法具有 pInputMemorypOutputMemory 參數。 某些裝置類型的驅動程式可能會使用這兩個參數指向 IOCTL 要求的寫入緩衝區和讀取緩衝區。 不過,若要將 IOCTL 要求傳送至 SPB 控制器,SPB 周邊設備磁碟機會將 pInputMemory 參數設定為指向包含 SPB_TRANSFER_LIST 結構的記憶體物件。 此結構描述 I/O 控制作業所需的任何讀取或寫入緩衝區。 驅動程式會將 pOutputMemory 參數設定為 Null。

參數檢查和緩衝區擷取

當 SPB 架構延伸模組 (SpbCx) 收到 IOCTL_SPB_EXECUTE_SEQUENCE 要求時,SpbCx 會呼叫驅動程式的 EvtSpbControllerIoSequence 函式 ,將此要求傳遞至 SPB 控制器驅動程式。 在此呼叫之前,SpbCx 會檢查描述要求中緩衝區 的 SPB_TRANSFER_LIST 結構。 SpbCx 會在要求來源的進程內容中擷取這些緩衝區。 (使用者模式記憶體中的緩衝區只能在配置記憶體的進程存取。) 此外,SpbCx 會檢查要求中的參數值是否有效。

當 SpbCx 收到 IOCTL_SPB_FULL_DUPLEX 要求或自訂 IOCTL 要求時,SpbCx 會藉由呼叫驅動程式的 EvtSpbControllerIoOther 回呼函式,將此要求傳遞至 SPB 控制器驅動程式。 進行此呼叫之前,SpbCx 不會驗證要求中的參數值,也不會擷取來源器內容中的要求緩衝區。 這些要求的參數檢查和緩衝區擷取是 SPB 控制器驅動程式的責任。

如果 SPB 控制器驅動程式支援 IOCTL_SPB_FULL_DUPLEX 要求,或支援針對其緩衝區使用 SPB_TRANSFER_LIST 結構的任何自訂 IOCTL 要求,驅動程式必須實作 EvtIoInCallerCoNtext 回呼 函式。 驅動程式會在呼叫 SpbControllerSetIoOtherCallback 方法時,提供此函式的指標做為輸入參數,以註冊驅動程式的 EvtSpbControllerIoOther 回呼函式。 當 SpbCx 收到 IOCTL_SPB_FULL_DUPLEX 要求或自訂 IOCTL 要求時,SpbCx 會在來源器的內容中呼叫驅動程式的 EvtIoInCallerCoNtext 函式。 如果 IOCTL 要求使用 SPB_TRANSFER_LIST 結構, EvtIoInCallerCoNtext 函式會呼叫 SpbRequestCaptureIoOtherTransferList 方法來擷取要求中的緩衝區。 EvtIoInCallerCoNtext函式也可能執行要求的一些初步處理。

下列程式碼範例顯示 SPB 控制器驅動程式所實作的 EvtIoInCallerCoNtext 函式。

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

在上述程式碼範例中 switch ,語句會驗證要求是否包含 SPB 控制器驅動程式可辨識的 IOCTL。 (為了簡潔起見,語句的 switch 主體不會顯示。) Next, 呼叫 SpbRequestCaptureIoOtherTransferList 方法會擷取要求中的緩衝區。 如果此呼叫成功,則會將要求新增至 SPB 控制器的 I/O 佇列。 否則,要求會以錯誤狀態碼完成。

如需顯示 EvtSpbControllerIoOther 函式的參數檢查的程式碼範例,請參閱 處理IOCTL_SPB_FULL_DUPLEX要求