USB コントロール転送を送信する方法

ここでは、コントロール転送の構造と、クライアント ドライバーで制御要求をデバイスに送る方法について説明します。

このトピックの内容:

既定のエンドポイントについて

すべての USB デバイスは、既定のエンドポイントと呼ばれるエンドポイントを少なくとも 1 つはサポートする必要があります。既定のエンドポイントをターゲットとする転送は、コントロール転送と呼ばれます。コントロール転送は、ホストによるデバイス情報の取得、デバイスの構成、またはデバイスに固有の制御操作の実行を可能にすることを目的としています。

既定のエンドポイントの特性は次のとおりです。

  • 既定のエンドポイントのアドレスは 0 です。
  • 既定のエンドポイントは双方向です。つまり、ホストは 1 つの転送でエンドポイントにデータを送り、エンドポイントからデータを受け取ることができます。
  • 既定のエンドポイントはデバイス レベルで使うことができます。デバイスのインターフェイスでは定義されていません。
  • 既定のエンドポイントは、ホストとデバイス間で接続が確立されるとすぐにアクティブになります。構成が選ばれる前でもアクティブになります。
  • 既定のエンドポイントの最大パケット サイズは、デバイスのバス速度によって異なります。Low-Speed では 8 バイト、Full-Speed と High-Speed では 64 バイト、SuperSpeed では 512 バイトです。

コントロール転送のレイアウト

コントロール転送は優先度の高い転送であるため、ホストによって一定量のバス帯域幅が確保されます。Low-Speed および Full-Speed 転送のデバイスでは帯域幅の 10%、High-Speed および SuperSpeed 転送のデバイスでは帯域幅の 20% が確保されます。ここでは、コントロール転送のレイアウトについて説明します。

USB コントロール転送

コントロール転送は、セットアップ トランザクションデータ トランザクションステータス トランザクションの 3 つのトランザクションに分けられます。各トランザクションには、トークン パケットデータ パケットハンドシェイク パケットの 3 種類のパケットが含まれます。

一部のフィールドはすべてのパケットに共通しています。これらのフィールドは次のとおりです。

  • パケットの開始を示す同期フィールド。
  • パケットの種類、トランザクションの方向、トランザクションの成功または失敗 (ハンドシェイク パケットの場合) を示すパケット識別子 (PID)。
  • パケットの終了を示す EOP フィールド。
他のフィールドはパケットの種類によって異なります。

  • Token packet

    セットアップ トランザクションはすべてトークン パケットで始まります。このパケットの構造を次に示します。ホストはトークン パケットを必ず送ります。

    Ff539261.token(ja-jp,VS.85).png

    PID 値は、トークン パケットの種類を示します。設定可能な値は次のとおりです。

    • SETUP: コントロール転送のセットアップ トランザクションの開始を示します。
    • IN: ホストがデバイスからのデータを要求していることを示します (読み取りの場合)。
    • OUT: ホストがデバイスにデータを送っていることを示します (書き込みの場合)。
    • SOF: フレームの開始を示します。この種類のトークン パケットには、11 ビットのフレーム番号が含まれます。SOF パケットはホストが送ります。このパケットの送信周期はバス速度によって異なります。Full-Speed の場合、ホストは 1 ミリ秒間隔でパケットを送り、High-Speed バスでは 125 マイクロ秒間隔で送ります。
  • Data packet

    トークン パケットのすぐ後は、ペイロードを含むデータ パケットです。各データ パケットに格納できるバイト数は、既定のエンドポイントの最大パケット サイズによって異なります。データ パケットは、転送方向に応じてホストとデバイスのどちらからでも送ることができます。

    Ff539261.data(ja-jp,VS.85).png

  • Handshake packet

    データ パケットのすぐ後はハンドシェイク パケットです。このパケットの PID は、ホストまたはデバイスがパケットを受け取ったかどうかを示します。ハンドシェイク パケットは、転送方向に応じてホストとデバイスのどちらからでも送ることができます。

    Ff539261.handshake(ja-jp,VS.85).png

