JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
デバイスドライバの記述     Oracle Solaris 11.1 Information Library (日本語)
このドキュメントの評価
search filter icon
search icon

ドキュメントの情報

はじめに

パート I Oracle Solaris プラットフォーム用デバイスドライバの設計

1.  Oracle Solaris デバイスドライバの概要

2.  Oracle Solaris カーネルとデバイスツリー

3.  マルチスレッド

4.  プロパティー

5.  イベントの管理とタスクのキュー

イベントの管理

イベントの概要

ddi_log_sysevent() を使用したイベントのロギング

ddi_log_sysevent() の構文

イベントロギング用のサンプルコード

イベント属性の定義

タスクのキュー

タスクキューの概要

タスクキューのインタフェース

タスクキューの監視

タスクキューのカーネル統計カウンタ

タスクキューの DTrace SDT プローブ

6.  ドライバの自動構成

7.  デバイスアクセス: プログラム式入出力

8.  割り込みハンドラ

9.  ダイレクトメモリーアクセス (DMA)

10.  デバイスメモリーおよびカーネルメモリーのマッピング

11.  デバイスコンテキスト管理

12.  電源管理

13.  Oracle Solaris ドライバの強化

14.  階層化ドライバインタフェース (LDI)

パート II 特定の種類のデバイスドライバの設計

15.  文字デバイスのドライバ

16.  ブロックデバイスのドライバ

17.  SCSI ターゲットドライバ

18.  SCSI ホストバスアダプタドライバ

19.  ネットワークデバイスのドライバ

20.  USB ドライバ

21.  SR-IOV ドライバ

パート III デバイスドライバの構築

22.  ドライバのコンパイル、ロード、パッケージ化、およびテスト

23.  デバイスドライバのデバッグ、テスト、およびチューニング

24.  推奨されるコーティング方法

パート IV 付録

A.  ハードウェアの概要

B.  Oracle Solaris DDI/DKI サービスのサマリー

C.  64 ビットデバイスドライバの準備

D.  コンソールフレームバッファードライバ

E.  pci.conf ファイル

索引

ドキュメントの品質向上のためのご意見をください
簡潔すぎた
読みづらかった、または難し過ぎた
重要な情報が欠けていた
内容が間違っていた
翻訳版が必要
その他
Your rating has been updated
貴重なご意見を有り難うございました!

あなたの貴重なご意見はより良いドキュメント作成の手助けとなります 内容の品質向上と追加コメントのためのアンケートに参加されますか?

イベントの管理

システムはしばしば、ユーザーアクションやシステム要求など、状態の変化に応答する必要があります。たとえばデバイスは、あるコンポーネントが過熱し始めたときに警告を発したり、DVDがドライブに挿入されたときにムービープレーヤーを起動したりする可能性があります。デバイスドライバは、イベントと呼ばれる特殊なメッセージを使用することで、状態の変化が発生したことをシステムに通知します。

イベントの概要

イベントとは、状態の変化が発生したことを示すためにデバイスドライバから対象のエンティティーに送信されるメッセージのことです。Oracle Solaris OS ではイベントはユーザー定義の名前-値ペア構造体として実装されており、この構造体は nvlist* 関数を使用して管理されます。nvlist_alloc(9F) のマニュアルページを参照してください。イベントはベンダー、クラス、およびサブクラスに基づいて編成されます。たとえば、環境の状態を監視するためのクラスを定義します。環境用のクラスには、温度、ファンのステータス、および電力の変化を示すためのサブクラスが存在する場合があります。

状態の変化が発生すると、デバイスはドライバに通知します。次に、ドライバは ddi_log_sysevent(9F) 関数を使用して、sysevent という名前のキュー内にこのイベントをロギングします。sysevent キューは、syseventd デーモンまたは syseventconfd のいずれかのデーモン経由でユーザーレベルにイベントを処理対象として渡します。これらのデーモンは、指定されたイベントの通知を受け取るように登録しているすべてのアプリケーションに、通知を送信します。

ユーザーレベルアプリケーションの設計者にとって、イベントを処理するには次の 2 つの方法があります。

このプロセスを示したのが次の図です。

図 5-1 イベントの plumb

image:図は、イベントがユーザーレベルアプリケーションへの通知用として sysevent キューにロギングされる様子を示したものです。

ddi_log_sysevent() を使用したイベントのロギング

デバイスドライバは ddi_log_sysevent(9F) インタフェースを使用することで、イベントの生成とそのイベントのシステムへのロギングを行います。

ddi_log_sysevent() の構文

ddi_log_sysevent() で使用される構文は、次のとおりです。

int ddi_log_sysevent(dev_info_t *dip, char *vendor, char *class, 
    char *subclass, nvlist_t *attr-list, sysevent_id_t *eidp, int sleep-flag);

各表記の意味は次のとおりです。

dip

このドライバの dev_info ノードへのポインタ。

vendor

