Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

デバイス通信

USB デバイスは、パイプと呼ばれる通信チャネル経由で要求を渡すことにより動作します。要求を送信するには、まずパイプをオープンする必要があります。パイプのフラッシュ、クエリー、およびクローズも行えます。このセクションでは、パイプ、データ転送とコールバック、およびデータ要求について説明します。

USB エンドポイント

4 種類の USB エンドポイントと通信を行う 4 種類のパイプを次に示します。

  • 制御。制御パイプは主に、コマンドを送信してステータスを取得するために使用されます。制御パイプは、小さいサイズの構造化データのホスト起動要求/応答通信を非定期的に行うためのものです。制御パイプは双方向です。デフォルトパイプは制御パイプです。デフォルトパイプを参照してください。

  • 一括。一括パイプは主にデータ転送に使用されます。一括パイプにより、大量のデータを確実に転送できます。一括パイプによるデータ配信は、適時に行われるとはかぎりません。一括パイプは単方向です。

  • 割り込み。割り込みパイプにより、少量の非構造化データの通信を適時かつ確実に行うことができます。定期的なポーリングは通常、割り込み入力パイプ上で開始されます。割り込み入力パイプは、デバイス上にデータが用意された時点でそのデータをホストに返します。一部のデバイスでは割り込み出力パイプも使用できます。割り込み出力パイプは割り込み入力パイプと同じく、適時性があり確実という「割り込みパイプ」の特性に基づいて、デバイスへのデータ転送を行います。割り込みパイプは単方向です。

  • アイソクロナス。アイソクロナスパイプは、オーディオデバイスの場合のように、一定速度の時間重視のデータを転送するためのチャネルを提供します。エラーが発生してもデータの再試行は行われません。アイソクロナスパイプは単方向です。

これらのエンドポイントに対応する転送タイプの詳細については、USB 2.0 仕様書の第 5 章を参照するか、要求を参照してください。

デフォルトパイプ

各 USB デバイスは、デフォルトエンドポイントと呼ばれる特殊な制御エンドポイントを持ちます。その通信チャネルはデフォルトパイプと呼ばれます。すべてではないにしろ、ほとんどのデバイス設定がこのパイプ経由で行われます。多くの USB デバイスは、自身の唯一の制御パイプとしてこのパイプを持ちます。

usb_get_dev_data(9F) 関数は、デフォルト制御パイプをクライアントドライバに提供します。このパイプは、ほかのパイプを開く前に必要とされるどのような特殊な設定にも対応できるよう、事前に開かれています。このデフォルト制御パイプは次の点で特殊です。

  • このパイプは共有されます。同じデバイスのほかのインタフェースを操作しているドライバも、同じデフォルト制御パイプを使用します。USBA 2.0 フレームワーク はこのパイプを複数のドライバ間で調停します。

  • このパイプのオープン、クローズ、またはリセットをクライアントドライバから行うことはできません。この制限が設けられているのは、このパイプが共有されるからです。

  • このパイプは例外発生時に自動的にクリアされます。

その他の制御パイプを含むほかのパイプは、明示的に開く必要があり、排他的にしか開くことができません。

パイプの状態

パイプの状態は次のいずれかになります。

  • USB_PIPE_STATE_IDLE

    • すべての制御パイプと一括パイプ、割り込み出力パイプ、およびアイソクロナス出力パイプ: 進行中の要求がありません。

    • 割り込み入力パイプとアイソクロナス入力パイプ: 進行中のポーリングがありません。

  • USB_PIPE_STATE_ACTIVE

    • すべての制御パイプと一括パイプ、割り込み出力パイプ、およびアイソクロナス出力パイプ: パイプがデータを転送しているか、入出力要求がアクティブになっています。

    • 割り込み入力パイプとアイソクロナス入力パイプ: ポーリングがアクティブになっています。

  • USB_PIPE_STATE_ERROR。エラーが発生した。このパイプがデフォルトパイプではなく、かつ自動クリアが有効になっていない場合、クライアントドライバはusb_pipe_reset(9F) 関数を呼び出す必要があります。

  • USB_PIPE_STATE_CLOSING: パイプが閉じられようとしています。

  • USB_PIPE_STATE_CLOSED: パイプが閉じられました。

