ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
![]() |
デバイスドライバの記述 Oracle Solaris 11.1 Information Library (日本語) |
パート I Oracle Solaris プラットフォーム用デバイスドライバの設計
2. Oracle Solaris カーネルとデバイスツリー
USB デバイスと Oracle Solaris デバイスツリー
デバイス、インタフェース、エンドポイントの各ステータスの取得
22. ドライバのコンパイル、ロード、パッケージ化、およびテスト
23. デバイスドライバのデバッグ、テスト、およびチューニング
このセクションでは、USB デバイスへのアクセス方法やクライアントドライバの登録方法について説明します。このセクションでは、記述子ツリーについても説明します。
クライアントドライバが接続される前に、次のイベントが発生します。
最初のクライアントドライバが接続される前に、PROM (OBP/BIOS) と USBA フレームワークがデバイスにアクセスします。
ハブドライバが、ハブの各ポート上のデバイスでアイデンティティーと構成を調べます。
各デバイスへのデフォルト制御パイプが開かれ、各デバイスのデバイス記述子が調べられます。
デバイスごとに、そのデバイス記述子とインタフェース記述子に基づいて互換名プロパティーが構築されます。
互換名プロパティーは、クライアントドライバに個別にバインド可能なデバイスのさまざまな部分を定義します。クライアントドライバは、デバイス全体にバインドすることも、1 つのインタフェースだけにバインドすることもできます。「クライアントドライバのバインド」を参照してください。
記述子の解析時には、構造体のメンバーが自然な境界に位置合わせされたあと、ホストの CPU のエンディアンに変換されます。解析後の標準 USB 構成記述子、インタフェース記述子、およびエンドポイント記述子は、各構成の階層ツリーの形でクライアントドライバから使用可能となります。クラス固有またはベンダー固有の raw 記述子情報もすべて、同じ階層ツリー内でクライアントドライバから使用可能となります。
階層記述子ツリーを取得するには、usb_get_dev_data(9F) 関数を呼び出します。usb_get_dev_data (9F) のマニュアルページの「関連項目」セクションには、各標準 USB 記述子のマニュアルページの一覧が含まれています。raw 記述子情報を解析するには、usb_parse_data(9F) 関数を使用します。
2 つの構成を含むデバイスの記述子ツリーは、次の図に示すようなツリーになります。
図 20-3 階層 USB 記述子ツリー
上図に示した dev_cfg 配列には、構成に対応するノードが含まれています。各ノードに含まれる情報は次のとおりです。
解析後の構成記述子
その構成のインタフェースに対応する記述子の配列へのポインタ
クラス固有またはベンダー固有の raw データが存在する場合はその配列へのポインタ
2 番目のインデックスで指定された構成の 2 番目のインタフェースを表すノードは、図で dev_cfg[1].cfg_if[1] の位置にあります。そのノードには、そのインタフェースの代替設定を表すノードの配列が含まれています。USB 記述子の階層はツリーの全体にわたって伝播されます。文字列記述子データに含まれる ASCII 文字列は、USB 仕様でこれらの文字列が存在するとされている場所に接続されます。
構成の配列は間が空いておらず、構成インデックスでインデックス指定されます。最初の有効な構成 (構成 1) は、dev_cfg[0] です。インタフェースと代替設定のインデックスは、それらの個数に対応した値になります。各代替設定のエンドポイントは連続的にインデックス指定されます。各代替設定の最初のエンドポイントはインデックス 0 です。
この採番方式によりツリーのトラバースが容易に行えます。たとえば、エンドポイントインデックス 0、代替 0、インタフェース 1、構成インデックス 1 の raw 記述子データは、次のパスで定義されるノードの位置にあります。
dev_cfg[1].cfg_if[1].if_alt[0].altif_ep[0].ep_descr
記述子ツリーを直接使用する代わりに usb_lookup_ep_data(9F) 関数を使用することもできます。usb_lookup_ep_data(9F) 関数は、引数としてインタフェース、代替設定、エンドポイント、エンドポイントタイプ、および向きを取ります。usb_lookup_ep_data(9F) 関数を使用すると、記述子ツリーをたどって特定のエンドポイントを取得できます。詳細については、usb_get_dev_data(9F) のマニュアルページを参照してください。
クライアントドライバからの USBA 2.0 フレームワーク への最初の 2 つの呼び出しは、usb_client_attach(9F) 関数と usb_get_dev_data(9F) 関数の呼び出しです。これら 2 つの呼び出しは、クライアントドライバの attach(9E) エントリポイントから行われます。usb_get_dev_data(9F) 関数を呼び出す前に usb_client_attach(9F) 関数を呼び出す必要があります。
usb_client_attach(9F) 関数は、USBA 2.0 フレームワーク にクライアントドライバを登録します。usb_client_attach(9F) 関数ではバージョン管理が実行されます。クライアントドライバのソースファイルは必ず、次の行で始まっている必要があります。
#define USBDRV_MAJOR_VER 2 #define USBDRV_MINOR_VER minor-version #include <sys/usb/usba.h>
minor-version の値は USBA_MINOR_VER 以下である必要があります。シンボル USBA_MINOR_VER は <sys/usb/usbai.h> ヘッダーファイル内で定義されています。<sys/usb/usbai.h> ヘッダーファイルは <sys/usb/usba.h> ヘッダーファイルによってインクルードされます。
USBDRV_VERSION は、USBDRV_MAJOR_VERSION と USBDRV_MINOR_VERSION からバージョン番号を生成するマクロです。usb_client_attach() の第 2 引数は USBDRV_VERSION である必要があります。この第 2 引数が USBDRV_VERSION でない場合や USBDRV_VERSION が無効なバージョンを反映している場合には、usb_client_attach() 関数が失敗します。この制限により、プログラミングインタフェースの互換性が確保されます。
usb_get_dev_data() 関数は、適切な USB デバイス管理に必要な情報を返します。たとえば、usb_get_dev_data() 関数から次の情報が返されます。
mutex の初期化に使用する iblock_cookie (mutex_init(9F) を参照)
解析後のデバイス記述子
ID 文字列
「記述子ツリー」で説明したツリー階層
usb_get_dev_data() 関数の呼び出しは必須です。usb_get_dev_data() を呼び出すことが、デフォルト制御パイプを取得したり mutex の初期化に必要な iblock_cookie を取得したりするための唯一の方法です。
クライアントドライバの attach(9E) ルーチンは通常、usb_get_dev_data() を呼び出したあとで、必要な記述子やデータを記述子ツリーからドライバのソフト状態にコピーします。ソフト状態にコピーされたエンドポイント記述子は、あとでそれらのエンドポイントへのパイプを開く際に使用されます。attach(9E) ルーチンは通常、記述子をコピーしたあとで、usb_free_descr_tree(9F) を呼び出して記述子ツリーを解放します。あるいは記述子ツリーを保持し、記述子をコピーしないようにしてもかまいません。
次の 3 つの解析レベルのいずれかを usb_get_dev_data(9F) 関数に指定することで、返される記述子ツリーの範囲を決定します。ドライバがデバイスのより広い範囲にバインドする必要がある場合、より広い範囲のツリーが必要となります。
USB_PARSE_LVL_IF: クライアントドライバが特定のインタフェースにバインドする場合、ドライバが必要とするのは、そのインタフェースの記述子だけです。それらの記述子のみを取得するには、usb_get_dev_data() の呼び出し時に解析レベルとして USB_PARSE_LVL_IF を指定します。
USB_PARSE_LVL_CFG: クライアントドライバがデバイス全体にバインドする場合は、USB_PARSE_LVL_CFG を指定して現在の構成のすべての記述子を取得します。
USB_PARSE_LVL_ALL: すべての構成のすべての記述子を取得するには、USB_PARSE_LVL_ALL を指定します。たとえば、usb_print_descr_tree(9F) を使用してあるデバイスのすべての構成の記述子ダンプを出力するには、ツリーの範囲をこの最高レベルにする必要があります。
クライアントドライバの detach(9E) ルーチンは、usb_free_dev_data(9F) 関数を呼び出すことで、usb_get_dev_data() 関数によって割り当てられた資源をすべて解放する必要があります。usb_free_dev_data() 関数はハンドルを受け取りますが、そのハンドルでは、記述子ツリーがすでに usb_free_descr_tree() 関数で解放されています。さらにクライアントドライバの detach() ルーチンは、usb_client_detach(9F) 関数も呼び出すことで、usb_client_attach(9F) 関数によって割り当てられた資源をすべて解放する必要があります。