USB アナライザー (Beagle、Ellisys、LeCroy などの USB プロトコル アナライザー) を使うことで、トランザクションとパケットの構造を確認できます。アナライザー デバイスでは、ネットワークを介して USB デバイスとの間でデータがどのように送受信されているかが示されます。この例では、LeCroy USB アナライザーでキャプチャされたトレースを調べていきます。この例は情報提供のみを目的としています。これは Microsoft が推奨するものではありません。

  • Setup transaction

    ホストはコントロール転送をいつでも開始できます。コントロール転送は、セットアップ トランザクションを送ることによって開始されます。このトランザクションには、セットアップ トークンと呼ばれるトークン パケットが含まれ、その後に 8 バイトのデータ パケットが続きます。次のスクリーン ショットは、セットアップ トランザクションの例を示しています。

    セットアップ トランザクションのトレース

    上記のトレースでは、ホストはセットアップ トークン パケット 434 を送ることによって、コントロール転送を開始しています (H↓ で示されています)。PID には、セットアップ トークンを示す SETUP が指定されていることがわかります。PID の後には、デバイス アドレスとエンドポイント アドレスが続きます。コントロール転送では、このエンドポイント アドレスは常に 0 になります。

    次に、ホストがデータ パケット 435 を送っています。PID は DATA0 になっています。この値は、後ほど説明するパケット順序制御に使われます。PID の後には、この要求に関する主要情報を含む 8 バイトが続きます。この 8 バイトは、要求の種類とデバイスが応答を書き込むバッファーのサイズを示します。

    すべてのバイトは逆の順番で受信されます。USB 仕様のセクション 9.3 の記載内容に従って、各フィールドと値を次に示します。

    フィールドサイズ説明
    bmRequestType (「9.3.1 bmRequestType」を参照)1 0x80

    データ転送方向はデバイスからホストです (D7 が 1)。

    この要求は標準要求です (D6 ~ D5 が 0)。

    要求の受信側はデバイスです (D4 が 0)。

    bRequest (セクション 9.3.2 と表 9-4 を参照) 1 0x06要求の種類は GET_DESCRIPTOR です。
    wValue (表 9-5 を参照) 20x0100この要求の値は、記述子の種類がデバイスであることを示します。
    wIndex (セクション 9.3.4 を参照) 2 0x0000

    方向はホストからデバイスです (D7 が 1)。

    エンドポイント番号は 0 です。

    wLength (セクション 9.3.5 を参照)20x0012この要求の目的は、18 バイト取得することです。

     

    まとめると、このコントロール (読み取り) 転送では、ホストがデバイス記述子の取得要求を送り、その記述子を保持するための転送長として 18 バイトを指定しています。 デバイスが 18 バイト送信する方法は、既定のエンドポイントが 1 つのトランザクションで送信できるデータ量によって異なります。この情報は、データ トランザクションでデバイスから返されるデバイス記述子に含まれています。

    応答で、デバイスはハンドシェイク パケット (D↓ で示されているパケット 436) を送ります。PID 値が ACK (ACK パケット) であることに注意してください。これは、デバイスがトランザクションの受信を確認したことを示します。

  • Data transaction

    ここでは、要求への応答でデバイスから返される内容を見ていきます。データ トランザクションでは実際のデータが転送されます。

    データ トランザクションのトレースを次に示します。

    データ トランザクションの例のトレース

    ホストは ACK パケットを受け取ると、データ トランザクションを開始します。トランザクションを開始するために、方向が IN のトークン パケット (450) を送ります (このパケットは、IN トークンと呼ばれます)。

    応答で、デバイスは IN トークンの後にデータ パケット (451) を送ります。このデータ パケットには、実際のデバイス記述子が含まれています。先頭バイトは、デバイス記述子の長さ (18 バイト (0x12)) を示します。このデータ バケットの最後のバイトは、既定のエンドポイントでサポートされる最大パケット サイズを示します。 この例では、デバイスが既定のエンドポイントから一度に 8 バイト送信できることがわかります。

      既定のエンドポイントの最大パケット サイズは、デバイスの速度によって異なります。 High-Speed デバイスの既定のエンドポイントでは 64 バイト、Low-Speed デバイスでは 8 バイトです。

    ホストは、ACK パケット (452) をデバイスに送ってデータ トランザクションの受信を確認します。

    返されるデータ量を計算してみましょう。セットアップ トランザクションのデータ パケット (435) の wLength フィールドで、ホストは 18 バイト要求しました。このデータ トランザクションでデバイスから受け取ったのは、デバイス記述子の最初の 8 バイトだけです。では、残りの 10 バイトに格納されている情報をホストはどのようにして受け取るのでしょうか。デバイスは、残りの 10 バイトを 2 つのトランザクションで送ります。まず 8 バイト送り、次に最後の 2 バイトを送ります。

    ホストは既定のエンドポイントの最大パケット サイズがわかったので、新しいデータ トランザクションを開始し、パケット サイズに基づいて次の部分を要求します。

    ここでは、次のデータ トランザクションを示します。

    データ トランザクションの例のトレース

    ホストは IN トークン (463) を送り、次の 8 バイトをデバイスに要求することによって、上記のデータ トランザクションを開始しています。デバイスは、デバイス記述子の次の 8 バイトを含むデータ パケット (464) で応答します。

    ホストは 8 バイトを受け取ると、ACK パケット (465) をデバイスに送ります。

    次に、ホストは別のデータ トランザクションで最後の 2 バイトを要求します。このデータ トランザクションを次に示します。

    Ff539261.datra_trans3(ja-jp,VS.85).png

    デバイスからホストに 18 バイト転送するために、ホストは転送済みのバイト数を追跡し、3 つのデータ トランザクション (8+8+2) を開始しました。

       データ トランザクション 19、23、26 のデータ パケットの PID に注目してください。PID は、DATA0 と DATA1 が交互になっています。このシーケンスは "データ トグル" と呼ばれます。データ トランザクションが複数ある場合、データ トグルを使ってパケットの順番が確認されます。この方法によって、データ パケットの重複や損失が発生していないかどうかが確認されます。

    統合されたデータ パケットをデバイス記述子の構造に対応付けて (表 9-8 を参照)、各フィールドと値を次に示します。
    フィールドサイズ説明
    bLength10x12デバイス記述子の長さ (18 バイト) です。
    bDescriptorType10x01記述子の種類はデバイスです。
    bcdUSB20x0100仕様のバージョン番号は 1.00 です。
    bDeviceClass10x00デバイス クラスは 0 です。構成の各インターフェイスにクラス情報が含まれます。
    bDeviceSubClass10x00デバイス クラスが 0 であるため、サブクラスは 0 です。
    bProtocol10x00プロトコルは 0 です。このデバイスでは、クラス固有のプロトコルは使われていません。
    bMaxPacketSize010x08エンドポイントの最大パケット サイズは 8 バイトです。
    idVendor20x0562Telex Communications です。
    idProduct20x0002USB マイクです。
    bcdDevice20x0100デバイスのリリース番号を示します。
    iManufacturer10x01製造元文字列です。
    iProduct10x02製品文字列です。
    iSerialNumber10x03シリアル番号です。
    bNumConfigurations10x01構成の数です。

     

    これらの値を調べることによって、このデバイスに関する予備情報が得られます。このデバイスは Low-Speed USB マイクです。既定のエンドポイントの最大パケット サイズは 8 バイトです。このデバイスは 1 つの構成をサポートしています。
  • Status transaction

    最後に、ホストは最後のトランザクションであるステータス トランザクションを開始してコントロール転送を完了します。

    Ff539261.status_trans(ja-jp,VS.85).png

    ホストは、OUT トークン パケット (481) でトランザクションを開始します。このパケットの目的は、要求されたデータをデバイスがすべて送ったことを確認することです。このステータス トランザクションで送られるデータ パケットはありません。デバイスは ACK パケットで応答します。エラーが発生した場合、PID が NAK または STALL になっていることがあります。