パイプの状態を取得するには、usb_pipe_get_state(9F) 関数を呼び出します。

パイプのオープン

パイプを開くには、その開くパイプに対応するエンドポイント記述子をusb_pipe_open(9F) 関数に渡します。記述子ツリーからエンドポイント記述子を取得するには、usb_get_dev_data(9F) およびusb_lookup_ep_data(9F) 関数を使用します。usb_pipe_open(9F) 関数はパイプへのハンドルを返します。

パイプを開くときにパイプポリシーを指定する必要があります。パイプポリシーには、このパイプで必要になると予想される、独立したスレッドを必要とする同時非同期処理の数が含まれています。予想されるスレッド数は、コールバック中に発生する可能性のある並列処理の数です。この予想値は 2 以上である必要があります。パイプポリシーの詳細については、usb_pipe_open(9F) のマニュアルページを参照してください。

パイプのクローズ

ドライバは、usb_pipe_close(9F) 関数を使用してデフォルトパイプ以外のパイプを閉じる必要があります。usb_pipe_close (9F) 関数は、パイプ内の残りの要求がすべて完了するまで待ちます。次にこの関数は、それらの要求のすべてのコールバックが完了するまで 1 秒間待ちます。

データ転送

どのパイプタイプの場合も、プログラミングモデルは次のようになります。

  1. 要求を割り当てます。

  2. いずれかのパイプ転送関数を使用して要求を送信します。 usb_pipe_bulk_xfer(9F)usb_pipe_ctrl_xfer(9F)usb_pipe_intr_xfer(9F)、およびusb_pipe_isoc_xfer(9F) のマニュアルページを参照してください。

  3. 完了通知が届くまで待ちます。

  4. 要求を解放します。

要求の詳細については、要求を参照してください。次の各セクションでは、さまざまな要求タイプの機能について説明します。

同期および非同期転送とコールバック

転送は同期型と非同期型のいずれかになります。同期転送は、転送が完了するまでブロックします。非同期転送では、転送完了時にクライアントドライバへのコールバックが発生します。flags 引数に USB_FLAGS_SLEEP フラグを設定して呼び出された転送関数の大半は同期型になります。

ポーリングやアイソクロナス転送といった継続的な転送を同期型にすることはできません。継続的な転送向けの転送関数を呼び出すときに USB_FLAGS_SLEEP フラグを設定した場合、転送が始まる前に、リソースに対して待機するためだけに呼び出しがブロックされます。

同期転送は、設定がもっとも単純な転送です。これは、同期転送ではコールバック関数が一切必要ないからです。同期転送関数は、転送が完了するまでブロックするにもかかわらず、転送開始ステータスを返します。転送が完了すると、要求の完了理由フィールドとコールバックフラグフィールドに、転送ステータスに関する追加情報が表示されます。完了理由フィールドとコールバックフラグフィールドについては後述します。

flags 引数に USB_FLAGS_SLEEP フラグを指定しなかった場合、その転送処理は非同期型になります。この規則の例外は、アイソクロナス転送です。非同期転送処理は、転送を設定して開始したあと、転送が完了する前に戻ります。非同期転送処理は転送開始ステータスを返します。クライアントドライバは、コールバックハンドラ経由で転送完了ステータスを受け取ります。

コールバックハンドラとは、非同期転送の完了時に呼び出される関数のことです。非同期転送を設定する際には必ずコールバックを指定してください。コールバックハンドラには、正常終了ハンドラと例外ハンドラの 2 種類があります。このどちらの場合にも同じハンドラが呼び出されるように指定することもできます。

  • 正常終了。正常終了コールバックハンドラは、転送が正常終了したことを通知するために呼び出されます。

  • 例外。例外コールバックハンドラは、転送が異常終了したことを通知し、エラーを処理するために呼び出されます。

