2010年10月10日日曜日

ハードウェアをアクセスするサンプルコード3.2

dealWithDevice()
IOReturn dealWithDevice(io_service_t usbDeviceRef)
{
  変数宣言
  err = IOCreatePlugInInterfaceForService(..., ..., ..., ..., ...);
  エラー処理
  err = (*iodev)->QueryInterface(..., CFUUIDGetUUIDBytes(...), ...);
  IODestroyPlugInInterface(...);
  エラー処理
  err = (*dev)->GetIOUSBLibVersion(..., ..., ...);
  エラー処理
  出力
  return err;
}

dealWithDevice()ではIOCreatePlugInInterfaceForService()でプラグインを生成し、さらにQueryInterface()でDevice Interfaceを生成します。このDevice Interfaceを経由して装置とやり取りします。USBの場合はIOUSBLib.hにある関数を利用して、USBのInterfaceを開いて、目的の装置を確認して、必要な作業を行います。今回の場合はGetIOUSBLibVersion()を呼び出してバージョンを調べているだけです。

topに戻る

ハードウェアをアクセスするサンプルコード3.1

main()
int main (void)
{
  変数宣言
  err = IOMasterPort(..., ...);
  エラー処理
  matchingDictionary = IOServiceMatching(...);
  エラー処理
  err = IOServiceGetMatchingServices(..., ..., ...);
  matchingDictionary = 0;
  if ((usbDeviceRef = IOIteratorNext(...)))
  {
    err = dealWithDevice(usbDeviceRef);
    エラー処理
  } else {
    エラー処理
  }
  使用したオブジェクトの解放
}

ここではIOMasterPortでポートを開き、ポートにアクセスするためのオブジェクトとして先ほどのmasterPortを利用します。確実にメモリ領域を取得するために、この命令を最初に入れます。


次に、以下の一文でIO RegistryデータベースにUSBに関して問い合わせるためのオブジェクトを作ります。

matchingDictionary = IOServiceMatching(kIOUSBDeviceClassName);

AppleではこのオブジェクトをDictionaryと読んでいますが、問い合わせたい内容をこのDictionaryに追加して目的の装置やソフトウェアを見つけ出します。

問い合わせの内容を追加する作業は意外と面倒です。USBを例にすると、USBには装置を特定するために企業名を指すVender IDと装置を指すProduct IDがあります。それぞれのIDをCFNumberCreate()と言う関数でCore Foundationのオブジェクトに変換し、CFDictionaryAddValue()でDictionaryオブジェクトに追加し、不要になったCore FoundationのオブジェクトをCFRelease()で解放し、0を代入してカーネルが必要に応じてパージしても良いようにします。

このサンプルコードでは、USB全体をターゲットにしますので、最初の IOServiceMatching()だけでDictionaryオブジェクトの作成が終わり、すぐにIOServiceGetMatchingServices()を読んでUSBに関連するデータを取得します。

IOServiceGetMatchingServices()では三つ目の引数として&iteratorというオブジェクトに入れています。USBやPCI拡張カードでは同じ装置が何台も接続されているかもしれません。&iteratorオブジェクトは複数の装置がつながっている場合を想定したオブジェクトで、装置に関するデータをif文で一つずつ取り出して処理します。この処理をするのがここで書かれている二つ目の関数であるdealWithDevice()です。

topに戻る

ハードウェアをアクセスするサンプルコード3rd

サンプルコードの説明

main.cファイルに書かれている内容を紹介します。サンプルコードと見比べながらご覧ください。

#include 
 省略
#include 

#ifndef __DebugSettin__
 省略
#endif // __DebugSettin__

mach_port_t  masterPort = 0;

IOReturn dealWithDevice(io_service_t usbDeviceRef)
{
 省略
}

int main (void)
{
 省略
}

まず、#includeで宣言されているファイルはポートを開いたり、IOKitとやり取りするためのヘッダファイルです。CoreFoundationは基本的な文字列操作から始まり、Mac OS Xのさまざまな基礎データを扱うライブラリです。

次の#ifndef...#endifはデバッグ用のコンソールやシステム ログへの出力を切り替えるマクロです。

グローバル変数のmasterPortはポートを参照するオブジェクトです。