サポートされるドライバー モデル

関連テクノロジ

前提条件

クライアント ドライバーでパイプを列挙する前に、次の要件が満たされていることを確認してください。

  • クライアント ドライバーでは、フレームワーク USB ターゲット デバイス オブジェクトを作っておく必要があります。

    Microsoft Visual Studio Professional 2012 に用意されている USB テンプレートを使う場合は、テンプレート コードによってこれらのタスクが実行されます。テンプレート コードでは、ターゲット デバイス オブジェクトへのハンドルを取得し、デバイス コンテキストに格納します。

    KMDF クライアント ドライバー:  

    KMDF クライアント ドライバーでは、WdfUsbTargetDeviceCreateWithParameters メソッドを呼び出して WDFUSBDEVICE ハンドルを取得する必要があります。詳しくは、「USB クライアント ドライバーのコード構造 (KMDF) について」のデバイス ソース コードをご覧ください。

    UMDF クライアント ドライバー:  

    UMDF クライアント ドライバーでは、フレームワーク ターゲット デバイス オブジェクトに照会して IWDFUsbTargetDevice ポインターを取得する必要があります。詳しくは、「USB クライアント ドライバーのコード構造 (UMDF) について」の「IPnpCallbackHardware 実装と USB 固有のタスク」をご覧ください。

  • コントロール転送の最も重要な部分は、セットアップ トークンを適切にフォーマットすることです。要求を送る前に、次の情報を収集します。

    • 要求の方向: ホストからデバイス、またはデバイスからホスト。
    • 要求の受信側: デバイス、インターフェイス、エンドポイント、またはその他。
    • 要求のカテゴリ: 標準、クラス、またはベンダー。
    • 要求の種類: GET_DESCRIPTPOR 要求など。詳しくは、USB 仕様のセクション 9.5 をご覧ください。
    • wValuewIndex の値。これらの値は要求の種類によって異なります。
    これらの情報はすべて公式な USB 仕様から入手できます。
  • UMDF ドライバーを作る場合は、OSR USB Fx2 Learning Kit 用 UMDF サンプル ドライバーから Usb_hw.h ヘッダー ファイルを入手します。このヘッダー ファイルには、コントロール転送のセットアップ パケットをフォーマットする際に役立つマクロと構造体が含まれています。

    すべての UMDF ドライバーは、デバイスとの間でデータを送受信するためにカーネル モード ドライバーと通信する必要があります。USB UMDF ドライバーの場合、カーネル モード ドライバーは常に Microsoft が提供する WinUSB ドライバー (Winusb.sys) です。

    UMDF ドライバーで USB ドライバー スタックに対する要求を作ると、Windows I/O マネージャーによって WinUSB に要求が送られます。WinUSB は要求を受け取ると、要求を処理するか、USB ドライバー スタックに転送します。

コントロール転送要求を送るために Microsoft が定義したメソッド

ホストの USB クライアント ドライバーが開始するほとんどの制御要求は、デバイスに関する情報の取得、デバイスの構成、またはベンダーの制御コマンドの送信を目的としています。これらの要求はすべて次のように分類できます。

  • 標準要求 - 標準要求は USB 仕様で定義されています。この要求を送る目的は、デバイス、構成、インターフェイス、エンドポイントに関する情報を取得することです。各要求の受信側は要求の種類によって異なります。デバイス、インターフェイス、またはエンドポイントが受信側になります。

      コントロール転送のターゲットは常に既定のエンドポイントです。受信側は、ホストが情報 (記述子、ステータスなど) を必要としているデバイスのエンティティです。

    これらの要求は、構成要求、機能要求、ステータス要求にさらに分類できます。

    • 構成要求 (GET_DESCRIPTOR 要求など) は、ホストがデバイスを構成できるようにデバイスから情報を取得するために送られます。この要求は、デバイスの特定の構成または代替設定を行うためにホストから送られる書き込み要求である場合もあります。
    • 機能要求は、デバイス、インターフェイス、またはエンドポイントでサポートされるデバイスの特定のブール設定を有効または無効にするために、クライアント ドライバーから送られます。
    • USB デバイスではステータス要求をサポートしています。この要求により、ホストは USB で定義されている、デバイス、エンドポイント、またはインターフェイスのステータス ビットを取得または設定できます。
    詳しくは、USB 仕様バージョン 2.0 のセクション 9.4 をご覧ください。標準要求の種類は、Usbspec.h ヘッダー ファイルに定義されています。
  • クラス要求 - 特定のデバイス クラス仕様で定義されています。
  • ベンダー要求 - ベンダーによって提供されます。この要求は、デバイスでサポートされる要求によって異なります。

