SSブログ

NuDCLその9 [Mac用USBデバイス工作]

FireWireのアイソクロナス転送でデータをやりとりするためのMacOS XのI/O Kitによるメカニズムである2種類のDCLを比較している。そして古いDCLで書いたIIDCカメラのドライバを新しいNuDCLを使ったものに書き換えたくて、AppleのサンプルコードであるUniversalReceiveTestの中身を見ている。昨日はアイソクロナス転送をするC++クラスであるUniversalReceiverのコンストラクタを確認した。インスタンス変数の設定以外にほとんど何もしていない、ということはわかった。今日はクライアント側からつぎに呼ばれるメンバ関数の中身を見る。

3.4  setupIsocReceiver関数

さっきのUniversalReceiverRTThreadStart関数の中でコンストラクタが呼ばれたあと、次に呼ばれる。この関数でNuDCL列を作っている。これも結構大きな関数だけど、順に見る。

3.4.1  ローカルノードのインタフェイスを得る

まずデバイスインターフェイスからローカルノードのインターフェイス、つまりFireWireのMac側のインターフェイスを作っている(これもAVSCommon.cppに定義されたヘルパ関数を使っている)。

インターフェイスが手に入ると、CFRunLoopGetCurrent関数で自分の乗っているCFRunLoopを得る。これはCreateUniversalReceiver関数で作られたスレッドの上のランループになっているはず。

ランループにローカルノードのコールバックのディスパッチャを登録したあと、CFMutableSetの配列を作っている。配列の長さはsegmentの個数になっている。これはNuDCLをアップデートするときに使う集合として使われるもの。

それからNuDCLPoolを作っている。

3.4.2  次の作業

そのあとは以前やったのと同じ。
  1. リモートポートを作る
  2. リモートポート用のハンドラを設定する
  3. vm_allocateで転送用のバッファ領域を確保する
  4. DCLのover run用やタイムスタンプ用のバッファのポインタを設定する
などをやっている。

3.4.3  NuDCLコマンド列を作る

コマンドをプール関数を使って作っていくが、それが2重ループになっている。
    for (seg = 0 ; seg < isochSegments ; seg++) {
        pSegUpdateBags[seg] = CFSetCreateMutable(NULL, 0, NULL);
        for (cycle = 0 ; cycle < isochCyclesPerSegment ; cycle++) {
            ...
外側がsegment、内側がcycle用になっている。まずsegmentにひとつCFMutableSetを作っている。

一番内側のループ(cycle)の最初は
            range.address = (IOVirtualAddress) &pBuffer[bufCnt * cycleBufLen];
            range.length = (IOByteCount) cycleBufLen;
            thisDCL = (*nuDCLPool)->AllocateReceivePacket(
                                                nuDCLPool,
                                                pSegUpdateBags[seg],
                                                4,
                                                1,
                                                &range);
となっていて、バッファのアドレスを設定したあとプールからパケットを受け取るNuDCLコマンドを作っている。bufCntというのは最初に0に設定されていて、cycleループの最後にインクリメントされている。

その次にフラグの設定などがあって
            if (cycle == 0) {
                receiveSegmentInfo[seg].segmentStartDCL = thisDCL;
                (*nuDCLPool)->SetDCLTimeStampPtr(thisDCL, &pTimeStamps[seg]) ;
            }
segmentの最初のcycleの場合にUniversalReceiveSegment構造体のふたつのポインタのうちStartDCLポインタをさっき作ったReceivePacketDCLに設定して、さらにタイムスタンプのバッファも指定している。

それに続いて
            else if (cycle == (isochCyclesPerSegment-1)) {
                receiveSegmentInfo[seg].segmentEndDCL = thisDCL;
                (*nuDCLPool)->SetDCLUpdateList(thisDCL,
                                               pSegUpdateBags[seg]) ;
                (*nuDCLPool)->SetDCLCallback(thisDCL,
                                             UniversalReceiveDCLCallback_Helper) ;
            }
            bufCnt++;
としている。つまりひとつのsegmentの最後のcycleだった場合、UniversalReceiveSegmentのもう一方のポインタを設定して、アップデートして、DCLコールバックを呼ぶ、ということをしている。cycleとsegmentのループはこれで終わっている。

これは整理すると、
  1. cycleBufferSize(=cycleBufLen)バイトのパケットを受ける
  2. cyclesPerSegment(=isochCyclesPerSegment)回繰り返す
  3. updateする
  4. コールバックを呼ぶ
  5. 以上をnumSegments(=isochSegments)回繰り返す
ということをしている。コールバックは一度にcyclesPerSegment個のパケットを処理することになる。従ってここではcycleというのはパケットの到来と同じ意味である。

そのすぐあとに
    range.address = (IOVirtualAddress) pOverrunReceiveBuffer;
    range.length = (IOByteCount) cycleBufLen;
    thisDCL = (*nuDCLPool)->AllocateReceivePacket(
                                    nuDCLPool,
                                    NULL,
                            // No update-bag needed for this DCL!
                                    4,
                                    1,
                                    &range);
となっていてもうひとつ追加でパケットを受け取るようになっていてさらに
        overrunDCL = thisDCL;
        ....
        (*nuDCLPool)->SetDCLCallback(thisDCL,
                        UniversalReceiveOverrunDCLCallback_Helper) ;
となっている。overrunDCLというのはインスタンス変数。そしてこのNuDCLコマンドに別のコールバック関数を設定している。古いDCLにもあったover run検出用のコールバックとなっている。

3.4.4  残りの作業

あとは
  1. ローカルポートを作る
  2. ローカルポートのfinalizeコールバックを設定する
  3. アイソクロナスチャンネルを作る
  4. チャンネルにローカルポートをリスナ、リモートポートをトーカとして設定する
  5. チャンネルのForceStopHandlerコールバックを設定する
  6. チャンネルの通知をオンにする
  7. 自分自身のfixupDCLJumpTargets関数を呼ぶ
ということをやっている。FireWireドキュメントのサンプルコードにはなかった作業がいくつか含まれているが、まあ何をやっているのかは名前から想像がつくのでとりあえずおいておく。
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

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

トラックバック 0

献立07/07献立07/12 ブログトップ

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