完了ハンドラと例外ハンドラはどちらも、転送の要求を引数として受け取ります。例外ハンドラは、要求内の完了理由とコールバックステータスに基づいて何が起こったのかを調べます。完了理由 (usb_cr_t) は、元のトランザクションがどのように完了したのかを示します。たとえば、完了理由 USB_CR_TIMEOUT は、転送がタイムアウトしたことを示します。別の例として、USB デバイスが使用中に削除された場合、クライアントドライバは自身の未処理の要求で、USB_CR_DEV_NOT_RESP を完了理由として受け取ります。コールバックステータス (usb_cb_flags_t) は、状況に対処するために USBA フレームワークが何を行なったのかを示します。たとえば、コールバックステータス USB_CB_STALL_CLEARED は、USBA フレームワークが機能ストールステータスをクリアしたことを示します。完了理由の詳細については、usb_completion_reason(9S) のマニュアルページを参照してください。コールバックステータスフラグの詳細については、usb_callback_flags(9S) のマニュアルページを参照してください。

コールバックのコンテキストと要求が実行されるパイプのポリシーによって、コールバック内で行える処理が制限されます。

  • コールバックコンテキスト。大部分のコールバックはカーネルコンテキストで実行され、通常はブロック可能です。一部のコールバックは割り込みコンテキストで実行され、ブロックできません。割り込みコンテキストであることを示すには、コールバックフラグに USB_CB_INTR_CONTEXT フラグを設定します。コールバックコンテキストの詳細やブロックの詳細については、usb_callback_flags(9S) のマニュアルページを参照してください。

  • パイプポリシー。同時非同期処理に関するパイプポリシーのヒントにより、並列実行可能な処理 (コールバックハンドラから実行される処理を含む) の数が制限されます。同期処理でのブロックは、1 つの処理としてカウントされます。パイプポリシーの詳細については、usb_pipe_open(9F) のマニュアルページを参照してください。

要求

このセクションでは要求構造体、および各種の要求の割り当てと割り当て解除について説明します。

要求の割り当てと割り当て解除

要求は、初期化された要求構造体として実装されます。各エンドポイントタイプはそれぞれ異なるタイプの要求を受け取ります。要求タイプごとに異なる要求構造体型が用意されています。次の表に、各要求タイプの構造体型を示します。この表では、各構造体型の割り当てや解放に使用する関数の一覧も示しています。

表 20  要求の初期化
パイプまたはエンドポイントのタイプ
要求構造体
要求構造体割り当て関数
要求構造体解放関数
制御
usb_ctrl_req_t (usb_ctrl_request(9S) のマニュアルページを参照)
一括
usb_bulk_req_t (usb_bulk_request(9S) のマニュアルページを参照)
割り込み
usb_intr_req_t (usb_intr_request(9S) のマニュアルページを参照)
アイソクロナス
usb_isoc_req_t (usb_isoc_request(9S) のマニュアルページを参照)

次の表は、各要求タイプで使用可能な転送関数の一覧です。

表 21  要求転送の設定
パイプまたはエンドポイントのタイプ
転送関数
制御
一括
割り込み
アイソクロナス

要求の割り当てと割り当て解除を行う際には、次の手順に従います。

  1. 適切な割り当て関数を使用して、必要な要求タイプの要求構造体を割り当てます。要求構造体割り当て関数のマニュアルページについては、表 20 を参照してください。

  2. 構造体内で必要なフィールドをすべて初期化します。詳細については、要求の機能とフィールドまたは対応する要求構造体のマニュアルページを参照してください。要求構造体のマニュアルページについては、表 20 を参照してください。

  3. データ転送が完了したら、適切な解放関数を使用して要求構造体を解放します。要求構造体解放関数のマニュアルページについては、表 20 を参照してください。

要求の機能とフィールド

ドライバが STREAMS 型、文字型、ブロック型のいずれであっても、データが画一的に処理されるように、すべての要求のデータがメッセージブロックとして渡されます。メッセージブロック型 mblk_t については、mblk(9S) のマニュアルページを参照してください。DDI には、メッセージブロックを操作するためのルーチンがいくつか用意されています。たとえば、allocb(9F)freemsg(9F) などがあります。メッセージブロックを操作するためのその他のルーチンについて学ぶには、allocb(9F) および freemsg(9F) のマニュアルページの「関連項目」セクションを参照してください。また、STREAMS Programming Guideも参照してください。