Microsoft が提供する USB スタックでは、前のトレースに示すようにデバイスとのプロトコル通信をすべて処理します。ドライバーは、クライアント ドライバーがさまざまな方法でコントロール転送を送ることができるようにするためのデバイス ドライバー インターフェイス (DDI) を公開します。クライアント ドライバーが Windows Driver Foundation (WDF) ドライバーの場合は、ルーチンを直接呼び出して一般的な種類のコントロール要求を送ることができます。WDF では、KMDF と UMDF のコントロール転送をサポートしています。

一部の種類の制御要求は WDF によって公開されません。これらの要求では、クライアント ドライバーで WDF ハイブリッド モデルを使うことができます。このモデルでは、クライアント ドライバーは WDM 形式の URB 要求を作ってフォーマットし、WDF フレームワーク オブジェクトを使って要求を送ることができます。ハイブリッド モデルは、カーネル モード ドライバーにのみ適用されます。

UMDF ドライバーの場合:  

usb_hw.h に定義されているヘルパー マクロと構造体を使います。このヘッダーは、OSR USB Fx2 Learning Kit 用 UMDF サンプル ドライバーに付属しています。

次の表を参考にして、USB ドライバー スタックに制御要求を送る最適な方法を判断してください。この表を表示できない場合は、こちらのトピックの表をご覧ください。

制御要求を送る目的使用する KMDF DDI (KMDF ドライバーの場合)使用する UMDF メソッド (UMDF ドライバーの場合)作成する URB 構造体 (ヘルパー ルーチン) (WDM ドライバーの場合)
CLEAR_FEATURE: デバイス、構成、インターフェイス、エンドポイントの特定の機能設定を無効にします。USB 仕様のセクション 9.4.1 をご覧ください。
  1. セットアップ パケットを宣言します。WDF_USB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE を呼び出して、セットアップ パケットを初期化します。
  3. WDF_USB_BMREQUEST_RECIPIENT で定義されている受信側の値を指定します。
  4. 機能セレクター (wValue) を指定します。Usbspec.h の定数 USB_FEATURE_XXX をご覧ください。USB 仕様の表 9-6 もご覧ください。
  5. SetFeatureFALSE に設定します。
  6. WdfUsbTargetDeviceSendControlTransferSynchronously または WdfUsbTargetDeviceFormatRequestForControlTransfer を呼び出して要求を送ります。
  1. セットアップ パケットを宣言します。usb_hw.h で宣言されている WINUSB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. usb_hw.h で定義されている WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE ヘルパー マクロを呼び出して、セットアップ パケットを初期化します。
  3. WINUSB_BMREQUEST_RECIPIENT で定義されている受信側の値を指定します。
  4. 機能セレクター (wValue) を指定します。Usbspec.h の定数 USB_FEATURE_XXX をご覧ください。USB 仕様の表 9-6 もご覧ください。
  5. SetFeatureFALSE に設定します。
  6. IWDFUsbTargetDevice::FormatRequestForControlTransfer メソッドを呼び出して、初期化したセットアップ パケットをフレームワーク要求オブジェクトと転送バッファーに関連付け、要求を作ります。
  7. IWDFIoRequest::Send メソッドを呼び出して要求を送ります。

_URB_CONTROL_FEATURE_REQUEST

(UsbBuildFeatureRequest)

URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE

URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE

URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT

URB_FUNCTION_CLEAR_FEATURE_TO_OTHER

GET_CONFIGURATION: 現在の USB 構成を取得します。USB 仕様のセクション 9.4.2 をご覧ください。

KMDF では、既定で最初の構成が選ばれます。デバイスによって定義された構成番号を取得するには、次の手順を実行します。

  1. WDF_USB_CONTROL_SETUP_PACKET をフォーマットし、bRequest メンバーを USB_REQUEST_GET_CONFIGURATION に設定します。
  2. WdfUsbTargetDeviceSendControlTransferSynchronously または WdfUsbTargetDeviceFormatRequestForControlTransfer を呼び出して要求を送ります。

UMDF では、既定で最初の構成が選ばれます。デバイスによって定義された構成番号を取得するには、次の手順を実行します。

  1. セットアップ パケットを宣言します。usb_hw.h で宣言されている WINUSB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. usb_hw.h で定義されている WINUSB_CONTROL_SETUP_PACKET_INIT ヘルパー マクロを呼び出して、セットアップ パケットを初期化します。
  3. 方向として BmRequestToDevice、受信側として BmRequestToDevice、要求として USB_REQUEST_GET_CONFIGURATION を指定します。
  4. IWDFUsbTargetDevice::FormatRequestForControlTransfer メソッドを呼び出して、初期化したセットアップ パケットをフレームワーク要求オブジェクトと転送バッファーに関連付け、要求を作ります。
  5. IWDFIoRequest::Send メソッドを呼び出して要求を送ります。
  6. 転送バッファー内の構成番号を取得します。IWDFMemory メソッドを呼び出して、このバッファーにアクセスします。

_URB_CONTROL_GET_CONFIGURATION_REQUEST

URB_FUNCTION_GET_CONFIGURATION

GET_DESCRIPTOR: デバイス、構成、インターフェイス、エンドポイントの各記述子を取得します。USB 仕様のセクション 9.4.3 をご覧ください。

詳しくは、「USB 記述子」をご覧ください。

次のメソッドを呼び出します。

次のメソッドを呼び出します。

_URB_CONTROL_DESCRIPTOR_REQUEST

(UsbBuildGetDescriptorRequest)

URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE

URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT

URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE

