ファンクション ドライバーでのデバイスの開始

ファンクションドライバーは、 IoCompletion ルーチンを設定し、 IRP_MN_START_DEVICE 要求をデバイススタックに渡し、すべての下位ドライバーがIRPを終了するまで、その開始操作を延期します。 カーネルイベントと IoCompletion ルーチンを使用してIRP処理を延期する方法の詳細については、 下位ドライバーが終了するまで PnP IRP処理を延期する を参照してください。

DispatchPnP ルーチンがすべての下位ドライバーがIRPを終了した後に制御を回復すると、ファンクションドライバーはデバイスを開始するためのタスクを実行します。 ファンクションドライバーは、以下のような手順でデバイスを起動します:

  1. 下位ドライバーがIRPに失敗した場合 (IoCallDriver がエラーを返した場合)、IRPの処理を続行しません。 必要なクリーンアップを行い、 DispatchPnP ルーチンからリターンします(このリストの最後のステップに進みます)。

  2. 下位ドライバーがIRPを正常に処理した場合は、デバイスを起動します。

    デバイスを起動する正確な手順は、デバイスによって異なります。 このような手順には、I/O空間のマッピング、ハードウェアレジスタの初期化、デバイスのD0電源状態の設定、 IoConnectInterruptによる割り込みの接続などがあります。 IRP_MN_STOP_DEVICE 要求の後にドライバーがデバイスを再起動する場合、ドライバーは復元するデバイスの状態を持つ場合があります。

    ドライバーがデバイスにアクセスする前に、デバイスの電源を入れる必要があります。 詳細は、 デバイスのパワーアップ を参照してください。

    デバイスのウェイクアップを有効にする必要がある場合、そのパワーポリシー所有者(通常はファンクションドライバー)は、デバイスのパワーアップ後、 IRP_MN_START_DEVICE 要求を完了する前に待機/ウェイクIRPを送信する必要があります。 詳細については、 待機/ウェイクIRPの送信を参照してください。

  3. IRP保持キューでIRP開始します。

    ドライバー定義のHOLD_NEW_REQUESTSフラグをクリアし、IRP保持キューのIRPを開始します。 ドライバーは、デバイスを初めて開始するときと、クエリ停止またはIRPを停止の後にデバイスを再起動するときに、この操作を行う必要があります。 詳細については、 デバイスが一時停止しているときにIRPを保留する を参照してください。

  4. [オプション] IoSetDeviceInterfaceStateを呼び出して、デバイスのインターフェイスを有効にします。

    ドライバーが AddDevice ルーチン (またはINFや共同インストーラなどの他のコンポーネント) で登録したインターフェイスがあれば、それを有効にします。

    Windows 2000以降のWindowsでは、 IRP_MN_START_DEVICE IRPが完了するまで、PnPマネージャはデバイスインターフェースの到着通知を送信しません。 PnP マネージャは、デバイスのすべてのドライバーが開始IRPを完了する前に到着した作成要求も失敗させます。

  5. IRPを完了します。

    Postponing PnP IRP Processing Until Lower Drivers Finishで説明したように、ファンクションドライバーの IoCompletion ルーチンがSTATUS_MORE_PROCESSING_REQUIREDを返したため、ファンクションドライバーの DispatchPnP ルーチンは、 IoCompleteRequest を呼び出してI/O完了処理を再開する必要があります。

    ファンクションドライバーの開始操作が成功した場合、ドライバーは Irp->IoStatus.Status をSTATUS_SUCCESSに設定し、優先度をIO_NO_INCREMENTにブーストして IoCompleteRequest を呼び出し、 DispatchPnP ルーチンからSTATUS_SUCCESSを返します。

    ファンクションドライバーは、起動操作時にエラーが発生した場合、IRPにエラーステータスを設定し、 IoCompleteRequest をIO_NO_INCREMENTで呼び出し、 DispatchPnP ルーチンからエラーを返します。

    下位ドライバーがIRPに失敗した場合 (IoCallDriver がエラーを返した場合)、 ファンクションドライバーは IoCompleteRequest をIO_NO_INCREMENTで呼び出し、 DispatchPnP ルーチンから IoCallDriver エラーを返します。 この場合、IRPに失敗した下位ドライバーによってすでに設定されているため、 ファンクションドライバーは Irp->IoStatus.Status を設定しません。

ファンクションドライバーが IRP_MN_START_DEVICE 要求を受信すると、 IrpSp->Parameters.StartDevice.AllocatedResources および IrpSp->Parameters.StartDevice.AllocatedResourcesTranslatedの構造を調べる必要があります。 ドライバーは、デバッグのために、各リソースリストのコピーをデバイス拡張に保存する必要があります。

リソース一覧は対になった CM_RESOURCE_LIST 構造で、生の一覧の各要素は翻訳された一覧の同じ要素に対応します。 たとえば、 AllocatedResources.List[0] が生の I/O ポート範囲を記述している場合、 AllocatedResourcesTranslated.List[0] は変換後の同じ範囲を記述します。 各変換済みリソースには、物理アドレスとリソースの種類が含まれます。

ドライバーが変換されたメモリ リソース (CmResourceTypeMemory)を割り当てられた場合、 MmMapIoSpace を呼び出して、物理アドレスをデバイスレジスタにアクセスできる仮想アドレスにマップする必要があります。 ドライバーがプラットフォームに依存しない方法で動作するためには、返され、変換された各リソースをチェックし、必要であればマッピングしなければなりません。

ファンクションドライバーは、すべてのデバイスリソースへのアクセスを保証するために、 IRP_MN_START_DEVICE に応答して次のことを行うべきです:

  1. IrpSp->Parameters.StartDevice.AllocatedResources をデバイス拡張にコピーします。

  2. IrpSp->Parameters.StartDevice.AllocatedResourcesTranslated をデバイス拡張子にコピーします。

  3. ループ内で、 AllocatedResourcesTranslated内の各記述子要素を検査します。 記述子リソースの種類が CmResourceTypeMemory の場合、 MmMapIoSpace を呼び出し、変換されたリソースの物理アドレスと長さを渡します。

ドライバーが IRP_MN_STOP_DEVICEIRP_MN_REMOVE_DEVICE、または IRP_MN_SURPRISE_REMOVAL 要求を受け取ると、同様のループで MmUnmapIoSpace を呼び出してマッピングをリリースしる必要があります。 ドライバーは、 IRP_MN_START_DEVICE 要求に失敗する必要がある場合にも、 MmUnmapIoSpace を呼び出さなければなりません。

詳細は バス相対アドレスを仮想アドレスにマッピングする を参照してください。