すべての転送タイプに含まれる要求フィールドを次に示します。各フィールド名の xxxx は、ctrlbulkintrisoc のいずれかの値になります。

xxxx_client_private

このフィールドの値は、クライアントドライバで要求と一緒に渡される内部データ用のポインタになります。デバイスにデータを転送するためにこのポインタが使用されることはありません。

xxxx_attributes

このフィールドの値は、一連の転送属性になります。このフィールドはすべての要求構造体に共通しますが、その初期化方法は転送タイプごとに若干異なります。詳細については、対応する要求構造体のマニュアルページを参照してください。これらのマニュアルページについては、表 20 を参照してください。また、usb_request_attributes(9S) のマニュアルページも参照してください。

xxxx_cb

このフィールドの値は、転送が正常終了した場合のコールバック関数になります。この関数は、非同期転送がエラーなしで完了した場合に呼び出されます。

xxxx_exc_cb

このフィールドの値は、エラー処理用のコールバック関数になります。この関数が呼び出されるのは、非同期転送でエラーが発生した場合だけです。

xxxx_completion_reason

このフィールドには転送自体の完了ステータスが保持されます。エラーが発生した場合にこのフィールドを見れば、どのような問題が発生したのかがわかります。詳細については、usb_completion_reason(9S) のマニュアルページを参照してください。このフィールドは USBA 2.0 フレームワーク によって更新されます。

xxxx_cb_flags

このフィールドには、USBA 2.0 フレームワーク がコールバックハンドラを呼び出す前に行なった復旧アクションのリストが含まれています。USB_CB_INTR_CONTEXT フラグは、コールバックが割り込みコンテキストで実行されているかどうかを示します。詳細については、usb_callback_flags(9S) のマニュアルページを参照してください。このフィールドは USBA 2.0 フレームワーク によって更新されます。

次の各セクションでは、4 つの転送タイプでそれぞれ異なる要求フィールドについて説明します。これらのセクションでは、それらの構造体フィールドを初期化する方法について説明します。また、属性やパラメータのさまざまな組み合わせに関する制限についてもこれらのセクションで説明します。

制御要求

制御パイプ経由でメッセージ転送を開始するには、制御要求を使用します。後述するように、転送は手動で設定できます。また、usb_pipe_ctrl_xfer_wait(9F) ラッパー関数を使用して同期転送を設定および送信することもできます。

クライアントドライバは、USB 2.0 仕様書に記載されているように、ctrl_bmRequestTypectrl_bRequestctrl_wValuectrl_wIndexctrl_wLength の各フィールドを初期化する必要があります。

要求の ctrl_data フィールドは、データバッファーを指すように初期化する必要があります。usb_alloc_ctrl_req(9F) 関数は、バッファーの len に正の値が渡された場合、このフィールドを初期化します。もちろん、アウトバウンド転送ではこのバッファーを必ず初期化する必要があります。いずれにしても、クライアントドライバは、転送完了時に要求を解放する必要があります。

複数の制御要求をキューに登録できます。キューに登録する要求として、同期要求と非同期要求を組み合わせてもかまいません。

ctrl_timeout フィールドは、要求が処理されるまでの最大待機時間を定義します。ただし、キューでの待機時間は含めません。このフィールドは同期要求と非同期要求の両方に適用されます。 ctrl_timeout フィールドは秒単位で指定します。

ctrl_exc_cb フィールドには、例外の発生時に呼び出す関数のアドレスを指定します。この例外ハンドラの引数については、usb_ctrl_request(9S) のマニュアルページを参照してください。例外ハンドラの第 2 引数は、usb_ctrl_req_t 構造体です。要求構造体を引数として渡せば、例外ハンドラから要求の ctrl_completion_reason および ctrl_cb_flags フィールドをチェックし、最適な復旧アクションを決定することが可能となります。

USB_ATTRS_ONE_XFER および USB_ATTRS_ISOC_* フラグは、すべての制御要求で無効な属性です。USB_ATTRS_SHORT_XFER_OK フラグは、ホスト宛ての要求でのみ有効です。