関数はdealWithDevice()main()の二つです。main()で作業の対象となるオブジェクト(USBのドライバ)を探し出し、dealWithDevice()で作業(USB バージョンの取得)をしています。今回はUSBのドライバを見つけ出してやり取りしていますが、通常はUSB装置やPCI拡張カードなどを探し出して、見つけた装置とやり取りします。

戻る

ハードウェアをアクセスするサンプルコード2nd

コンパイル手順
コンパイルにはXcodeを使います。古いものでも動作しますが、今回はXcode 3.2.2を使用しました。理由はたまたま手元にあるものがこのバージョンであったと言うだけです。zipファイルにはXcodeのプロジェクト ファイルも入っています。プロジェクト ファイルから作る場合のコンパイルの手順は以下の通りです。
  1. Xcodeを起動
  2. [ファイル]メニューから[新規プロジェクト...]を選択
  3. 左蘭から[Mac OS X]>[Application]を選択
  4. 右蘭から[Command Line Tool]を選択
  5. Typeは”C"のまま、[選択]ボタンを押下
  6. プロジェクトの保存場所、プロジェクト名を決定
  7. メインのウィンドウ右蘭から"main.c"を選択
  8. main.cファイルをダブルクリック
  9. main.cの内容をサンプルコードに入れ替え
  10. メイン ウィンドウ左蘭からプロジェクト名を選択
  11. プロジェクト名を右クリック
  12. [追加]>[既存のフレームワーク...]を選択
  13. リストから以下の二つを選択して追加ボタンを押下
    * CoreFoundation.framework
    * IOKit.framework
  14. [実行]メニューから[コンソール]を選択
  15. [ビルドと実行ボタン]を押下
以上で、コンソールの画面にUSBLibとUSBFamilyのバージョンが表示されます。
    USBLib    Version is 3.90
        stage is 80 non-released version is 00
    USBFamily Version is 4.02
        stage is 80 non-released version is 00

戻る

ハードウェアをアクセスするサンプルコード1st

Mac OS X ハードウェア アクセスの概要

Mac OS XではIO Registryと呼ばれるデータベースにハードウェアに関する情報やDevice Driverなどを保管しています。Windowsのデバイス マネージャに近いものと考えても良いでしょう。このIO RegistryをブラウズするツールとしてIORegistryExplorer.appというソフトウェアがあります。Mac OS Xに標準付属の開発環境Xcodeをインストールすると以下の場所にありますので、試しにブラウズしてみてください。


/Developer/Applications/Utilities/IORegistryExplorer.app

Mac OS XではDarwinカーネル内にあるI/O Kitがハードウェアに関連するリソースを管理しています。ハードウェアをアクセスするにはこのI/O Kitを通してやり取りしますが、Darwinカーネルのメモリ空間(カーネル空間)とアプリケーションのメモリ空間(ユーザ空間)は分離されて、相互のやり取りは限定されています。ユーザ空間にあるプログラムからカーネル空間のI/O Kitとやり取りするために、通常はDevice Interfaceを経由してやり取りします。Device Interfaceはユーザ空間側にあるライブラリまたはプラグインです。

Mac OS Xのユーザ空間側にあるプログラムからハードウェアにアクセスする一般的な手順は、まずIO Registryのデータベースに問い合わせてハードウェアを参照するオブジェクトを入手します。次に入手したオブジェクトを元にDevice Interfaceのプラグインを開いて、そのプラグインとI/O Kitを経由して目的の装置とやり取りをします。やり取りが終わるとオブジェクトなどを解放してプログラムを終了させます。

サンプルコードはTerminal用のアプリケーションで、USBを管理するソフトウェアであるUSBLibUSBFamilyのバージョンを表示します。この時に上記のIO RegistryデータベースにUSBの情報を問い合わせて、Device Interfaceを経由してそのバージョンを入手し表示しています。

戻る

ハードウェアをアクセスするサンプルコードtop

2年前に公開するつもりでコードの切れ端をかき集めて、そのままになっていたサンプルコードを見つけました(笑)

USBを例にして、Mac OS Xでハードウェアをアクセスする時の基本を紹介したコードです。知っている人には何を今さらというたわいないものですが、始めてMac OS Xでハードウェアをアクセスするプログラムを書く人にはヒントになると思います。

詳細はAppleの資料Accessing Hardware From ApplicationsFinding and Accessing Devicesを参照してください。昔と比べれば大幅に改善されて分かりやすい解説になっています。

サンプルコードはこちらからダウンロードしてください

目次