ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
デバイスドライバの記述 Oracle Solaris 11.1 Information Library (日本語) |
パート I Oracle Solaris プラットフォーム用デバイスドライバの設計
2. Oracle Solaris カーネルとデバイスツリー
22. ドライバのコンパイル、ロード、パッケージ化、およびテスト
23. デバイスドライバのデバッグ、テスト、およびチューニング
デバイス属性情報は、プロパティーと呼ばれる名前-値ペアの表記で表すことができます。
たとえば、デバイスレジスタとオンボードメモリーは reg プロパティーで表すことができます。reg プロパティーは、デバイスハードウェアレジスタを記述するソフトウェアの抽象化です。reg プロパティーの値により、デバイスレジスタのアドレス位置とサイズがエンコードされます。ドライバは、reg プロパティーを使用してデバイスレジスタにアクセスします。
別の例として interrupt プロパティーがあります。interrupt プロパティーは、デバイス割り込みを表します。interrupt プロパティーの値により、デバイス割り込み PIN がエンコードされます。
プロパティーには次の 5 つの型の値を割り当てることができます。
バイト配列 – 任意の長さの一連のバイト
整数プロパティー – 整数値
整数配列プロパティー – 整数の配列
文字列プロパティー – null で終わる文字列
文字列配列プロパティー – null で終わる文字列のリスト
値を持たないプロパティーは、boolean プロパティーとみなされます。boolean プロパティーが存在する場合は真 (true) です。boolean プロパティーが存在しない場合は偽 (false) です。
厳密に言えば、DDI/DKI ソフトウェアのプロパティー名には制限がありません。ただし、推奨される使い方がいくつかあります。IEEE 1275-1994「Standard for Boot Firmware」では、プロパティーは次のように定義されています。
プロパティーとは、1 から 31 文字までのプリント可能文字で構成される、人間が読めるテキスト文字列のことです。プロパティー名には、大文字や「/」、「\」、「:」、「[」、「]」、「@」の文字を含めることはできません。「+」文字で始まるプロパティー名は、将来のバージョンの IEEE 1275-1994 用に予約されています。
通常、下線はプロパティー名に使用しません。代わりにハイフン (-) を使用します。通常、疑問符 (?) で終わるプロパティー名には、文字列の値 (一般には TRUE または FALSE) を指定します (例: auto-boot?)。
ドライバ構成ファイルへのプロパティーの追加については、driver.conf(4) のマニュアルページを参照してください。pm(9P) と pm-components(9P) のマニュアルページには、電源管理におけるプロパティーの使用方法が記載されています。デバイスドライバのマニュアルページにプロパティーがどのように文書化されているかの例として、sd(7D) のマニュアルページをお読みください。
ドライバのプロパティーを作成したり、既存のプロパティーを更新したりするには、適切なプロパティー型を持つ DDI ドライバ更新インタフェース (ddi_prop_update_int(9F) や ddi_prop_update_string(9F) など) の 1 つを使用します。使用できるプロパティーインタフェースの一覧については、表 4-1 を参照してください。これらのインタフェースは通常、ドライバの attach(9E) エントリポイントから呼び出されます。次の例では、ddi_prop_update_string() は、needs-suspend-resume という値を使って pm-hardware-state という文字列プロパティーを作成します。
/* The following code is to tell cpr that this device * needs to be suspended and resumed. */ (void) ddi_prop_update_string(device, dip, "pm-hardware-state", "needs-suspend-resume");
ほとんどの場合、プロパティーの更新には ddi_prop_update() ルーチンを使用すれば十分です。ただし、頻繁に値が変わるプロパティーの場合は更新によるオーバーヘッドが原因で、パフォーマンスに関する問題が発生することがあります。ddi_prop_update() の使用を避けるためにプロパティー値のローカルインスタンスを使用する方法については、「prop_op() エントリポイント」を参照してください。
ドライバは、その親にプロパティーを要求できます。そしてその親は、さらにその親に要求できます。ドライバは、要求をその親よりも上位に対して行えるかどうかを制御できます。
たとえば、次の例の esp ドライバは、ターゲットごとに targetx-sync-speed という整数プロパティーを保持します。targetx-sync-speed 内の x はターゲット番号を表します。prtconf(1M) コマンドは、ドライバのプロパティーを冗長モードで表示します。次の例は、esp ドライバの部分的なリストを示しています。
% prtconf -v ... esp, instance #0 Driver software properties: name <target2-sync-speed> length <4> value <0x00000fa0>. ...
表 4-1 プロパティーインタフェースの使い方
|
int プロパティーインタフェースを使用するときは、できるだけ ddi_prop_update_int64(9F) などの 32 ビットバージョンではなく、ddi_prop_update_int(9F) などの 64 ビットバージョンを使用してください。
Oracle Solaris OS が稼働するシステムをアップグレードすると、新しいバージョンのドライバがインストールされる可能性があります。そのアップグレードプロセスの間、システム上の driver.conf ファイルも更新されます。driver.conf ファイルのカスタマイズは、ベンダーとシステム管理者の両方によって行われます。システムのアップグレード時には、システムの以前の構成が引き続き、新しいドライバ、ベンダーの driver.conf ファイル、および管理者の driver.conf ファイルとともに動作するようにしてください。
Oracle Solaris 11 リリースでは、ベンダー提供のドライバデータを含む driver.conf ファイルを別途提供するオプションがドライバの開発者に用意されています。新しい driver.conf ファイルは /etc/driver/drv ディレクトリに格納されます。これによりシステムは、このファイルに対して行われた管理変更をすべて保持できます。ドライバが両方の構成ファイル内で見つかった場合、システムはそれらのファイルをマージし、すべてのプロパティーを含むファイルを提供します。ベンダーの driver.conf ファイルの形式は、管理者のドライバ構成ファイルと同じです。
ベンダー構成データと管理構成データは、新しいインタフェース経由でドライバから明示的に使用できるようになりました。このため、ドライバ開発者は、すべてのマージロジックのエンコードを、クラスアクションスクリプト内やインストール前およびインストール後スクリプト内ではなく、ドライバ内で直接行えます。管理ファイルに対して行われたカスタマイズは保持されるため、ドライバ内で新しい値と古い値の関係について判定を行うことができます。
ドライバで前述のモデルが正しく機能するようにするために、ドライバ開発者は次を考慮すべきです。
統制のとれた一連の構成可能オプションを使用できるように、ドライバを設計します。
ドライバのドキュメントやマニュアルページ内でドライバのオプションやモデルについて完全に記述します。
管理者の設定が無効になるか置き換えられるような方法でドライバの構成オプションを変更する場合、そのドライバで必ず以前の管理設定が尊重されるようにすべきです。以前の構成を検索する際に、ドライバは、ddi_prop_lookup(9F) インタフェース (プロパティータイプを DDI_PROP_VENDOR と DDI_PROP_ADMIN のいずれかに設定) を使用できます。
たとえば、あるドライバで秒単位のタイムアウト構成がサポートされていたが、そのドライバの新しいバージョンでは、ミリ秒単位のより細かい粒度のタイムアウトがサポートされるようになったとします。その新しいバージョンのプロパティーの名前は、以前のプロパティーと区別できるようなものにすべきです。このときドライバは、管理リスト上で以前のプロパティーを検索し、そのプロパティーが見つかった場合、その値を引き続き尊重すべきです。次のドライバコードは、このタイムアウトの例を示したものです。
例 4-1 ドライバはローカルで構成されたタイムアウト値をチェックする
* Has the timeout been locally configured using the + * prior option of timeout in units of seconds? + */ + if (ddi_prop_lookup_int(DDI_DEV_T_ANY, dip, + DDI_PROP_ADMIN, "timeout",&ivalues,&n) == + DDI_PROP_SUCCESS) { + if (n != 1) { + ddi_prop_free(ivalues); + return (EINVAL); + } + /* yes - convert our working timeout accordingly */ + dip->ms_timeout = 1000 * ivalues[0]; + /* record the new parameter setting for confirmation */ + (void) ddi_prop_update_int(DDI_DEV_T_NONE, + dip, "ms-timeout", dip->ms_timeout); + ddi_prop_free(ivalues); + }
prtconf(1M) コマンドではドライバのプロパティーが表示されますが、新しい -u オプションを使うと、元のプロパティー値と変更後のプロパティー値を表示できます。
prop_op(9E) エントリポイントは通常、デバイスプロパティーまたはドライバプロパティーの値をシステムに報告するために必要です。ドライバが専用のプロパティーを作成または管理する必要がない場合は、ddi_prop_op(9F) 関数をこのエントリポイントに使用できます。
ddi_prop_op() がデバイスドライバの cb_ops(9S) 構造体で定義されている場合は、ddi_prop_op(9F) をそのドライバの prop_op(9E) エントリポイントとして使用できます。ddi_prop_op() を使用すると、リーフデバイスでプロパティー値を検索して、それをデバイスのプロパティーリストから取得できます。
頻繁に値が変わるプロパティーをドライバで保持する必要がある場合は、ddi_prop_op() を呼び出すのではなく、cb_ops 構造体の中にドライバ固有の prop_op() ルーチンを定義します。この手法により、ddi_prop_update() を繰り返し使用するという非効率性を解消できます。ドライバは、そのソフト状態構造体の中またはドライバ変数でプロパティー値のコピーを保持します。
prop_op(9E) エントリポイントは、特定のドライバプロパティーやデバイスプロパティーの値をシステムに報告します。多くの場合、ddi_prop_op(9F) ルーチンは、cb_ops(9S) 構造体でドライバの prop_op() エントリポイントとして使用できます。ddi_prop_op() は、必要なすべての処理を実行します。デバイスプロパティーリクエストの処理時に特別な処理を必要としないドライバには、ddi_prop_op() で十分です。
ただし、ドライバが prop_op() エントリポイントを提供することが必要な場合があります。たとえば、頻繁に値が変わるプロパティーをドライバで保持する場合、変更のたびに ddi_prop_update(9F) を使用してプロパティーを更新することは効率的ではありません。代わりに、ドライバはインスタンスのソフト状態によってプロパティーのシャドウコピーを保持します。ドライバは、プロパティーの値が変わると、ddi_prop_update() ルーチンを一切使わずにシャドウコピーを更新します。prop_op() エントリポイントは、ddi_prop_op() にリクエストを渡してプロパティーリクエストを処理する前に、このプロパティーのリクエストを遮断し、いずれかの ddi_prop_update() ルーチンを使用してプロパティーの値を更新する必要があります。
次の例では、prop_op() は temperature プロパティーの要求を遮断しています。ドライバは、プロパティーが変わるたびに状態構造体で変数を更新します。ただし、プロパティーが更新されるのは、要求が出されたときだけです。その際、ドライバは ddi_prop_op() を使用してプロパティーリクエストを処理します。プロパティー要求がデバイスに固有のものでない場合、ドライバはその要求を遮断しません。このような状況は、dev パラメータの値が DDI_DEV_T_ANY (ワイルドカードのデバイス番号) である場合に示されます。
例 4-2 prop_op() ルーチン
static int xx_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int flags, char *name, caddr_t valuep, int *lengthp) { minor_t instance; struct xxstate *xsp; if (dev != DDI_DEV_T_ANY) { return (ddi_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp)); } instance = getminor(dev); xsp = ddi_get_soft_state(statep, instance); if (xsp == NULL) return (DDI_PROP_NOTFOUND); if (strcmp(name, "temperature") == 0) { ddi_prop_update_int(dev, dip, name, temperature); } /* other cases */ }