GET_INTERFACE: インターフェイスの現在の代替設定を取得します。USB 仕様のセクション 9.4.4 をご覧ください。

  1. WdfUsbTargetDeviceGetInterface メソッドを呼び出して、ターゲット インターフェイス オブジェクトへの WDFUSBINTERFACE ハンドルを取得します。
  2. WdfUsbInterfaceGetConfiguredSettingIndex メソッドを呼び出します。
  1. ターゲット インターフェイス オブジェクトへの IWDFUsbInterface ポインターを取得します。
  2. IWDFUsbInterface::GetConfiguredSettingIndex メソッドを呼び出します。

_URB_CONTROL_GET_INTERFACE_REQUEST

URB_FUNCTION_GET_INTERFACE

GET_STATUS: デバイス、エンドポイント、またはインターフェイスからステータス ビットを取得します。USB 仕様のセクション 9.4.5 をご覧ください。
  1. セットアップ パケットを宣言します。WDF_USB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS を呼び出して、セットアップ パケットを初期化します。
  3. WDF_USB_BMREQUEST_RECIPIENT で定義されている受信側の値を指定します。
  4. デバイス、インターフェイス、エンドポイントのうち、どのステータスを取得するかを指定します (wIndex)。
  5. WdfUsbTargetDeviceSendControlTransferSynchronously または WdfUsbTargetDeviceFormatRequestForControlTransfer を呼び出して要求を送ります。
  1. セットアップ パケットを宣言します。usb_hw.h で宣言されている WINUSB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. usb_hw.h で定義されている WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS ヘルパー マクロを呼び出して、セットアップ パケットを初期化します。
  3. WINUSB_BMREQUEST_RECIPIENT で定義されている受信側の値を指定します。
  4. デバイス、インターフェイス、エンドポイントのうち、どのステータスを取得するかを指定します (wIndex)。
  5. IWDFUsbTargetDevice::FormatRequestForControlTransfer メソッドを呼び出して、初期化したセットアップ パケットをフレームワーク要求オブジェクトと転送バッファーに関連付け、要求を作ります。
  6. IWDFIoRequest::Send メソッドを呼び出して要求を送ります。
  7. 転送バッファー内のステータス値を取得します。IWDFMemory メソッドを呼び出して、このバッファーにアクセスします。
  8. ステータスが自己供給型を示しているかどうか、リモート ウェイクアップを示しているかどうかを確認するには、WINUSB_DEVICE_TRAITS 列挙型で定義されている値を使います。

_URB_CONTROL_GET_STATUS_REQUEST

(UsbBuildGetStatusRequest)

URB_FUNCTION_GET_STATUS_FROM_DEVICE

URB_FUNCTION_GET_STATUS_FROM_INTERFACE

URB_FUNCTION_GET_STATUS_FROM_ENDPOINT

URB_FUNCTION_GET_STATUS_FROM_OTHER

SET_ADDRESS: USB 仕様のセクション 9.4.6 をご覧ください。この要求は、USB ドライバー スタックによって処理されます。クライアント ドライバーでこの操作を実行することはできません。この要求は、USB ドライバー スタックによって処理されます。クライアント ドライバーでこの操作を実行することはできません。この要求は、USB ドライバー スタックによって処理されます。クライアント ドライバーでこの操作を実行することはできません。
SET_CONFIGURATION: 構成を設定します。USB 仕様のセクション 9.4.7 をご覧ください。

詳しくは、「USB デバイスの構成を選択する方法」をご覧ください。

KMDF では、既定の構成と各インターフェイスの最初の代替設定が既定で選ばれます。クライアント ドライバーでは、WdfUsbTargetDeviceSelectConfigType メソッドを呼び出し、要求オプションとして WdfUsbTargetDeviceSelectConfigTypeUrb を指定することで既定の構成を変更できます。その後、この要求の URB をフォーマットし、USB ドライバー スタックに送る必要があります。UMDF では、既定の構成と各インターフェイスの最初の代替設定が既定で選ばれます。クライアント ドライバーが構成を変更することはできません。

_URB_SELECT_CONFIGURATION

(USBD_SelectConfigUrbAllocateAndBuild)

URB_FUNCTION_SELECT_CONFIGURATION

SET_DESCRIPTOR: 既にあるデバイス記述子、構成記述子、または文字列記述子を更新します。USB 仕様のセクション 9.4.8 をご覧ください。

この要求が使われることはあまりありません。ただし、USB ドライバー スタックは、クライアント ドライバーからのこのような要求を受け入れます。

  1. この要求の URB を割り当てて構築します。
  2. _URB_CONTROL_DESCRIPTOR_REQUEST 構造体で転送情報を指定します。
  3. WdfUsbTargetDeviceFormatRequestForUrb または WdfUsbTargetDeviceSendUrbSynchronously を呼び出して要求を送ります。
  1. セットアップ パケットを宣言します。usb_hw.h で宣言されている WINUSB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. USB 仕様に従って転送情報を指定します。
  3. IWDFUsbTargetDevice::FormatRequestForControlTransfer メソッドを呼び出して、初期化したセットアップ パケットをフレームワーク要求オブジェクトと転送バッファーに関連付け、要求を作ります。
  4. IWDFIoRequest::Send メソッドを呼び出して要求を送ります。

_URB_CONTROL_DESCRIPTOR_REQUEST

URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE

URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT

URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE

