前回まで紹介したBurst Transferは、単純に大量のデータを連続して送る際に利用されるが、これと一緒に定義されているのがBulk Streamである。実際プロトコルを見る限り、両者の主要な違いはPipeがあるかどうか、に尽きる。Streamを使う場合、Streamの管理はPacket Headerに格納されたStream IDで行う事になる。

そもそもPIPEとは何か? という話である。ここで言うPipeは、USB 3.0のPHYとMACを繋ぐPIPE(PHY Interface for the PCI Express and USB 3.0)ではなく、281回などでも触れた、仮想的な通信経路である。この概念はUSB 1.1/2.0から存在したもので、このメカニズムをUSB 3.0でもそのまま引き継いでいる。なので、まずはUSB 1.1/2.0におけるPIPEについてちょっと簡単に説明してみたい。

PIPEとは、DeviceのEndpointと、Host上で動くApplication Softwareの間に形成される、仮想的な通信経路である。SoftwareはこのPIPEにデータを送り込んだり、あるいはPIPEからデータを受け取るという形で、USB Deviceとのデータのやり取りを行う事になる。実際にはApplicationがPIPEとの通信用のBufferを格納し、送信ならBufferにデータを埋めた後で、受信ならばBufferを空にした上で、それぞれBufferのpointerを渡すようなイメージだと思えばよい。

PIPEとの通信方式にはStreamとMessageの2種類がある。Messageは、USBで定義されたデータ構造を使って転送を行う形であり、対してStreamではUSBではユーザー独自定義のデータ構造で転送を行うのが違いということになる。USBそのものはデータの中身それ自体を解釈したり操作したりすることはない。PIPEには加えて、

  • どの程度の帯域を必要とするかの宣言
  • 転送タイプ
  • DeviceのEndpointの特性(通信方向とか最大転送サイズなど)

を属性として持つ。

実は全てのDeviceは、0番のEndPointを必ず持つことが定められおり、この0番のEndpointとのPIPEをDefault Control PIPEと称する。これは要するにデフォルトの通信手段なのであって、必要に応じてEndpointの数(や、それに繋げるPIPEの数)は増やすことが出来るので、例えば初期化が終わったらDeviceのFunction毎に異なるPIPEを使って通信する、なんて事も可能だが、各Deviceの初期化などに関してはこのControl PIPEを使って通信を行うことになる。

さて、このPIPEを使ってデータを送るのに、Stream PIPEとMessage PIPEの2種類がある、というのは実はUSB 1.1/2.0から存在している。USB 1.1/2.0の場合、Stream PIPEでは、DeviceとApplicationの間は単なるFIFO式の通信路(文字通りのPipe)が形成される。ここでは例えばタイミング同期といった事は不要(というか、出来ない)だし、データの送出順序も完全に保障される(だからこそのFIFOである)。また一つのStream PIPEには1対の送受信Clientが対応しており、複数のClientがぶら下がることは考慮されていない(というか、実際には複数Clientが繋がることは出来ない)。要するに、UNIXのFilesystemにおけるPIPEの様に、極めて単純な使い方が可能だし、逆にそれ以外の使い方は出来ない事になる。

これに対してMessageは? というと、こちらはきちんとプロトコルを考慮して通信を行う事が求められる。まずHost上のApplication Softwareから特定のDeviceに対してRequestを掛け、次いで転送方向に応じてHostなりDeviceから相手にDataを転送し、最後にStatusを交換して一連の作業が終了する。要するにここまで説明してきたような流れをApplication Softwareがハンドリングする必要があるわけだ。

もっとも実際のインプリメントを考えた場合、例えばExplolerでUSB Flash Memoryにファイルを転送する場合に、Expololerがここまでハンドリングすることは無い。こうした作業はBase DriverなりMiniPort Driverなりがハンドリングすることで、Explolerがここまで管理するわけではないからだ。ただStream PIPEの場合は、送受信の一連の流れを全部ドライバに任せられるのに対し、例えばUSB Audioの様に細かく管理するものはMessage PIPEを使うことになり、実際のハンドリングはもう少し上のClass DriverやFilter Driverが行うことになるという違いはある。

(続く)