ver. 0.9 by inADA
ここからは実際に動作するkextドライバを書くための準備からコーディング、動作検証などを説明します。
kextドライバの開発にはMac OS Xが走る環境の他にもいくつか用意するもの、あるいは用意した方が良いものがあります。
現在のMac OS Xは開発ツールをApp Store.appという専用ブラウザを使ってInternet経由でMac App Storeから配布されています。App Store.appは今回の開発ターゲットであるMac OS X 10.7.xに標準インストールされています。まず最初に、App Store.appを利用して開発ツールの基本となる開発環境Xcode 4.3.xをインストールしてください。Mac App Storeに関する詳細はAppleのサイトを参照してください。この文章を執筆している時点では以下のURLにありました。
Mac OS XはLinuxなどと同様にUSBやFireWireなどの外部ドライブからOSを起動できます。障害があった場合には外部ドライブのケーブルを抜くだけでシステムは安全に起動できます。場合によっては内蔵ドライブを取り外すのも一案です。
kextドライバは起動時のロードが基本のため、頻繁に再起動することになります。このため再起動の早いSSDが有利です。また、開発中の装置であれば抜き差しなども頻繁になり、ディスクドライブが読み書きしている最中に物理的な衝撃を与える可能性も高くなります。この意味でもSSDであれば安心です。
kextドライバにより復帰できないほどシステムがクラッシュする可能性も高くなります。このためTime Machineにより絶えずバックアップをお勧めします。Time Capsuleであれば、EthernetだけでなくWiFiでバックアップがとれるため、オシレータやアナライザなどの配線が混乱しがちな試作機での開発が安心です。
今回はMac OS X 10.7.x上の開発のため、Lion 復旧ディスクアシスタントが利用できます。USBメモリによるリカバリディスクにより、システム クラッシュとなった場合にすばやく復旧し開発を継続できます。
Appleの開発者向けサイトにはさまざまなサンプルコードがあり、デバイスドライバのサンプルコードもあります。しかし、この資料では文頭にもあるように手近なUSBマウスをターゲットにして実際に動作するMac OS Xのkextドライバを試作してみることにします。
マウスのkextドライバを書く最も簡単な方法はDarwinプロジェクトのソースコードを流用することです。DarwinプロジェクトはMac OS Xのカーネル部などのソースコードを公開するプロジェクトです。このマウスのコードは汎用に書かれていますので、ここでは専用のコードに変更します。専用にすることで、ターゲットのマウスだけを対象にさまざまな実験をし、Mac OS Xのkextドライバの動きを知ることができます。
Darwinのソースコードを入手するためにはライセンス契約に同意するなどの手続きが必要です。詳しくはAppleのOpen Sourceのサイトからたどって下さい。
Darwinプロジェクトで公開されているMac OS X 10.3.9に含まれるIOUSBFamilyのソースコードからAppleUSBMouse.cppとAppleUSBMouse.hを入手して下さい。この文章を執筆している時点では以下のURLにありました。
上記のURLで表示されるページの上部に[[plain text]と言うボタンがあり、テキストファイルが表示されますのでそれぞれのファイル名で保存してください。
なお、Mac OS X 10.4から上記のファイルがなくなりましたが、単独のドライバとして書くには都合が良いのでこのソースファイルを利用します。また、IOUSBFamilyフォルダにはDarwinのソースコード以外にもさまざまなサンプルと資料が入っています。最新のIOUSBFamilyを入手して、時間をかけて色々と調べてみることをお勧めします。
ここからは先に入手した開発環境のXcodeで新規にプロジェクトを作り、上記のソースファイルを使ってkextドライバを作ります。Xcodeの使い方は[Help]メニューなどを利用すると良いでしょう。なお、現在のMac OS Xのカーネルは64 bitになっており、kextドライバも64 bitとして生成します。
Fig 3. 新規プロジェクト
Xcodeの[File > New > Project…]を選択し、開いたウィンドウの左欄から[Mac OS X > System Plug-in]を選択し、主画面から[IOKit Driver]を選択し、右下の[Next]ボタンを押します。
Fig 4. 製品名など
次の画面で[Product Name:]を入れますが、ここでは仮に[mDriver]とします。[ Company Identifier]は会社や個人で取得したDomain Nameを元に入力します。私の[inADAinc.com]を例にするとDomain Nameを逆にし、その後に[.driver]を加えて、欄には[com.inADAinc.com.driver]と入力します。以上のように入力すると三行目の[Bundle Identifier]には[com.inADAinc.driver.mDriver]と表示されます。このBundle Identifierは、さまざまなメーカから提供されるデバイスドライバなどのソフトウェアを名前から特定するための命名方法です。
右下の[Next]ボタンを押してプロジェクトのフォルダを置く場所を決めます。ここでは仮にプロジェクトを置く場所をホームディレクトリにします。
Fig 5. LLVM設定
次の画面で黄色の三角が画面の数カ所に表示されます。左欄の[mDriver project > mDriver.xcodeproj]の下にある[Validate Project Settings Update to recommended settings]をクリックすると[Build Settings]と書かれた画面が表示され、コンパイラの設定を変更することを求められます。右下にある[Perform Changes]ボタンをクリックし、さらに確認画面で[Enable]ボタンをクリックします。
これで、プロジェクトファイルの他に汎用のC++ファイルとヘッダファイル、さらにInfoPlist.stringsなどが複数のディレクトリと共に作られます。
Darwinプロジェクトから入手したAppleUSBMouse.cppとAppleUSBMouse.hのコードをXcodeが自動生成したmDriver.cppとmDriver.hにコピーします。
mDriver.cppの以下の行を書き換えます。
修正前
#include "AppleUSBMouse.h"
修正後
#include "mDriver.h"
修正前
AppleUSBMouse::message( UInt32 type, IOService * provider, void * argument = 0 )
修正後
AppleUSBMouse::message( UInt32 type, IOService * provider, void * argument )
AppleUSBMouse::ChangeOutstandingIO()内の下記の行
修正前
UInt32 direction = (UInt32)param1;
修正後
UInt32 direction = (long)param1;
mDriver.cppとmDriver.hのAppleUSBMouseをcom_inADAinc_driver_mDriverClassにすべて検索置換します。このClass名は後のInfo.plistの設定でも使用します。
他に64 bitに変更した事によるDebug用のLog出力に関する問題がいくつか報告されます。Xcodeの指示に従って適時書き換えてください。場合によっては削除しても動作には影響しません。
mDriver.cppとmDriver.hには、汎用にするためのコードや、個々の機器に対応するためのコードなど冗長なコードが多く含まれています。しかし、今回はデバイスドライバの動きを知ることが目的なので冗長部分を残したままにします。
以上で、ソースコードの変更は終了です。ここでXcodeの[Product]メニューから[Build]を選択して、エラーなどが表示されないことを確認してください。