一括要求

処理時間の要件が高くないデータを送信するには、一括要求を使用します。バス全体の負荷によっては、一括要求が完了するまでに数 USB フレームかかる可能性があります。

すべての要求は、初期化済みのメッセージブロックを受け取る必要があります。mblk_t メッセージブロック型の説明については、mblk(9S) のマニュアルページを参照してください。このメッセージブロックは、転送の向きに応じてデータ提供とデータ格納のいずれかを行います。詳細については、usb_bulk_request(9S) のマニュアルページを参照してください。

USB_ATTRS_ONE_XFER および USB_ATTRS_ISOC_* フラグは、すべての一括要求で無効な属性です。USB_ATTRS_SHORT_XFER_OK フラグは、ホスト宛ての要求でのみ有効です。

usb_pipe_get_max_bulk_transfer_size(9F) 関数は、要求当たりの最大バイト数を指定します。取得した値は、クライアントドライバのminphys(9F) ルーチンで使用される最大値として指定できます。

複数の一括要求をキューに登録できます。

割り込み要求

割り込み要求は通常、定期的なインバウンドデータ用です。割り込み要求は、定期的にデバイスにポーリングしてデータの有無を確認します。ただし、USBA 2.0 フレームワーク では、1 回かぎりのインバウンド割り込みデータ要求やアウトバウンド割り込みデータ要求がサポートされています。USB 割り込み転送機能の適時性と再試行は、どの割り込み要求でも利用できます。

USB_ATTRS_ISOC_* フラグは、すべての割り込み要求で無効な属性です。USB_ATTRS_SHORT_XFER_OK および USB_ATTRS_ONE_XFER フラグは、ホスト宛ての要求でのみ有効です。

1 回かぎりのポーリングは必ず同期割り込み転送として実行されます。要求で USB_ATTRS_ONE_XFER 属性を指定すると、1 回かぎりのポーリングになります。

定期的なポーリングは、非同期割り込み転送として開始されます。元の割り込み要求を usb_pipe_intr_xfer(9F) に渡します。ポーリング中に返す新しいデータが見つかると、新しい usb_intr_req_t 構造体が元の要求から複製され、初期化済みのデータブロックが設定されます。要求を割り当てる際には、usb_alloc_intr_req(9F) 関数の len 引数にゼロを指定します。len 引数をゼロにするのは、USBA 2.0 フレームワーク がコールバックごとに新しい要求の割り当てやデータ設定を行うからです。要求構造体の割り当て後、その intr_len フィールドを設定することで、ポーリングごとにフレームワークが割り当てるバイト数を指定します。intr_len バイトを超えるデータは返されません。

クライアントドライバは、受け取った各要求を解放する必要があります。メッセージブロックをアップストリームに送信する場合、送信を行う前にメッセージブロックを要求から切り離します。メッセージブロックを要求から切り離すには、要求のデータポインタを NULL に設定します。要求のデータポインタを NULL に設定すると、要求が割り当て解除されるときに、メッセージブロックが解放されるのを防ぐことができます。

定期的なポーリングを取り消すには、usb_pipe_stop_intr_polling(9F) 関数を呼び出します。ポーリングを停止したりパイプを閉じたりすると、例外コールバック経由で元の要求構造体が返されます。この返される要求構造体の完了理由には、USB_CR_STOPPED_POLLING が設定されます。

ポーリングがすでに進行中である場合にポーリングを開始しないでください。usb_pipe_stop_intr_polling(9F) の呼び出しの進行中にポーリングを開始しないでください。

アイソクロナス要求

アイソクロナス要求は、一定速度の時間重視のストリーミングデータ用です。エラー時の再試行は行われません。アイソクロナス要求には次の要求固有フィールドが含まれています。

isoc_frame_no

転送全体を特定のフレーム番号から始める必要がある場合に、このフィールドを指定します。このフィールドの値は、現在のフレーム番号よりも大きい必要があります。現在のフレーム番号を取得するには、usb_get_current_frame_number(9F) を使用します。現在のフレーム番号は刻々変化します。低速バスやフルスピードバスでは、現在のフレームは 1 ミリ秒ごとに更新されます。高速バスでは、現在のフレームは 0.125 ミリ秒ごとに更新されます。isoc_frame_no フィールドが認識されるように、USB_ATTR_ISOC_START_FRAME 属性を設定します。