SET_FEATURE: デバイス、構成、インターフェイス、エンドポイントの特定の機能設定を有効にします。USB 仕様のセクション 9.4.9 をご覧ください。
  1. セットアップ パケットを宣言します。WDF_USB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE を呼び出して、セットアップ パケットを初期化します。
  3. WDF_USB_BMREQUEST_RECIPIENT で定義されている受信側の値 (デバイス、インターフェイス、エンドポイント) を指定します。
  4. 機能セレクター (wValue) を指定します。Usbspec.h の定数 USB_FEATURE_XXX をご覧ください。USB 仕様の表 9-6 もご覧ください。
  5. SetFeatureTRUE に設定します。
  6. WdfUsbTargetDeviceSendControlTransferSynchronously または WdfUsbTargetDeviceFormatRequestForControlTransfer を呼び出して要求を送ります。
  1. セットアップ パケットを宣言します。usb_hw.h で宣言されている WINUSB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. usb_hw.h で定義されている WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE ヘルパー マクロを呼び出して、セットアップ パケットを初期化します。
  3. WINUSB_BMREQUEST_RECIPIENT で定義されている受信側の値を指定します。
  4. 機能セレクター (wValue) を指定します。Usbspec.h の定数 USB_FEATURE_XXX をご覧ください。USB 仕様の表 9-6 もご覧ください。
  5. SetFeatureTRUE に設定します。
  6. IWDFUsbTargetDevice::FormatRequestForControlTransfer メソッドを呼び出して、初期化したセットアップ パケットをフレームワーク要求オブジェクトと転送バッファーに関連付け、要求を作ります。
  7. IWDFIoRequest::Send メソッドを呼び出して要求を送ります。

_URB_CONTROL_FEATURE_REQUEST

(UsbBuildFeatureRequest)

URB_FUNCTION_SET_FEATURE_TO_DEVICE

URB_FUNCTION_SET_FEATURE_TO_INTERFACE

URB_FUNCTION_SET_FEATURE_TO_ENDPOINT

URB_FUNCTION_SET_FEATURE_TO_OTHER

SET_INTERFACE: インターフェイスの代替設定を変更します。USB 仕様のセクション 9.4.9 をご覧ください。

詳しくは、「USB インターフェイスの代替設定を選択する方法」をご覧ください。

WdfUsbTargetDeviceSelectConfig

  1. ターゲット インターフェイス オブジェクトへの WDFUSBINTERFACE ハンドルを取得します。
  2. WdfUsbInterfaceSelectSetting メソッドを呼び出します。
  1. ターゲット インターフェイス オブジェクトへの IWDFUsbInterface ポインターを取得します。
  2. IWDFUsbInterface::SelectSetting メソッドを呼び出します。

_URB_SELECT_INTERFACE

(USBD_SelectInterfaceUrbAllocateAndBuild)

URB_FUNCTION_SELECT_INTERFACE

SYNC_FRAME: エンドポイントの同期フレーム番号を設定および取得します。USB 仕様のセクション 9.4.10 をご覧ください。この要求は、USB ドライバー スタックによって処理されます。クライアント ドライバーでこの操作を実行することはできません。この要求は、USB ドライバー スタックによって処理されます。クライアント ドライバーでこの操作を実行することはできません。この要求は、USB ドライバー スタックによって処理されます。クライアント ドライバーでこの操作を実行することはできません。
デバイス クラス固有の要求およびベンダー コマンドの場合。
  1. セットアップ パケットを宣言します。WDF_USB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS (クラス固有の要求の場合) または WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR (ベンダー コマンドの場合) を呼び出して、セットアップ パケットを初期化します。
  3. WDF_USB_BMREQUEST_RECIPIENT で定義されている受信側の値 (デバイス、インターフェイス、エンドポイント) を指定します。
  4. WdfUsbTargetDeviceSendControlTransferSynchronously または WdfUsbTargetDeviceFormatRequestForControlTransfer を呼び出して要求を送ります。
  1. セットアップ パケットを宣言します。usb_hw.h で宣言されている WINUSB_CONTROL_SETUP_PACKET 構造体をご覧ください。
  2. usb_hw.h で定義されている WINUSB_CONTROL_SETUP_PACKET_INIT_CLASS または WINUSB_CONTROL_SETUP_PACKET_INIT_VENDOR ヘルパー マクロを呼び出して、セットアップ パケットを初期化します。
  3. クラス仕様またはハードウェア仕様の記載内容に従って、方向 (WINUSB_BMREQUEST_DIRECTION 列挙型を参照)、受信側 (WINUSB_BMREQUEST_RECIPIENT 列挙型を参照)、要求を指定します。
  4. IWDFUsbTargetDevice::FormatRequestForControlTransfer メソッドを呼び出して、初期化したセットアップ パケットをフレームワーク要求オブジェクトと転送バッファーに関連付け、要求を作ります。
  5. IWDFIoRequest::Send メソッドを呼び出して要求を送ります。
  6. 転送バッファー内のデバイスの情報を取得します。IWDFMemory メソッドを呼び出して、このバッファーにアクセスします。

_URB_CONTROL_VENDOR_OR_CLASS_REQUEST

(UsbBuildVendorRequest)

URB_FUNCTION_VENDOR_DEVICE

URB_FUNCTION_VENDOR_INTERFACE

URB_FUNCTION_VENDOR_ENDPOINT

URB_FUNCTION_VENDOR_OTHER

URB_FUNCTION_CLASS_DEVICE

URB_FUNCTION_CLASS_INTERFACE

URB_FUNCTION_CLASS_ENDPOINT

URB_FUNCTION_CLASS_OTHER

 

ベンダー コマンドのコントロール転送を送信する方法 - KMDF