ドライバのベンダーを定義する文字列へのポインタ。他社製ドライバでは、その会社の銘柄記号や、銘柄記号と同様の永続性のある識別子を使用します。Oracle が提供するドライバでは DDI_VENDOR_SUNW が使用されます。

class

イベントのクラスを定義する文字列へのポインタ。class はドライバに固有の値です。クラスの例には、あるデバイスに影響を与える一連の環境状態を表す文字列があります。この値は、イベントのコンシューマが認識できるものである必要があります。

subclass

class 引数のサブセットを表すドライバ固有の文字列。たとえば、環境の状態を表すクラス内に、デバイスの温度を表すイベントサブクラスを追加できます。この値は、イベントのコンシューマが理解できるものである必要があります。

attr-list

このイベントに関連する名前-値属性のリストを含む nvlist_t 構造体へのポインタ。名前-値属性はドライバごとに定義される値であり、デバイスの特定の属性や状態を表すことができます。

たとえば、CD-ROM と DVD の両方を読み取るデバイスを考えます。このデバイスには、名前が disc_type で値が cd_romdvd のいずれかに等しいような属性を割り当てることができます。

イベントのコンシューマは classsubclass の場合と同様に、名前-値ペアを解釈できる必要があります。

名前-値ペアや nvlist_t 構造体の詳細については、「イベント属性の定義」を参照するほか、nvlist_alloc(9F) のマニュアルページも参照してください。

属性を持たないイベントでは、この引数を NULL に設定するべきです。

eidp

sysevent_id_t 構造体のアドレス。sysevent_id_t 構造体を使用すると、イベントを一意に識別できます。ddi_log_sysevent(9F) から返されるこの構造体には、システムによって提供されるイベントシーケンス番号とタイムスタンプが含まれます。sysevent_id_t 構造体の詳細については、ddi_log_sysevent(9F) のマニュアルページを参照してください。

sleep-flag

リソースが使用可能でない場合に呼び出し元がどのように対処するのかを示すフラグ。sleep-flagDDI_SLEEP に設定されると、リソースが使用可能になるまでドライバがブロックされます。DDI_NOSLEEP の状態では割り当てがスリープしないため、処理の成功が保証されません。DDI_ENOMEM が返された場合、ドライバは処理をあとで再試行する必要があります。

DDI_SLEEP の状態でも、システムビジーや syseventd デーモンの不応答、割り込みコンテキストでのイベントのロギング試行など、その他のエラーがこのインタフェースから返される可能性があります。

イベントロギング用のサンプルコード

デバイスドライバは、イベントのロギングを行うために次のタスクを実行します。

次の例は、ddi_log_sysevent() の使用方法を示しています。

例 5-1 ddi_log_sysevent() の呼び出し

char *vendor_name = "DDI_VENDOR_JGJG"
char *my_class = "JGJG_event";
char *my_subclass = "JGJG_alert";
nvlist_t *nvl;
/* ... */
nvlist_alloc(&nvl, nvflag, kmflag);
/* ... */
(void) nvlist_add_byte_array(nvl, propname, (uchar_t *)propval, proplen + 1); 
/* ... */
if (ddi_log_sysevent(dip, vendor_name, my_class, 
    my_subclass, nvl, NULL, DDI_SLEEP)!= DDI_SUCCESS)
    cmn_err(CE_WARN, "error logging system event"); 
nvlist_free(nvl);

イベント属性の定義

イベント属性は名前-値ペアのリストとして定義します。Oracle Solaris DDI には、情報を名前-値ペアとして格納するためのルーチンや構造体が用意されています。名前-値ペアは、ドライバからは不透明な nvlist_t 構造体に保持されます。名前-値ペアの値は、ブール、int、バイト、文字列、nvlist のいずれか、またはこれらのデータ型の配列になります。int は、16 ビット、32 ビット、64 ビットのいずれかとして定義できるほか、符号付き、符号なしのいずれかにすることができます。

名前-値ペアのリストを作成する手順は、次のとおりです。

  1. nvlist_alloc(9F) を使用して nvlist_t 構造体を作成します。

    nvlist_alloc () インタフェースが取る引数は次の 3 つです。

    • nvlpnvlist_t 構造体へのポインタへのポインタ

    • nvflag – ペアの名前の一意性を示すフラグ。このフラグを NV_UNIQUE_NAME_TYPE に設定すると、新しいペアの名前と型に一致する既存のペアがすべて、リストから削除されます。このフラグを NV_UNIQUE_NAME に設定すると、型が何であっても、同じ名前を持つ既存のペアがすべて削除されます。NV_UNIQUE_NAME_TYPE を指定すると、型が異なるかぎり、名前が同じペアを複数個リストに含めることが可能となります。一方、NV_UNIQUE_NAME の場合、リストに含めることのできるペア名のインスタンスは 1 つのみになります。このフラグを設定しなかった場合、一意性のチェックは行われず、リストのコンシューマが重複への対処を担当することになります。

    • kmflag – カーネルメモリーの割り当てポリシーを示すフラグ。この引数を KM_SLEEP に設定すると、要求したメモリーが割り当て可能になるまでドライバがブロックされます。KM_SLEEP 割り当ての場合、スリープが発生する可能性がありますが、処理が成功することは保証されます。KM_NOSLEEP 割り当ての場合、スリープが発生しないことが保証されますが、使用可能なメモリーが現在存在しない場合には NULL が返される可能性があります。

  2. nvlist に名前-値ペアを設定します。たとえば、文字列を追加するには、nvlist_add_string(9F) を使用します。32 ビット整数の配列を追加するには、nvlist_add_int32_array(9F) を使用します。nvlist_add_boolean(9F) のマニュアルページに、ペアを追加するためのインタフェースの完全な一覧が含まれています。

