SSブログ

Mac用USBデバイス-41 FireWire抄訳その2 [Mac用USBデバイス工作]

FireWire Device Interface Guide」の意訳の続き。最初のこのあたりはUSBでやったのと同じことなので、訳するのも速い。

Accessing FireWire Devices From Applications

FireWireファミリのdevice interfaceはデバイスと通信して制御するための関数がつまったプラグインを提供する。どうやってデバイスを探してdevice interfaceを得てそれと通信するかを示す。

Device Matching for FireWire Devices

まず、Machポートを得る。
kern_return_t   result;
mach_port_t     masterPort;
result = IOMasterPort( MACH_PORT_NULL, &masterPort );
デバイス検索のためにはI/O Kit関数のIOServiceMatchingを使ってマッチング辞書を作る。
CFMutableDictionaryRef  matchingDictionary = IOServiceMatching
                                                ( "IOFireWireDevice" );
表にマッチング辞書に使えるFireWireのクラス名を示す。
IOFireWireSBP2Targetデバイスの中のSBP-2ターゲットのユニット
IOFireWireSBP2LUNSBP-2ターゲットのLUN
IOFireWireAVCUnitデバイスの中のAV/Cユニット
IOFireWireUnitデバイスの中のユニット
IOFireWireDeviceバス上のデバイス
IOFireWireLocalNodeMac本体
もしさらに詳細の検索する必要がないならIOServiceMatchingが作った辞書はその時点でI/O Registryにある特定のクラスのすべてを発見できる。

もしさらに検索を続けたいならデバイスを特定するpropertyを辞書に加えることができる。「In-Kernel FireWire Device Support」にあるようにIOFireWireファミリはそれぞれのデバイスやユニットを表現するpropertyをI/O Registry内に設定している。特定のデバイスやユニットの詳細検索にこれらのpropertyを使うことができる。表はそれぞれのオブジェクトで利用可能なpropertyを示す。
1220tbl01.png
マッチングにこういったpropertyを使うには、IOServiceMatchingで辞書を作ってCore Foundationの関数でpropertyのキーバリュー対を付け足す。次のリストには特定のUnit_Spec_ID と Unit_SW_Version valuesを持ったIOFireWireUnitオブジェクトにマッチする辞書を示す。
CFMutableDictionaryRef  matchingDictionary =
                                    IOServiceMatching("IOFireWireUnit" );
 
UInt32      value;
CFNumberRef cfValue;
 
value = myFireWireUnitSpecID;
cfValue = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value );
CFDictionaryAddValue( matchingDictionary, CFSTR( "Unit_Spec_ID" ), cfValue );
CFRelease( cfValue );
 
value = myFireWireUnitSwVersionID;
cfValue = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &value );
CFDictionaryAddValue( matchingDictionary, CFSTR( "Unit_SW_Version" ),
                        cfValue);
CFRelease( cfValue );

Finding FireWire Devices

探したいデバイスやデバイスタイプを記述した辞書を設定した後は、I/O Kit関数のIOServiceGetMatchingServicesにそれを渡す。この関数はI/O Registryの中で辞書にマッチするpropertyを持つオブジェクトを探して、そのイタレータを返す。
kern_return_t   result;
io_iterator_t   iterator;
 
result = IOServiceGetMatchingServices( masterPort, matchingDictionary,
    &iterator );
次に、イタレータをI/O Kit関数のIOIteratorNextに渡すと、マッチしたオブジェクトを順に返す。
io_object_t aDevice;
 
while ( (aDevice = IOIteratorNext( iterator ) ) != 0 ) {
    //get a device interface for the device
}
また、I/O Kit関数を使ってデバイスのホットプラグ、アンプラグの通知を受け取ることができる。そのためには通知ポートを設定してその実行ループイベントソースをプログラムの実行ループに追加する。そのあと、IOServiceGetmatchingSerices関数を呼ぶ替わりに、さっき作ったマッチング辞書をI/O Kit関数のIOServeiceAddMatchingNotificationに送る。その関数はマッチしたデバイスオブジェクトのイタレータを得て、また新しくマッチするデバイスのオブジェクトのために通知をインストールしなおす。myServiceMatchingCallbak関数はマッチしたデバイスをイタレートしてそれぞれにアクセスするためのものである。次のリストに通知の設定のしかたを示す。
//global variables
IONotificationPortRef   gNotifyPort;
CFRunLoopSourceRef      gNotifySource;
 
//local variables
io_iterator_t   iterator;
kern_return_t   result;
mach_port_t     masterPort;
CFMutableDictionaryRef  matchingDictionary;
 
//The acquisition of the Mach port and the creation of the matching
//dictionary are not shown here.
gNotifyPort = IONotificationPortCreate( masterPort );
gNotifySource = IONotificationPortGetRunLoopSource( gNotifyPort );
CFRunLoopAddSource( CFRunLoopGetCurrent(), gNotifySource,
    kCFRunLoopDefaultMode );
 
result = IOServiceAddMatchingNotification( gNotifyPort,
    kIOMatchedNotification, matchingDictionary,
    myServiceMatchingCallback, NULL, &iterator );
 
//IOServiceAddMatchingNotification consumes a reference to the
//matching dictionary so if you need to use the dictionary again
//after this call, you must first call CFRetain on it.
 
//Execute your callback function to iterate over the set of matching
//devices already present and to arm the notification for future devices.
myServiceMatchingCallback( NULL, iterator );

