SSブログ

USBプロジェクト - ファームウェアに立ち返る (9) [USB]このエントリーを含むはてなブックマーク#

1475712

GET_DESCRIPTORの処理を考え始めました。 サンプル・プログラムには、簡単に書いてあるのですが、仕様書を読むと色々と制約があるようです。

GET_DESCRIPTORで対応すべきデスクリプタ

標準デバイス・リクエストで対応すべきデスクリプタは、USB2.0仕様書の"9.4.3 Get Descriptor"に記述があります。 low-speedデバイスの場合には、デバイス・デスクリプタ、コンフィグレーション・デスクリプタ、ストリング・デスクリプタの三つのリクエストに対応する必要があります。 これ以外のデスクリプタには、対応することは出来ますが、必要なのか、不要なのか、可能なのか、判断がつきません。

では、HIDデバイスとしては、どうかというと、HID1.11仕様書の"7.1.1 Get_Descriptor Request"に書いてありそうです。 HID関連のデスクリプタには、HIDデスクリプタ、レポート・デスクリプタ、フィジカル・デスクリプタの三つがありますが、どれが必須なのか不明確です。 HIDデスクリプタは、標準デスクリプタのコンフィグレーション・デスクリプタに組み込まれています。 だから、単体での対応はしなくてもいいのかな?

フィジカル・デスクリプタは、"6.2.3 Physical Descriptors"に完全にオプションであると書いてあり、「必要が無ければ、ここは読み飛ばしていいよ」とだけ書いてあります。 つまり、必須ではないのは解るですが、その場合、GET_DESCRIPTORリクエストにSTALLで返答すべきか、長さ0のパケットで返答すべきかという、詳しいことは書いてありません。

レポート・デスクリプタは、サンプル・プログラムでも対応しています。 これがないと、トランザクションの長さが決まらないので、必要だとは思います。 でも、本当にこれだけで良いのか、根拠がわからないのです。

bmRequestTypeも見た方がいいと思うんだけど

サンプル・プログラムでは、bRequestだけを見て、GET_DESCRIPTORリクエストであることを認識しています。 つまり、デバイス・リクエストもクラス・リクエストも同じハンドラが処理しています。 きっと、bmRequestTypeも見た方が良いに違いないと考えて、こんなプログラムになっています。

byte parseSetup(void) {
  switch (setupBuffer.bmRequestType & 0x60) {
    case RT_STANDARD:  // Standard Request Decoder:
      switch (setupBuffer.bRequest) {
        :
        case GET_DESCRIPTOR:    // 6
          return getDescriptorSetup();
        :
      }
      break;
    case RT_CLASS:  // Class Request Decoder:
      switch (setupBuffer.bRequest) {
        :
        case GET_DESCRIPTOR:    // 6
          return getClassDescriptorSetup();
        :
      }
      break;
    default:    // Unsupported Request
      return ERR_STALL;
  }
}

GET_DESCRIPTORハンドラが、二つの関数に分かれてしまいました。 それぞれ、標準とHID特有のデスクリプタの処理を行っています。 きっと、これで正しい処理になるんだろうけど、かなり煩雑です。 まあ、今は、妥協せずにこのまま続けます。

2008-03-30 13:55 コメントで頂いた情報を転記

このHIDデバイスで実装すべきGET_DESCRIPTOR

コメントに頂いたように、以下のデスクリプタを実装すれば十分との事です。

このHIDデバイスのGETDESCRIPTORの実装
bmRequestType wValue wIndex 備考
%1000_0000 (Standard Device) $01_00 (device:0) $00_00 (ZERO) デバイス・デスクリプタを返します。
$02_00 (configuration:index0) $00_00 (ZERO) コンフィグレーション・デスクリプタを返します。インデックス0だけに応答します。
$03_0X (string:index0-2) $04_09 (LangID US English) ストリング・デスクリプタを返します。文字列を二つ定義したので、インデックス0から2の範囲で応答します。
%1000_0001 (Standard Interface) $21_00 (HID:ZERO) $00_00 (interface0) HIDデスクリプタを返します。インターフェース0にだけ応答します。
$22_00 (report:index0) $00_00 (interface0) レポート・デスクリプタを返します。インターフェース0にだけ応答します。また、インデックス0だけに応答します。

USB2.0仕様書の"9.6.7 String"によると、 ストリング・デスクリプタで有効な言語ID一覧は、ストリング・デスクリプタのインデックス0に入っています。 この一覧だけは、指定された言語IDに関わらず同じものが返ってきます。 すると、GET_DESCRIPTORリクエストの実装では、言語IDのValidationは、省略したほうが賢明なのかな?

付録 : USBプロジェクト索引

参考文献

USBハード&ソフト開発のすべて―USBコントローラの使い方からWindows/Linuxドライバの作成まで (TECHI―Bus Interface)

USBハード&ソフト開発のすべて―USBコントローラの使い方からWindows/Linuxドライバの作成まで (TECHI―Bus Interface)

  • 作者: インターフェース編集部
  • 出版社/メーカー: CQ出版
  • 発売日: 2006/07
  • メディア: 単行本

nice!(0)  コメント(4)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 4

Tsuneo

Get_Descriptor はUSB2.0、HIDやCDCなど個別のスペックでやや混乱した定義となっています。
このCommon Classの定義に従うのが良いでしょう。

"Common Class Base Specification 1.0"
http://www.usb.org/developers/devclass_docs/usbccs10.pdf