リストの割り当てを解除するには、nvlist_free(9F) を使用します。

次のサンプルコードは、名前-値リストの作成方法を示したものです。

例 5-2 名前-値ペアリストの作成およびデータ設定

nvlist_t*
create_nvlist()
    {
    int err;
    char *str = "child";
    int32_t ints[] = {0, 1, 2};
    nvlist_t *nvl;

    err = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0);    /* allocate list */
    if (err)
        return (NULL);
    if ((nvlist_add_string(nvl, "name", str) != 0) ||
        (nvlist_add_int32_array(nvl, "prop", ints, 3) != 0)) {
        nvlist_free(nvl);
        return (NULL);
    }
    return (nvl);
}

ドライバから nvlist の要素を取得するには、nvlist_lookup_int32_array(9F) など、その型の検索用関数を使用します。検索用関数は、検索対象となるペアの名前を引数として取ります。


注 - これらのインタフェースが動作するのは、nvlist_alloc(9F) の呼び出し時に NV_UNIQUE_NAME NV_UNIQUE_NAME_TYPE のいずれかが指定された場合のみです。それ以外の場合は ENOTSUP が返されます。同じ名前の複数のペアをリストに含めることができないためです。


名前-値リストペアのリストは、連続するメモリー内に配置できます。このアプローチは、通知を受け取るように登録したエンティティーにリストを渡す場合に便利です。最初のステップは、リストに必要なメモリーブロックのサイズを、nvlist_size(9F) を使用して取得することです。次のステップは、nvlist_pack(9F) でリストをバッファーにパックすることです。バッファーの内容を受け取るコンシューマは、nvlist_unpack(9F) でバッファーを展開できます。

名前-値ペアを操作するための関数は、ユーザーレベル、カーネルレベルのどちらの開発者も使用できます。『man pages section 3: Library Interfaces and Headers』『man pages section 9: DDI and DKI Kernel Functions 』の両方に、これらの関数に対する同一のマニュアルページが含まれています。名前-値ペアを処理対象とする関数の一覧については、次の表を参照してください。

表 5-1 名前-値ペアを使用するための関数

マニュアルページ
目的/関数
名前-値ペアをリストに追加します。関数は次のとおりです。

nvlist_add_boolean()nvlist_add_boolean_value()nvlist_add_byte()nvlist_add_int8()nvlist_add_uint8()nvlist_add_int16()nvlist_add_uint16()nvlist_add_int32()nvlist_add_uint32()nvlist_add_int64()nvlist_add_uint64()nvlist_add_string()nvlist_add_nvlist()nvlist_add_nvpair()nvlist_add_boolean_array()nvlist_add_int8_array, nvlist_add_uint8_array()nvlist_add_nvlist_array()nvlist_add_byte_array()nvlist_add_int16_array()nvlist_add_uint16_array()nvlist_add_int32_array()nvlist_add_uint32_array ()nvlist_add_int64_array()nvlist_add_uint64_array()nvlist_add_string_array()

名前-値リストのバッファーを操作します。関数は次のとおりです。

nvlist_alloc()nvlist_free()nvlist_size()nvlist_pack()nvlist_unpack()nvlist_dup()nvlist_merge()

名前-値ペアを検索します。関数は次のとおりです。

nvlist_lookup_boolean()nvlist_lookup_boolean_value ()nvlist_lookup_byte()nvlist_lookup_int8()nvlist_lookup_int16()nvlist_lookup_int32()nvlist_lookup_int64()nvlist_lookup_uint8()nvlist_lookup_uint16()nvlist_lookup_uint32()nvlist_lookup_uint64()nvlist_lookup_string()nvlist_lookup_nvlist()nvlist_lookup_boolean_array、 nvlist_lookup_byte_array()nvlist_lookup_int8_array()nvlist_lookup_int16_array()nvlist_lookup_int32_array()nvlist_lookup_int64_array()nvlist_lookup_uint8_array()nvlist_lookup_uint16_array()nvlist_lookup_uint32_array() nvlist_lookup_uint64_array()nvlist_lookup_string_array() nvlist_lookup_nvlist_array()nvlist_lookup_pairs()

名前-値ペアのデータを取得します。関数は次のとおりです。

nvlist_next_nvpair()nvpair_name()nvpair_type()

名前-値ペアを削除します。関数は次のとおりです。

nv_remove()nv_remove_all()