次の方法で共有


カスタム IOCTL に対する SPB_TRANSFER_LIST 構造体の使用

単純な周辺機器バス (SPB) コントローラー ドライバーが 1 つ以上のカスタム I/O 制御 (IOCTL) 要求をサポートしている場合は、SPB_TRANSFER_LIST 構造体を使用して、これらの要求の読み取りバッファーと書き込みバッファーを記述します。 この構造体は、要求内のバッファーを記述する一貫した方法を提供し、METHOD_BUFFERED I/O 操作に関連するバッファー コピーのオーバーヘッドを回避します。

カスタム IOCTL 要求で SPB_TRANSFER_LIST 構造体を使用する場合、SPB コントローラー ドライバーは SpbRequestCaptureIoOtherTransferList メソッドを呼び出して、要求元のプロセス コンテキストでこれらのバッファーをキャプチャする必要があります。 ドライバーは、SpbRequestGetTransferParameters メソッドを呼び出して、これらのバッファーにアクセスできます。

SPB I/O 要求インターフェイスの一部として定義されている IOCTL_SPB_FULL_DUPLEX および IOCTL_SPB_EXECUTE_SEQUENCE 要求は、SPB_TRANSFER_LIST 構造体を使用して、読み取りバッファーと書き込みバッファーを記述します。 IOCTL_SPB_FULL_DUPLEX 要求の SPB_TRANSFER_LIST 構造体は、要求の書き込みバッファーと読み取りバッファーの両方を (その順序で) 記述します。 IOCTL_SPB_EXECUTE_SEQUENCE 要求の SPB_TRANSFER_LIST 構造体は、読み取りバッファーと書き込みバッファーの任意のシーケンスを記述できます。

同様に、カスタム IOCTL を定義して、読み取りバッファーと書き込みバッファーの組み合わせを使用する SPB_TRANSFER_LIST 構造体を要求し、必要なバッファーの順序を一覧に指定できます。

SPB 周辺機器のカーネル モード ドライバー基盤 (KMDF) ドライバーは、SPB コント ローラーに IOCTL 要求を送信する WdfIoTargetSendIoctlSynchronousously などのメソッドを呼び出します。 このメソッドには、 InputBuffer パラメーターと OutputBuffer パラメーターがあります。 一部の種類のデバイスのドライバーでは、これら 2 つのパラメーターを使用して、IOCTL 要求の書き込みバッファーと読み取りバッファーをそれぞれ指定する場合があります。 ただし、IOCTL 要求を SPB コントローラーに送信するために、SPB 周辺機器ドライバーは、InputBuffer パラメーターを、SPB_TRANSFER_LIST 構造体に指定するメモリ記述子を指定するように設定します。 この構造体は、I/O 制御操作に必要な読み取りバッファーまたは書き込みバッファーを記述します。 ドライバーは、OutputBuffer パラメーターを NULL に設定します。

同様に、SPB 周辺機器のユーザー モード ドライバー基盤 (UMDF) ドライバーは、IWDFIoTarget::FormatRequestForIoctl などのメソッドを呼び出して、I/O コントロール操作の I/O 要求を書式設定します。 このメソッドには、pInputMemory パラメーターと pOutputMemory パラメーターがあります。 一部の種類のデバイスのドライバーでは、これら 2 つのパラメーターを使用して、IOCTL 要求の書き取りバッファーと読み込みバッファーをそれぞれ指定する場合があります。 ただし、SPB コントローラーに IOCTL 要求を送信するため、SPB 周辺機器ドライバーは、SPB_TRANSFER_LIST 構造体を含むメモリ オブジェクトを指す pInputMemory パラメーターを設定します。 この構造体は、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 コールバック関数を実装する必要があります。 ドライバーは、ドライバーの EvtSpbControllerIoOther コールバック関数を登録する SpbControllerSetIoOtherCallback メソッドの呼び出しで、この関数へのポインターを入力パラメーターとして提供します。 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 ステートメントの本文は表示されません)。次に、SpbRequestCaptureIoOtherTransferList メソッドの呼び出しによって、要求内のバッファーがキャプチャされます。 この呼び出しが成功すると、要求は SPB コントローラーの I/O キューに追加されます。 それ以外の場合、要求はエラー ステータス コードで完了します。

EvtSpbControllerIoOther 関数によるパラメーターのチェックを示すコード例については、「IOCTL_SPB_FULL_DUPLEX要求の処理」を参照してください。