3.11 Identifying Class and Vendor-Specific Requests and Descriptors (usbccs10.pdf p8)
The standard GET_DESCRIPTOR request (with the bRequestType.Type field set to standard) is used to directly request class or vendor-specific descriptors. The class associated with such a request is determined by the class of the bmRequestType.Recipient. When the bmRequestType.Recipient field is set to INTERFACE or ENDPOINT, the wIndex field identifies the desired interface or endpoint. All endpoints within an interface use that interface's class, subclass and protocol.

多少補ってまとめると、
- bRequestType.Typeフィールドが標準(bRequestType = 100x xxxxB)のGet_Descriptor リクエストが、標準、クラス、ベンダすべてのデスクリプタに対する要求を扱う。

- bmRequestType.Recipientフィールドがデバイスのとき(bRequestType = 1000 0000)、
9.4.3 Get Descriptor (usb_20.pdf p253)
に従う。
ここでサポートすべきデスクリプタは、ロー/フルスピードデバイスでは
- - デバイス・デスクリプタ
- - コンフィギュレーション・デスクリプタのセット
- - ストリング・デスクリプタ
の3種類のみ。他は不用です。

- bmRequestType.Recipientフィールドがインターフェースのとき(bRequestType = 1000 0001)、wIndexフィールドが求めるデスクリプタの属するインターフェース番号を指定する。(コンポジットデバイスへの対応)
HIDクラスでは、
- - HIDデスクリプタ
- - レポート・デスクリプタ
へのリクエストをサポートする。

以上でスペックを完全に満足しています。
このデバイスのエンドポイントの数から、マウス+キーボードなどHIDX2のコンポジットデバイスまで実装できます。コンポジットデバイスに対応できる構成にしておいた方が拡張性が高いでしょう。(実はマウス+キーボードなら1つのHIDインターフェースでサポートする方法もありますが)


>HIDデスクリプタは、標準デスクリプタのコンフィグレーション・デスクリプタに組み込まれています。 だから、単体での対応はしなくてもいいのかな?

確かに私もHIDデスクリプタが実際に要求されるのを見たことはありません。
ただ、HIDのスペックは必須ともオプションとも書いてはいません。
念のためサポートしておいた方が安全でしょう。

>つまり、必須ではないのは解るですが、その場合、GET_DESCRIPTORリクエストにSTALLで返答すべきか、長さ0のパケットで返答すべきかという、詳しいことは書いてありません。

サポートしないリクエストはすべてSTALLを返します。
サポートしているリクエストでも、要求されたパラメータがサポート条件に合致しない場合もSTALLします。
この場合もそうです。

Tsuneo
by Tsuneo (2008-03-30 11:54) 

noritan

Tsuneoさん、ありがとうございます。

どんどん、仕様書が増えていきますね。
このBLOGには、「検索」の機能があるのに「コメント」の中までは検索してくれません。後から参照する時のために、本文の方にどんどん転記させていただきます。

by noritan (2008-03-30 13:20) 

Tsuneo

>GET_DESCRIPTORハンドラが、二つの関数に分かれてしまいました。

前のコメントがまとまりが無くてうまく伝わらなかったようですが、Get_Descriptor は2つに分ける必要はありません。RT_STANDARD のものだけで、標準、クラス、ベンダすべてのデスクリプタを扱います。プログラムの中で RT_CLASSの方のGet_Descriptorは削除できます。


さて、どうして他の標準デスクリプタを返さなくても良いのか、ちゃんと根拠を示していませんでした。インターフェースとエンドポイント・デスクリプタについては、USB2.0スペックがGet_Descriptorではこれらのデスクリプタにアクセス出来ないとしているからです。

9.6.5 Interface (usb_20.pdf p267)
Interface descriptors cannot be directly accessed with a GetDescriptor() or SetDescriptor() request.

9.6.6 Endpoint (usb_20.pdf p269)
An endpoint descriptor cannot be directly accessed with a GetDescriptor() or SetDescriptor() request.

また、Device_QualifierとOther_Speed_Configuration デスクリプタはハイスピードデバイスでのみ使用するので、ロー/フルスピードデバイスではそもそもこれらのデスクリプタを実装しません。


>GET_DESCRIPTORリクエストの実装では、言語IDのValidationは、省略したほうが賢明なのかな?

好みの問題でしょう。両極端を言えば、
- とにかくすべてのパラメータ(デバイスステートも含めて)を厳重にチェックする
- 省略可能なチェックはすべて省略する
という態度があり得ます。お好きな落としどころを見つけてください。

実はUSBCV(コンプライアンステスト)はそこまで厳重にテストしないので、かなり省略しても通ります。厳重にチェックした方がコードサイズは増えますが、悩むことが減って早く片づきます。

なお、GetDescriptor( String )で、インデックス(wValueのLSB)の有効範囲のチェックは省略しない方が良いでしょう。Windows は特有のインデックス(0xEE)を指定してくることがあります。またWindowsのUSBView はインデックス0からSTALLするまでストリングのスキャンをかけます。

Microsoft-Defined USB Descriptors
http://msdn2.microsoft.com/en-us/library/ms790473.aspx

Tsuneo
by Tsuneo (2008-03-30 17:11) 

noritan

Tsuneoさん、毎度ありがとうございます。

GET_DESCRIPTORリクエストに関して言えば、bmRequestTypeは、D6..5の"Type"だけを気にすれば良くて、下位5ビットの"Recipient"は、条件分岐に使用する必要は無いということなんですね。了解です。

言語IDは、ひとまずは、素通しでいきます。慣れたら、「日本語対応」というのもやってみたいですね。

by noritan (2008-03-31 21:57) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。