USB パイプの操作

フレームワークは、USB インターフェイス内の各パイプを "フレームワーク USB パイプ オブジェクト" として表します。**ドライバーが USB デバイスを構成すると、フレームワークは、選択した各インターフェイス内のパイプごとにフレームワーク USB パイプ オブジェクトを作成します。パイプ オブジェクトのメソッドにより、ドライバーは次の操作を実行できます。

  • パイプ情報を取得する。

  • パイプから読み取る。

  • パイプに書き込む。

  • パイプを停止またはリセットする。

  • URB をパイプに送信する。

  • パイプ エラーを処理する。

パイプ情報の取得

WdfUsbInterfaceGetConfiguredPipe を呼び出してフレームワーク USB パイプ オブジェクトへのハンドルを取得した後に、USB パイプに関する情報を取得するために USB パイプ オブジェクトが定義する次のメソッドをドライバーで呼び出すことができます。

 

パイプからの読み取り

USB 入力パイプからデータを読み取るために、ドライバーは次の 3 つの方法のいずれか (またはすべて) を使用できます。

  • データを同期的に読み取る。

    USB 入力パイプからデータを同期的に読み取るために、ドライバーは WdfUsbTargetPipeReadSynchronously メソッドを呼び出すことができます。このメソッドは読み取り要求を作成して送信し、I/O 操作が完了した後、制御を戻します。

  • データを非同期的に読み取る。

    USB 入力パイプからデータを非同期的に読み取るために、ドライバーは WdfUsbTargetPipeFormatRequestForRead メソッドを呼び出して読み取り要求を作成できます。次に、WdfRequestSend を呼び出して、その要求を非同期的 (または同期的) に送信します。

  • データを非同期的に連続して読み取る。

    "連続的なリーダー" とは、フレームワークで提供されるメカニズムであり、USB パイプで読み取り要求を常に使用できるようにします。**このメカニズムにより、ドライバーは、要求されていない非同期の入力ストリームを提供するデバイスからいつでもデータを受信できる状態になります。たとえば、ネットワーク インターフェイス カード (NIC) のドライバーは、連続的なリーダーを使用して入力データを受信します。

    入力パイプの連続的なリーダーを構成するために、ドライバーの EvtDevicePrepareHardware コールバック関数は WdfUsbTargetPipeConfigContinuousReader メソッドを呼び出す必要があります。このメソッドは、デバイスの I/ O ターゲットへの一連の読み取り要求をキューに入れます。

    また、ドライバーの EvtDeviceD0Entry コールバック関数は WdfIoTargetStart を呼び出して連続的なリーダーを開始し、ドライバーの EvtDeviceD0Exit コールバック関数は WdfIoTargetStop を呼び出して連続的なリーダーを停止する必要があります。

    データがデバイスから取得されるたびに、I/O ターゲットは読み取り要求を完了し、フレームワークは次の 2 つのコールバック関数の 1 つを呼び出します。I/O ターゲットがデータを正常に読み取った場合は EvtUsbTargetPipeReadComplete を呼び出し、I/O ターゲットがエラーを報告した場合は EvtUsbTargetPipeReadersFailed を呼び出します。

    ドライバーが WdfUsbTargetPipeConfigContinuousReader を呼び出した後、ドライバーの EvtUsbTargetPipeReadersFailed コールバック関数が呼び出され、FALSE を返さない限り、WdfUsbTargetPipeReadSynchronously または WdfRequestSend を使用してパイプに I/O 要求を送信することはできません。

既定では、パイプの最大パケット サイズの倍数ではない読み取りバッファーがドライバーで指定された場合、フレームワークはエラーを報告します。ドライバーは、WdfUsbTargetPipeSetNoMaximumPacketSizeCheck を呼び出して、読み取りバッファー サイズのこのテストを無効にすることができます。

パイプへの書き込み

USB 出力パイプにデータを書き込むために、ドライバーは次のいずれか (または両方) の方法を使用できます。

  • データを同期的に書き込む。

    データを USB 出力パイプに同期的に書き込むために、ドライバーは WdfUsbTargetPipeWriteSynchronously メソッドを呼び出すことができます。このメソッドは書き込み要求を作成して送信し、I/O 操作が完了した後、制御を戻します。

  • データを非同期的に書き込む。

    データを USB 入力パイプに非同期的に書き込むために、ドライバーは WdfUsbTargetPipeFormatRequestForWrite メソッドを呼び出して書き込み要求を作成できます。次に、ドライバーは WdfRequestSend を呼び出して、要求を非同期的に送信できます。

パイプの停止とリセット

ドライバーは次のメソッドを呼び出して、USB パイプを停止またはリセットできます。

  • WdfUsbTargetPipeAbortSynchronously
    USB パイプを停止するための要求を同期的に送信します。

  • WdfUsbTargetPipeFormatRequestForAbort
    USB パイプを停止するための要求をフォーマットします。ドライバーは WdfRequestSend を呼び出して、要求を同期的または非同期的に送信できます。

  • WdfUsbTargetPipeResetSynchronously
    USB パイプをリセットするための要求を同期的に送信します。

  • WdfUsbTargetPipeFormatRequestForReset
    USB パイプをリセットするための要求をフォーマットします。ドライバーは WdfRequestSend を呼び出して、要求を同期的または非同期的に送信する必要があります。

 

パイプへの URB の送信

ドライバーは、URB を含む I/O 要求を送信して USB パイプと通信する場合、次のメソッドを呼び出すことができます。

 

パイプ エラーの処理

ドライバーの USB ターゲットがエラー状態の値で I/O 要求を完了した場合、ドライバーは次の処理を実行する必要があります。

  1. ドライバーが USB ターゲットに追加の I/O 要求を送信していた場合、ターゲットがこの要求を完了していないときは、パイプを停止し、追加の I/O 要求を取り消します。

    WdfIoTargetCancelSentIo フラッグ セットと共に WdfIoTargetStop を呼び出します。

  2. 中止要求をパイプに同期的に送信します。

    WdfUsbTargetPipeAbortSynchronously を呼び出した後、または WdfUsbTargetPipeFormatRequestForAbort を呼び出した後に、WDF_REQUEST_SEND_OPTION_SYNCHRONOUS フラッグ セットと共に WdfRequestSend を呼び出します。

  3. リセット要求をパイプに同期的に送信します。

    WdfUsbTargetPipeResetSynchronously を呼び出した後、または WdfUsbTargetPipeFormatRequestForReset を呼び出した後に、WDF_REQUEST_SEND_OPTION_SYNCHRONOUS フラッグ セットと共に WdfRequestSend を呼び出します。

  4. パイプを再起動します。

    WdfIoTargetStart を呼び出します。

  5. 失敗した I/O 要求、および失敗した要求の後のすべての I/O 要求を再送信します。

多数のエラーが発生した場合、ドライバーは次の処理を実行して USB ポートのリセットを試行する必要があります。

  1. ドライバーが各パイプの USB ターゲットに追加の I/O 要求を送信していた場合、ターゲットがこの要求を完了していないときは、パイプを停止し、追加の I/O 要求を取り消します。

    アクティブな各パイプについて、WdfIoTargetCancelSentIo フラッグ セットと共に WdfIoTargetStop を呼び出します。

  2. USB ポートをリセットするための要求を同期的に送信します。

    WdfUsbTargetDeviceResetPortSynchronously を呼び出します。

  3. パイプを再起動します。

    ドライバーが停止したパイプごとに WdfIoTargetStart を呼び出します。

  4. 失敗した最後の I/O 要求、および失敗した要求の後のすべての I/O 要求を再送信します。