次の手順は、クライアント ドライバーでコントロール転送を送る方法を示しています。この例では、クライアント ドライバーはデバイスからファームウェアのバージョンを取得するベンダー コマンドを送ります。

  1. ベンダー コマンドの定数を宣言します。ハードウェア仕様を調べて、使うベンダー コマンドを決定します。
  2. WDF_MEMORY_DESCRIPTOR 構造体を宣言し、WDF_MEMORY_DESCRIPTOR_INIT_BUFFER マクロを呼び出して構造体を初期化します。USB ドライバーが要求を完了したら、この構造体がデバイスからの応答を受け取ります。
  3. 要求を同期的に送るか非同期的に送るかに応じて、送信オプションを指定します。
    • WdfUsbTargetDeviceSendControlTransferSynchronously を呼び出して要求を同期的に送る場合は、タイムアウト値を指定します。タイムアウトを指定しないとスレッドをブロックし続ける可能性があるため、この値が重要となります。

      タイムアウト値を指定するには、WDF_REQUEST_SEND_OPTIONS 構造体を宣言し、WDF_REQUEST_SEND_OPTIONS_INIT マクロを呼び出して構造体を初期化します。オプションとして WDF_REQUEST_SEND_OPTION_TIMEOUT を指定します。

      次に、WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT マクロを呼び出して、タイムアウト値を設定します。

    • 要求を非同期的に送る場合は、完了ルーチンを実装します。割り当てられているすべてのリソースを完了ルーチンで解放します。
  4. セットアップ トークンを格納する WDF_USB_CONTROL_SETUP_PACKET 構造体を宣言し、構造体をフォーマットします。そのためには、WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR マクロを呼び出してセットアップ パケットをフォーマットします。この呼び出しで、要求の方向、受信側、要求の送信オプション (手順 3. で初期化したもの)、ベンダー コマンドの定数を指定します。
  5. WdfUsbTargetDeviceSendControlTransferSynchronously または WdfUsbTargetDeviceFormatRequestForControlTransfer を呼び出して要求を送ります。
  6. フレームワークから返された NTSTATUS 値を確認し、受け取った値を調べます。

次のコード例では、USB デバイスにコントロール転送要求を送ってファームウェアのバージョンを取得します。この要求は同期的に送られます。クライアント ドライバーでは、相対タイムアウト値として 5 秒 (100 ナノ秒単位) を指定します。受け取った応答は、ドライバーによって定義されたデバイス コンテキストに格納されます。



enum {   
    USBFX2_GET_FIRMWARE_VERSION = 0x1,  
....

} USBFX2_VENDOR_COMMANDS; 

#define WDF_TIMEOUT_TO_SEC              ((LONGLONG) 1 * 10 * 1000 * 1000)  // defined in wdfcore.h

const __declspec(selectany) LONGLONG   
            DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; 


typedef struct _DEVICE_CONTEXT
{
 
    ...
	   union {  
        USHORT      VersionAsUshort;  
        struct {  
            BYTE Minor;  
            BYTE Major;  
        } Version;  
    } Firmware; // Firmware version.

} DEVICE_CONTEXT, *PDEVICE_CONTEXT;


__drv_requiresIRQL(PASSIVE_LEVEL)  
VOID  GetFirmwareVersion(  
    __in PDEVICE_CONTEXT DeviceContext  
)  
{  
    NTSTATUS                        status;  
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;  
    WDF_REQUEST_SEND_OPTIONS        sendOptions;  
    USHORT                          firmwareVersion;  
    WDF_MEMORY_DESCRIPTOR           memoryDescriptor;  
      
    PAGED_CODE();  
  
    firmwareVersion = 0;  
  
    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, (PVOID) &firmwareVersion, sizeof(firmwareVersion));  
  
    WDF_REQUEST_SEND_OPTIONS_INIT(  
                                  &sendOptions,  
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT  
                                  );  
  
    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(  
                                         &sendOptions,  
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT  
                                         );  
                
    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,  
                                        BmRequestDeviceToHost,       // Direction of the request
                                        BmRequestToDevice,           // Recipient
                                        USBFX2_GET_FIRMWARE_VERSION, // Vendor command
                                        0,                           // Value
                                        0);                          // Index    
  
    status = WdfUsbTargetDeviceSendControlTransferSynchronously(  
                                        DeviceContext->UsbDevice,  
                                        WDF_NO_HANDLE,               // Optional WDFREQUEST
                                        &sendOptions,  
                                        &controlSetupPacket,  
                                        &memoryDescriptor,           // MemoryDescriptor                                          
                                        NULL);                       // BytesTransferred    
     
    if (!NT_SUCCESS(status)) 
    {  
        KdPrint(("Device %d: Failed to get device firmware version 0x%x\n", DeviceContext->DeviceNumber, status));  
        TraceEvents(DeviceContext->DebugLog,  
                    TRACE_LEVEL_ERROR,  
                    DBG_RUN,  
                    "Device %d: Failed to get device firmware version 0x%x\n",  
                    DeviceContext->DeviceNumber,  
                    status);  
    }
    else 
    {  
        DeviceContext->Firmware.VersionAsUshort = firmwareVersion;  
        TraceEvents(DeviceContext->DebugLog,  
                    TRACE_LEVEL_INFORMATION,  
                    DBG_RUN,  
                    "Device %d: Get device firmware version : 0x%x\n",  
                    DeviceContext->DeviceNumber,  
                    firmwareVersion);  
    }  
  
    return;  
}  


GET_STATUS のコントロール転送を送信する方法 - UMDF

