テクニカル ドキュメント #75



Doc ID: 75
製品: WinDriver
Version:  --

ユーザー モード WinDriver アプリケーションでどのように PCI 割り込みを処理できますか?

まず初めに、WD_PciScanCards() を使用して、カードを接続してる場所を見つけてください。WD_PciGetCardInfo() を呼んでカードの情報を取得します。この情報には、プラグ アンド プレイ システムでカードが選択した IRQ が含まれます。WD_CardRegister() を呼んで、割り込みをインストールします。

PCI 割り込みは、レベル センシティブなので、cardReg.Card.Item[i].I.Int.dwOptionsINTERRUPT_LEVEL_SENSITIVE フラグが設定されているか確認してください。 'i' は、Item 配列の割り込みアイテムのインデックス番号です。WD_PciGetCardInfo() 関数が自動的に PCI カードのフラグを設定するので、通常、コード上には明白にフラグを設定する必要はありません。そして、同じ WD_CARD 構造体に渡します。WD_CARD 構造体は、WD_PciGetCardInfo() から WD_CardRegister() へ渡されます。

レベル センシティブ割り込みを受信すると直ぐにカーネルで検知 (クリア) されます。割り込みの検知を有効にするには、InterruptEnable() 関数 (/ InterruptThreadEnable() - in versions 4.30 - 5.22)を呼ぶか、より低レベルな WD_IntEnable() 関数 (InterruptEnable() に呼ばれます) を呼びます。WD_INTERRUPT 構造体に渡すことによって、WD_INTERRUPT 構造体はWD_CardRegister() を呼ぶ前に戻された割り込みハンドルを保持します。WD_TRANSFER 構造体の配列にこの情報をセットアップする必要があります。この構造体は、WD_INTERRUPT 構造体の Cmd メンバーによってポイントされます。割り込みの検知およびクリアに関する情報は、ハードウェアの仕様によります。

注意: DriverWizard を使用して、割り込みの検知の関連するレジスタを定義でき、そしてコードを生成する前に、割り込みへのレジスタを割り当てることができます ("Registers" タブから "New" を選択して、レジスタを定義します)。[v5.21 以降、割り込みに対して、1つ以上のレジスタを割り当てることができます]。また、生成されたコードには、割り込みを検知するための転送コマンドがあり、それは DriverWizard プロジェクトで定義した情報と一致します。

WinDriver へ割り込み検知情報を渡した後、物理的に割り込みを有効にする必要があります。割り込みレジスタへの関連する情報を記述することによって、コードから実行できます (この情報もまたハードウェアの仕様に依存します)。

InterruptEnable() (/ InterruptThreadEnable() - v4.30 - 5.22 の場合) 関数で、WD_IntEnable() 関数を呼ぶことによって、割り込みを有効にし、割り込み処理スレッドを生成および起動します。割り込みスレッドは、WD_IntWait() 関数を呼んで、割り込みを待機し、そして割り込みが発生し、WD_IntWait() 関数が戻す際に、割り込み処理ルーティンを有効にします。InterruptEnable() 関数の実装を参照するには、WinDriver\src\windrvr_int_thread.c ファイルを参照してください (v4.30 - 5.22 の場合、WinDriver\include\windrvr_int_thread.h ファイルで、InterruptThreadEnable() ファイルの実装を参照してください)。[コードから直接より低レベルな WD_IntEnable() および WD_IntWait() 関数を使用するように選択する場合、InterruptEnable() (/ InterruptThreadEnable) 関数を使用する代わりに、WD_IntWait() 関数を呼び出すスレッドを生成する必要があります]。割り込みが発生した際には、割り込みを有効にする前に、WD_INTERRUPT 構造体で設定した割り込み検知のコマンドをカーネル レベルで WinDriver で実行し、WD_IntWait() 関数が返す前に、処理ルーティンを有効にします。

最後に、割り込みを無効にするには、InterruptDisable() (/ InterruptThreadDisable() - v4.30 - 5.22 の場合)関数または、より低レベルな WD_IntDisable() 関数を呼んでください (割り込みを有効にした方法に依存します)。

注意 int.Cmd 配列は1つ以上の WD_TRANSFER コマンドを持つことができます。int.Cmd を設定し、できるだけ多くの WD_TRANSFER 構造体の配列を示すことができます。たとえば、割り込みを検知する前に、カーネルで関連するレジスタかた読込むために、read (読み込み) 転送コマンドで配列に初めの WD_TRANSFER 構造体を設定することができます。読み込み結果を WD_TRANSFER 構造体の Data ユニオン フィールドに保存し、ユーザー モードの割り込み処理ルーティンから後でアクセスできます (例: DWORD data = int.Cmd[0].Data.Dword)。
割り込みを検知する前に、カーネルで読込んだデータを保存するには、WD_INTERRUPT 構造体の dwOptions フィールドに INTERRUPT_CMD_COPY フラグを設定する必要があります (int.dwOptions |= INTERRUPT_CMD_COPY;)。

対象のカードの DriverWizard で生成されたコードは、PCI バスをスキャン、カードのリソースをレジスト (割り込みを含みます) および割り込みを有効および処理する、関連する WinDriver API 呼び出しをすでに実装しています。ただし、割り込み検知のメカニズムはハードウェアの仕様に依存するので、割り込みの正確に検知情報を設定し (ハードウェアの仕様に依存します)、割り込み処理ルーティンを実装するためには、上記のガイドラインにそって、修正が必要なコードがあります。

特定の PCI チップセット (PLX、Altera など) 用の WinDriver のライブライ関数を参照することもできます。たとえば、これらのチップ用の WinDriver の割り込み処理のコードをなど。サンプルの割り込み検知のコマンドは、これ以上のすべての割り込みを無効にするので注意してください。このため、割り込み処理ルーティンから割り込みを再度有効にする必要があります。(XXX_IntHandler() または XXX_IntHandlerRoutine() ルーティンの最後に、XXX_IntEnable() で割り込みを有効にするために使用したのと同じような行を追加することによって、これを実行できます)。

WinDriver の割り込み処理のメカニズムの説明と関連するサンプル コードに関しては、WinDriver のユーザー マニュアルを参照してください。

割り込みのコードの柔軟性を増し、割り込み処理速度を向上させるには、カーネルで直接、割り込みを検知し処理するための WinDriver の Kernel PlugIn 機能を使用することを考慮してください。