Getting FireWire Device Interfaces

イタレータからそれぞれのマッチしたデバイスへの参照を手に入れたあと、そのdevice interfaceを取得する。どのFireWire device interfaceライブラリを使うかに関係なく、まずIOCFPlugInInterface型のプラグインインターフェイスを得なければならない。それは次の例のようにIOIteratorNext関数からもらったデバイスへのio_object_t参照と定数kIOFireWireLibTypeIDを使って、
IOCFPlugInInterface**   cfPlugInInterface = 0;
IOReturn                result;
SInt32                  theScore;
 
result = IOCreatePlugInInterfaceForService( aDevice, kIOFireWireLibTypeID,
    kIOCFPlugInInterfaceID, &cfPlugInInterface, &theScore );
そのあと、IOCFPlugInInterfaceのQuerryInterface関数を使って、必要なdevice interfaceを得る。使いたいプライマリdevice interfaceの認識子を渡す。例えばkIOFireWireDeviceInterfaceIDやkIOFireWireSBP2LibLUNInterfaceIDのようなもの。
IOFireWireLibDeviceRef  fwDeviceInterface = 0;
 
(*cfPlugInInterface)->QueryInterface( cfPlugInInterface, CFUUIDGetUUIDBytes(
    kIOFireWireDeviceInterfaceID ), (void **) fwDeviceInterface );
(ところでドキュメントには上のようなリストになっているが、明らかな間違い。これは
(*cfPlugInInterface)->QueryInterface( cfPlugInInterface, CFUUIDGetUUIDBytes(
    kIOFireWireDeviceInterfaceID ), (void **) &fwDeviceInterface );
で、最後の引数はアドレスを渡さなければならない。pdfも間違ったまんま。トリビアルな間違いだけど、voidへのポインタでコンパイラの警告は出ないので実行するまで気がつかない。要注意)

利用可能なIOFireWireDeviceInterfaceには3つのバージョンがある。それぞれのバージョンは前のものに新しいサービスを付け加えている。ヘッダをチェックして走らせたいMacOS Xのバージョンに対応するIOFireWireDeviceInterfaceを確認する必要がある。MacOS XがサポートするバージョンよりあとのバージョンのIOFireWireDeviceInterfaceを取得しようとすると、QueryInterface関数呼び出しは失敗する。しかしOSがサポートするそれより古いバージョンなら取得できる。

また、IOFireWireUnitInterfaceとIOFireWireNubInterfaceのインスタンスを取得することもできる。これらはIOFireWireDeviceInterfaceとにたようなもので同じオブジェクトを参照している。それらはユニットやローカルノードをオープンする場合に記述性の高い名前を提供しているだけである。

ライブラリ中のアプリで使いたいプライマリdevice interfaceを得たとき、ライブラリが提供する他のinterfaceを取得するためにIOCreatePlugInForServiceとQueryInterface関数を使ってはならない。それぞれのライブラリには他のinterfaceを得るための独自の関数を用意している。

Getting Multiple FireWire Device Interfaces

device interfaceのopen関数を使ってデバイスやユニットをオープンしたとき、kernel内のデバイスやユニットを表すオブジェクトとの排他的な接続を得たことになる。open関数は呼び出したオブジェクトをオープンするだけでなく、スタックの下にあるオブジェクトも一緒にオープンすることになるので、それ以降は他のアプリはそのデバイスやユニットをオープンすることができなくなる。例えば、IOFireWireAVCLibUnitInterfaceのopen関数でAV/Cユニットをオープンしたら、自動的にIOFireWireUnitとIOFireWireDeviceオブジェクトもオープンしているということになる。

このように、もしIOFireWireSBP2LibとIOFireWireAVCLibをIOFireWireLibと一緒に使いたいなら、すでにオープンされているデバイスやユニットのオブジェクトをオープンしなければならない。これを許すためにIOFireWireファミリはデバイスやユニットのオブジェクトの特定の接続を参照するsession referenceの概念を使用する。

session referenceは排他的なopen関数をオーバーライドできるキーのようなものである。もしアプリがSBP-2やAV/Cユニットをdevice interfaceのopen関数でオープンしたら、GetSessionRef関数(IOFireWireAVCLibとIOFireWireSBP2Libの両方にある)を使って、IOFireWireSessionRefを取得することで、IOFireWireUnitやIOFireWireDeviceオブジェクトをオープンできる。

IOFireWireDeviceInterfaceのopenWithSssionRef関数にIOFireWireSessionRefを渡すと、kernel内のデバイスやユニットのオブジェクトをオープンできる。そうすれば、そのデバイスやユニットと通信する両方のinterfaceと関数を使うことができる。次のリストはIOFireWreAVCLibUnitInterfaceインスタンスを使ってAV/Cユニットをオープンして次にIOFireWireDeviceInterfaceのインスタンスをオープンするためにsession referenceを得ている。
IOFireWireSessionRef    session;
 
result = (*avcInterface)->open( avcInterface );
session = (*avcInterface)->getSessionRef( avcInterface );
result = (*fwInterface)->openWithSessionRef( fwInterface, session );
しかし、これらのdevice interfaceを使えるようになる前にデバイスを検索しなければならない。デバイスマッチングはI/OKit関数を使って特定のデバイスやユニットやデバイスタイプをI/O Registryの中で検索するプロセスである。

nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

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

トラックバック 0

献立01/06献立01/07 ブログトップ

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