さて、本来の作業である殆どのドライバの機能を sdc_driver.c ファイル に書く段階に来ました。先ず、ドライバの主な機能の概要は次のとおり:
詳細にドライバーのファイルを追いかける前に、重要な情報がここにあり ます:
#define してある所で両者を区別することが出来ま
す。16 色サーバーをサポートする場合、XF86VGA16 の
#define が有効になるようにプログラムに指定して
ください。殆どの場合、次を stub_driver.c ファイルの先頭近く
に指定する事で充分です。
#ifdef XF86VGA16 #define MONOVGA #endif
運がよければ、チップセットのベンダーのデータブックに様々な BIOS モー ド用のレジスタの設定の表が掲載されているでしょう。様々な BIOS モード でどんな操作が可能であるか学習することが出来ます。
同じベンダーが出荷している複数のチップセットは単一のドライバでサ ポート可能で、実際魅力的です。複数のサポートしているチップセットが ある場合、一連の対応する #define とドライバを識別する為の変数の `SDCchipset' を保持して下さい。Trident と PVGA1/WD を例題として見て ください(Tseng ET3000 と ET4000は逆の意味での例題です。つまり複数 のチップセットに対応したドライバインターフェースが開発される前に実 現してしまいました。従ってこの場合はもうフォロー出来ません。)。追 加するドライバはこれらと異なるように作業をするときはバージョンを意 識するだけで良いことに注意してください。例えば、SDC ドライバが SDC-1a,SDC-1b と SDC-2 のチップセットをサポートしていると仮定して下 さい。この -1a と-1b は本質的には同一ですが、-2 とは異なります。追 加するドライバが -1 と -2 のチップセットをサポートすれば、-1a と -1b の違いを意識しなくても良いでしょう。この事はエンドユーザの作業を簡 単にします。
ユーザにドライバの挙動を制御させるか、ユーザの介入無しにドライバを 決定できない場合は、``option'' を使いましょう。SDC チップセットを 使用しているボードベンダーは 8 個か 16 個のクロックパラメータをオ プションで与えてなさいと言うでしょう。チップセットの探査の結果から 決定するしか方法は無いので XF86Config ファイル からユーザがオプショ ンで挙動を選択できるように提供しましょう。オプションは ``xf86_option.h'' ファイルに定義します。再利用可能なオプションが既 にそこにあるかもしれません。再利用可能な場合は追加するドライバに使 いましょう。再利用可能で無い場合は新たに #define を追加し、そ のファイルに 文字列->シンボルの割り当てを表形式で定義します。オプ ションの使い方を理解するには ET4000, PVGA1/WD と Trident のドライ バを見てください。
上記の説明から何が必要なのか理解したら、ドライバのデータ構造を記入 する段階です。最初に `vgaSDCRec' の構造に取り掛かりましょう。このデ ータ構造は SVGA の状態情報を保持するドライバ特有のデータ構造です。 このデータ構造の最初の項目は常に `vgaHWRec std' です。この項目は汎 用 VGA の一部分の情報を保持します。それ以降に追加するドライバが操作 するレジスタ毎に一つの `unsigned char' の領域を取ってください。これ が最初のデータ構造の全てです。
次に `SDC' 構造(`vgaVideoChipRec' 型) の初期化をしなければいけませ ん。これは追加するドライバをサーバーに識別させるグローバルな構造体 です。その名称はすべて大文字で `SDC' としなければいけません。つまり、 追加するドライバのあるディレクトリの名称と一致しなければなりません。 この事はリンクキットの再構成を行う時に必要なディレクトリとグローバ ルなデータ構造の全てを確認することが必須です。
この構造体の始めの部分はドライバ関数へのポインタを単に保持します。
次は、チップセットがバンク切り替えをどうするかについての情報を初期 化します。以降の領域は次のように記入しなければいけません:
Ident() 関数は大変単純な関数です。サーバーがこの関数を NULL を帰すまで繰り返し呼び出したときに、組み込まれているドライバの 一覧を出力します。Ident() 関数はサポートしているチップセッ トの名称を返します。この関数は各々の繰り返しで 0 から増加する数値を 渡します。
ClockSelect() 関数はクロックの探査をするときに(例えば `Clocks' 行を XF86Config ファイルで指定しなかった場合)選択したドッ トクロックをパラメタで受け取るのに用います。受け取った数値によって 関数はチップセットの clock-select ビットを設定します。 (CLK_REG_SAVE, CLK_SAVE_RESTORE) のような値は二つのダミーとして受け 取る場合があります。CLK_REG_SAVE を受け取った時は、関数がクロック 選択途中に変更したレジスタの写しが保存されています。CLK_REG_RESTORE を受け取った時は、関数がレジスタを回復しました。クロック探査がレジ スタの内容を破壊しなかったことを保証します。
受け取ったインデックスの値が不正か、もしくはクロックが不正で設定出 来なかった場合、この関数は FALSE を返します
Probe() 関数はドライバの中で多分最も重要でかつ最も直感的で
無い関数でしょう。Probe 関数は全てのチップセットに依存せずにチップ
セットを識別しなければなりません。XF86Config ファイルに
`Chipset' 行を指定した時に、単純な文字列比較を行います。運
がよければ、チップセットの認識機構(識別/バージョン レジスタ, 等)が
あって、それがデータブックに掲載されているでしょう。さもなければ、
以下に述べるような何らかの手順によって認識しなければなりません。
よくレジスタに特有のパターンや、一定の拡張レジスタを探して認識しま す。又はいくつかのボードやチップセットでは、必要な情報は一定の署名 文字列を BIOSから読みだして獲得しています。既存の探査関数を勉強する 事と参考文献を参照する事を強くお薦めします。追加する探査が非破壊で 行われていることを確認して、レジスタを更新するならば、更新前に保存 して、更新後に回復しなければいけません。
チップセットが認識できたら、Probe() 関数はいくつかの他の 初期化を行う必要があります。
VideoRam' パラメタを指定
しない場合は、搭載しているメモリ量を特定しなければいけません。
Clocks' パラメタを指定し
ない場合は、可能なドットクロックの値を特定しなければいけませ
ん。vgaGetClocks() 関数を呼ぶことで、可能なクロック
の値とClockSelect() へのポインタを受け取れます。
EnterLeave() 関数はサーバー上の仮想コンソールに入ったり出 たりする度に呼ばれます(仮想コンソールの無い OS では、この関数はサー バーの開始時に呼ばれ、終了時にもう一度呼ばれます)。この関数の目的は I/O の権限を(OS が要求するように)譲渡したり剥奪したりする事にある為 と ドライバが操作しなければならない``保護された''レジスタへのロック 解除と再ロックアクセスをする為です。これは、とても小さな関数ですが 以降のスタブドライバのコメントにあるように実現しました。
Restore() 関数は保存されたビデオ状態を回復するのに用いま す。restore という名称は少し誤った名称で、この関数は保存された状態 を回復する事とサーバーが新規に作成した状態を保存する事の両方に使用 します。Restore() 関数は次の手続きをふむ必要があります:
Save() 関数はサーバー開始時に初期ビデオ状態情報を取り出す のに使用する。Save() 関数は次の手続きをふむ必要があります:
Init() 関数はドライバの中で (Probe() 関数の次に) 二番目に重要です。サーバーの中に定義された表示モード各々についてデー タ構造を初期化します。この関数は SVGA チップセットに必要な状態に `vgaSDCRec' データ構造全体を初期化するのに使います。構造体の汎用 VGA 部分は (これも vgaHW.c 内にある) vgaHWInit() を呼ぶこ とにより初期化します。
汎用の部分を初期化したら、必要なら Init() 関数が汎用レジス タのいくつかの初期化を行います。正しい初期化によってその他全ての領 域が埋められます。初期化した特有のモードの情報は `mode' パラメタで ある`DisplayModeRec' 構造体へのポインタで受け取ります。
レジスタの適正なビットの初期化の方法が分かっている場合はここで初期 化しましょう。Restore() 関数でしかそのビットを read/modify/write 出来ない事を確認してください。
Adjust() 関数は比較的根本的な関数です。仮想スクリーンのス クロールや表示解像度の変更によって、サーバーがビデオメモリの表示用 領域の開始点を調整する必要のあるときはいつも呼ばれます。毎回、指定 した座標に合わせてチップセットの開始アドレスを設定します。これを実 現する方法の詳細はスタブドライバの中のコメントに従ってください。
ValidMode() 関数は必須です。何故グラフィックモードが妥当で 無いのか、チップセットに依存した理由を調査するのに使用します。 Probe() 実行後のプログラムのより上位のプログラムから呼ばれます。多くの場 合、特別な調査は必要なくこの関数は通常、単に TRUE を返します。
SaveScreen() 関数は殆どのチップセットでは必要ありません。 追加するドライバが同期リセットをチップセットで実行する場合、拡張レ ジスタを更新するのでこの関数が必要になります(データブックに詳細に 記載があります)。この関数が必要*無い*とき、特に定義は必要無く、 vgaVideoChipRec 構造体型で初期化した `NoopDDA' を置きましょう (NoopDDA は汎用の空の関数です)。
この関数が*必要*ならば、比較的単純な次の作業を行ってください。二回 呼び出すのですが、一回目はリセット前と二回目はリセット後に呼び出し ます。前者の場合は 引数にSS_START を渡し、後者では SS_FINISH を渡し て下さい。毎回、SS_START で呼び出した場合はリセットによって影響のあ るレジスタを格納し、SS_FINISH で呼び出した場合はそれを回復する必要 があります。
GetMode() 関数は XFree86 1.3 迄は使っていませんし、これは vgaVideoChipRec 型で `NoopDDA' を初期化したものです。
将来、いくつかの点でこの関数はサーバーのドライバライブラリを使うサー バー且つ/又はスタンドアローンのプログラムの対話型ビデオモード調節 に使用可能になるでしょう。この関数は SVGA レジスタを読み込み現在の ビデオモードの DisplayModeRec 構造体に書き込みます。
FbInit() 関数はアクセラレータグラフィックスをサポートする ドライバに必須です。アクセラレータチップ固有のバージョンでは標準で cfb.banked 関数を置き換えて使用します。vga256LowlevFuncs は置き換え 可能な関数の一覧を含む構造体です。この構造体は vga256.h で定義して います。FbInit() 関数の例は et4000, pvga1 とcirrus のドラ イバにあります。
この関数が必要ない場合、単に定義をしないで、vgaVideoChipRec 型で初 期化した `NoopDDA' を置いてください。