次の手順は、クライアント ドライバーで GET_STATUS コマンドのコントロール転送を送る方法を示しています。要求の受信側はデバイスです。この要求では、ビット D1 から D0 で情報を取得します。詳しくは、USB 仕様の図 9-4 をご覧ください。

  1. OSR USB Fx2 Learning Kit 用 UMDF サンプル ドライバーで入手できる Usb_hw.h ヘッダー ファイルを含めます。
  2. WINUSB_CONTROL_SETUP_PACKET 構造体を宣言します。
  3. WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS ヘルパー マクロを呼び出して、セットアップ パケットを初期化します。
  4. 受信側として BmRequestToDevice を指定します。
  5. Index 値に 0 を指定します。
  6. SendControlTransferSynchronously ヘルパー メソッドを呼び出して、要求を同期的に送ります。

    このヘルパー メソッドは、IWDFUsbTargetDevice::FormatRequestForControlTransfer メソッドを呼び出して、初期化されたセットアップ パケットをフレームワーク要求オブジェクトと転送バッファーに関連付け、要求を作ります。ヘルパー メソッドは IWDFIoRequest::Send メソッドを呼び出して要求を送ります。メソッドから制御が戻ったら、返された値を調べます。

  7. ステータスが自己供給型を示しているかどうか、リモート ウェイクアップを示しているかどうかを確認するには、WINUSB_DEVICE_TRAITS 列挙型で定義されている値を使います。

次のコード例では、デバイスのステータスを取得するコントロール転送要求を送ります。この例では、SendControlTransferSynchronously というヘルパー メソッドを呼び出して、要求を同期的に送ります。



HRESULT  
CDevice::GetDeviceStatus ()  
{  

    HRESULT hr = S_OK;

    USHORT deviceStatus;  
    ULONG bytesTransferred;  
  
  
    TraceEvents(TRACE_LEVEL_INFORMATION,  
                DRIVER_ALL_INFO,  
                "%!FUNC!: entry");  
  
 
    // Setup the control packet.      

    WINUSB_CONTROL_SETUP_PACKET setupPacket;  
  
    WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(  
                                      &setupPacket,  
                                      BmRequestToDevice,  
                                      0);  

    hr = SendControlTransferSynchronously(  
                 &(setupPacket.WinUsb),  
                 & deviceStatus,  
                 sizeof(USHORT),  
                 &bytesReturned  
                ); 

     if (SUCCEEDED(hr))  
    {  
        if (deviceStatus & USB_GETSTATUS_SELF_POWERED)
        {
             m_Self_Powered = true;
        } 
        if (deviceStatus & USB_GETSTATUS_REMOTE_WAKEUP_ENABLED)
        {
             m_remote_wake-enabled = true;
        }  

    }  

  
    return hr;  

 }


次のコード例は、SendControlTransferSynchronously というヘルパー メソッドの実装を示しています。このメソッドは要求を同期的に送ります。



HRESULT  
CDevice::SendControlTransferSynchronously(  
    _In_ PWINUSB_SETUP_PACKET SetupPacket,  
    _Inout_ PBYTE Buffer,  
    _In_ ULONG BufferLength,  
    _Out_ PULONG LengthTransferred  
    )  
{  
    HRESULT hr = S_OK;  
    IWDFIoRequest *pWdfRequest = NULL;  
    IWDFDriver * FxDriver = NULL;  
    IWDFMemory * FxMemory = NULL;   
    IWDFRequestCompletionParams * FxComplParams = NULL;  
    IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL;  
  
    *LengthTransferred = 0;  
      
    hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface
                                    NULL, //pParentObject
                                    &pWdfRequest);  
  
    if (SUCCEEDED(hr))  
    {  
        m_FxDevice->GetDriver(&FxDriver);  
  
        hr = FxDriver->CreatePreallocatedWdfMemory( Buffer,  
                                                    BufferLength,  
                                                    NULL,        //pCallbackInterface
                                                    pWdfRequest, //pParetObject
                                                    &FxMemory );  
    }  
  
    if (SUCCEEDED(hr))  
    {  
        hr = m_pIUsbTargetDevice->FormatRequestForControlTransfer( pWdfRequest,  
                                                                   SetupPacket,  
                                                                   FxMemory,  
                                                                   NULL); //TransferOffset
    }                                                            
                          
    if (SUCCEEDED(hr))  
    {  
        hr = pWdfRequest->Send( m_pIUsbTargetDevice,  
                                WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,  
                                0); //Timeout      }  
  
    if (SUCCEEDED(hr))  
    {  
        pWdfRequest->GetCompletionParams(&FxComplParams);  
  
        hr = FxComplParams->GetCompletionStatus();  
    }  
  
    if (SUCCEEDED(hr))  
    {  
        HRESULT hrQI = FxComplParams->QueryInterface(IID_PPV_ARGS(&FxUsbComplParams));  
        WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI));  
  
        WUDF_TEST_DRIVER_ASSERT( WdfUsbRequestTypeDeviceControlTransfer ==   
                            FxUsbComplParams->GetCompletedUsbRequestType() );  
  
        FxUsbComplParams->GetDeviceControlTransferParameters( NULL,  
                                                             LengthTransferred,  
                                                             NULL,  
                                                             NULL );  
    }  
  
    SAFE_RELEASE(FxUsbComplParams);  
    SAFE_RELEASE(FxComplParams);  
    SAFE_RELEASE(FxMemory);  
  
    pWdfRequest->DeleteWdfObject();          
    SAFE_RELEASE(pWdfRequest);  
  
    SAFE_RELEASE(FxDriver);  
  
    return hr;  
}  



注釈

デバイスの機能ドライバーとして Winusb.sys を使う場合は、アプリケーションからコントロール転送を送ることができます。WinUSB でセットアップ パケットをフォーマットするには、このトピックの表に記載されている UMDF のヘルパー マクロと構造体を使います。要求を送るには、WinUsb_ControlTransfer 関数を呼び出します。

 

 

表示:
© 2014 Microsoft