このフレーム番号フィールドを無視してできるだけすぐに開始するには、USB_ATTR_ISOC_XFER_ASAP フラグを設定します。

isoc_pkts_count

このフィールドは、リクエスト内のパケット数です。この値は、usb_get_max_pkts_per_isoc_request(9F) 関数から返される値と isoc_pkt_descr 配列 (後述の説明を参照) のサイズによって制限されます。このリクエストで転送可能なバイト数は、この isoc_pkts_count 値とエンドポイントの wMaxPacketSize 値の積に等しくなります。

isoc_pkts_length

このフィールドは、要求のすべてのパケットの長さを合計したものになります。この値はイニシエータによって設定されます。isoc_pkt_descr リストの isoc_pkts_length の合計が自動的に使用されるようにこの値はゼロに設定し、この要素にチェックが適用されないようにしてください。

isoc_error_count

このフィールドは、エラーが発生して完了したパケットの数です。この値は USBA 2.0 フレームワーク によって設定されます。

isoc_pkt_descr

このフィールドは、各パケットのデータ転送量を定義したパケット記述子の配列を指します。送信要求の場合、この値は処理対象のサブ要求の非公開キューを定義します。受信要求の場合、この値は、データがどのように分割されて到着するかを記述します。送信要求の場合、クライアントドライバがこれらの記述子を割り当てます。受信要求の場合、フレームワークがこれらの記述子の割り当てと初期化を行います。この配列の各記述子にはフレームワークによって初期化されたフィールドが含まれており、それらのフィールドには、実際に転送されたバイト数と転送ステータスが保持されています。詳細については、usb_isoc_request(9S) のマニュアルページを参照してください。

すべての要求は、初期化済みのメッセージブロックを受け取る必要があります。このメッセージブロックはデータ提供とデータ格納のいずれかを行います。mblk_t メッセージブロック型の説明については、mblk(9S) のマニュアルページを参照してください。

USB_ATTR_ONE_XFER フラグは不正な属性です。システムが使用可能なパケット経由でデータ量をどのように変化させるかを決定するからです。USB_ATTR_SHORT_XFER_OK フラグは、ホスト宛てのデータでのみ有効です。

usb_pipe_isoc_xfer(9F) 関数は、USB_FLAGS_SLEEP フラグの設定の有無にかかわらず、すべてのアイソクロナス転送を非同期にします。アイソクロナス入力要求では必ずポーリングが開始されます。

定期的なポーリングを取り消すには、usb_pipe_stop_isoc_polling(9F) 関数を呼び出します。ポーリングを停止したりパイプを閉じたりすると、例外コールバック経由で元の要求構造体が返されます。この返される要求構造体の完了理由には、USB_CR_STOPPED_POLLING が設定されます。

ポーリングは、次のいずれかのイベントが発生するまで継続されます。

  • usb_pipe_stop_isoc_polling (9F) 呼び出しが受信された。

  • 例外コールバック経由でデバイスの切り離しが報告された。

  • usb_pipe_close(9F) 呼び出しが受信された。

パイプのフラッシュ

エラー発生後にパイプをクリーンアップする必要に迫られたり、パイプが空になるまで待機したりする可能性があります。パイプのフラッシュやクリアを行うには、次のいずれかの方法を使用します。

  • usb_pipe_reset(9F) 関数はパイプをリセットし、すべての要求をフラッシュします。これは、自動クリアが有効になっていないパイプがエラー状態になった場合に行ってください。パイプの状態を確認するには、usb_pipe_get_state(9F) を使用します。

  • usb_pipe_drain_reqs(9F) 関数は、保留中のすべての要求が完了するまで待ちながらブロックしたあと、処理を続行します。この関数は、無期限に待機することも、指定された期間のあとでタイムアウトすることもできます。usb_pipe_drain_reqs (9F) 関数は、パイプを閉じることもフラッシュすることもしません。