ver. 0.9 by inADA
お手持ちのUSBマウスで動作するMac OS X kextデバイスドライバの書き方を紹介します。
Appleは当初からkextドライバを書くことを推薦していません。また、多くの外付け装置がUSBを経由するようになった現在では、独自にkextドライバを書く必要性は低くなっています。ほとんどの場合にはターゲットの装置を他のアプリケーションが横取りしないようにするためのcode-less kextドライバを書き、アプリケーションから制御するだけで十分でしょう。しかし、カーネル内で実際に動作するkextドライバーのソースコードを元に実験してみることは、良い学習になると思います。
この資料ではMac OS Xのカーネル部分の概要を説明し、USBマウスのkextドライバを作る方法を紹介します。
この資料は2003年にPDFとして公開したものを元に、Mac OS X 10.7.xの64bit環境で動作するkextドライバをXcode 4.3で生成できるように改定し、さらに書式をHTMLファイルにしました。iBooks Authorで編集しiBooksで読めるようにしたものも用意しています。
Mac OS XではMachカーネルに高速性を目的に改造を加えたカーネルを採用しています。この章ではその概要を紹介します。
Fig 1. カーネルとIOKit
Mac OS XではMachカーネルに高速性を目的に改造を加えたカーネルを採用しています。この章ではその概要を紹介します。
Mac OS Xではカーネル空間とユーザ空間(アプリケーションなどが利用する)が分けられ、相互のやり取りはすべて予め決めた関数や手続きのみで処理されます。
I/O Kitへの拡張機能として、ハードウェアとのやり取りを行うソフトウェア ドライバをkext(Kernel EXTention)ドライバと呼びます。
また、Mac OS Xではユーザ インタフェースを持たないアプリケーションで、ハードウェアを扱うソフトウェアをドライバと呼ぶ場合もあります。この資料ではこのようなソフトウェアをデーモンと呼ぶことにします。
Mac OS X 10.5からカーネルが64bit化しました。デーモンはユーザ空間で起動しますので、64bitカーネルでも引き続き利用できます。しかし、kextドライバはカーネル空間で動作しますので、カーネルと同じ64bitに対応しなくてはならなくなりました。多くのkextドライバはソース コードを変更することなしに、ビルドに必要な64bitの設定に変更して再ビルドするだけで64bitカーネルでも動作します。
実際にここで紹介するUSB Mouseドライバも元にしたソースコードが持っていた問題をわずかに変更し、設定を変更するだけで動作しました。
32bitと64bitそれぞれのkextドライバを別々に用意し、インストーラで選択することは簡単ですが、一つのkextファイルで32bitと64bitの二つのMac OS Xに対応する方法も提供されています。さらにPowerPCとのバイナリ互換を提供するRosettaにも対応する方法も提供されています。興味のある方は以下の資料を参照してください。
アプリケーションやデーモンがカーネル空間のkextドライバと通信する場合にはIOKit.framework内のIOKitLib.hファイルで定義された関数を利用します。逆にkextドライバからはKernel.frameworkのIOKit内にあるIOUserClient.h関数を利用してユーザ空間と通信します。関数は32bit版と64bit版があります。64bit版はMac OS X 10.5以降で利用できます。
以下の資料にその概要が書かれていますが、 詳細はそれぞれのヘッダ ファイルを参照ください。
SimpleUserClient: User Client Info.txt
I/O RegistryはI/O Kitがハードウェアを管理するためのデータベースで、カーネル空間からもユーザ空間からも読み書きできます。
kextドライバからI/O Registryにデータを登録し、ユーザ空間にあるアプリケーションなどからその内容を読む、あるいはその逆にアプリケーションなどからI/O Registryにデータを登録し、kextドライバから読むことで通信できます。
簡単にI/O Registryに登録されたデータをブラウズすするにはIORegistryExplorer.appというブラウザがあります。周辺装置などが接続されるとこのI/O Registryデータベースが更新され、その内容を元にkextドライバやデーモンなどが呼び出されます。また、前述のようにI/O Registryはカーネル空間からもユーザ空間からも扱うことができるため、カーネルとアプリケーション間の通信に使用することも可能です。
I/O Kitに関する情報は以下のURLから調べ始めると良いでしょう。
Introduction to I/O Kit Fundamentals
Mac OS Xのkextドライバはアプリケーションと同様にバンドルになっています。バンドルは特定のファイルとディレクトリ構成を持ったディレクトリですが、Mac OS Xのファイル ブラウザであるFinderからは、一つのファイルとして扱われます。Finderでバンドルの中を見るにはマウスの副クリックで表示されたコンテクストメニューから[パッケージの内容を表示]を選択します。
Fig 1. カーネルとIOKit
バンドルの中では、二つのファイルが重要です。一つはOSがデバイス ドライバを認識し管理するためのInfo.plistファイル、もう一つはターゲットとなる装置やアプリケーションとデータをやり取りするためのドライバ本体(Fig. 2の例ではmDriver)です。
前者のInfo.plistファイルによって、OSからデバイス ドライバとして認識され、周辺機器が接続されたときなどに呼び出してもらうための情報をOSに提供します。Info.plistファイルの書式はXMLで、情報の中身はkextドライバに共通のタグの他に、USBやFireWire、PCIなど装置が使用するバス形式や、提供するサービスなどによってタグがあります。
後者のドライバ本体は「Darwinカーネル: kextとの通信」で解説した関数群などを利用して起動時や外部装置の接続時などに呼び出され初期化などを行います。各関数は適時に、呼び出されてハードウェア、カーネル空間やアプリケーション空間にあるソフトウェアと通信を行います。これらの関数はUSBやPCIなどのバス規格や StorageやHID (Human Interface Device)などの利用形態などに応じてClassごとにまとめられFamilyと呼ばれます。Familyには、IOUSBFamilyやIOPCIFamily、OHIDFamily、IOStorageFamilyなどがあります。
なお、Fig. 2 Bundleの例には各国の言語に合わせるためのInfoPlist.stringsファイルが含まれていますが、空のファイルです。