DispatchPnP ルーチン

ドライバーの DispatchPnP ルーチンは、IRP_MJ_PNP I/O 関数コードの IRP を処理することによってプラグ アンド プレイをサポートします。 IRP_MJ_PNP 関数コードには、いくつかのマイナー I/O 関数コード (「プラグ アンド プレイのマイナー IRP」を参照) が関連付けられています。その一部は、すべてのドライバーが処理する必要があり、その一部は必要に応じて処理できます。 PnP マネージャーはこれらのマイナー関数コードを使用して、デバイスを起動、停止、削除すること、およびドライバーのデバイスに関してドライバーにクエリを実行することをドライバーに指示します。

デバイスのすべてのドライバーは、機能またはフィルター ドライバーが IRP を失敗することが許可されている場合を除き、デバイスの PnP IRP を処理する機会を持っている必要があります。

各ドライバーの DispatchPnP ルーチンは、次の規則に従う必要があります。

  • 関数またはフィルター ドライバーは、関数またはフィルター ドライバーが IRP を処理し、(リソースが不足しているためなど) エラーが発生しない限り、デバイス スタック内の次のドライバーに PnP IRP を渡す必要があります。

    いずれかのドライバーでエラーが発生しない限り、デバイスのすべてのドライバーは、デバイスの PnP IRP を処理する機会を持っている必要があります。 PnP マネージャーは、デバイス スタック内の最上位のドライバーに Irp を送信します。 関数ドライバーとフィルター ドライバーは、次のドライバーに IRP を渡し、親バス ドライバーは IRP を完了します。 詳細については、「下のデバイス スタックへの PnP IRP の受け渡し」を参照してください。

    ドライバーは、IRP の処理を試み、(リソースが不足しているなど) エラーが発生した場合、IRP に失敗することができます。 ドライバーが処理しないコードを含む IRP を受け取った場合、ドライバーは IRP を失敗させる必要があります。 IRP の状態を変更せずに、このような IRP を次のドライバーに渡す必要があります。

  • ドライバーは、特定の PnP IRP を処理する必要があり、必要に応じて他の PnP IRP を処理できます。

    各 PnP ドライバーは、IRP_MN_REMOVE_DEVICE などの特定の IRP を処理するために必要であり、必要に応じて他の IRP を処理できます。 ドライバー (関数ドライバー、フィルター ドライバー、バス ドライバー) の種類ごとに必要な IRP とオプションについては、「プラグ アンド プレイのマイナー IRP」を参照してください。

    ドライバーは、適切なエラー状態で必要な PnP IRP を失敗させることができますが、ドライバーは、このような IRP の STATUS_NOT_SUPPORTED を返す必要があります。

  • ドライバーが PnP IRP を正常に処理する場合、ドライバーは IRP のステータスを成功に設定します。 スタック内の別のドライバーに依存せずにステータスを設定できます。

    ドライバーは、Irp->IoStatus.Status を STATUS_SUCCESS に設定して、ドライバーが IRP を正常に処理したことを PnP マネージャーに通知します。 IRP によっては、バス ドライバー以外のドライバーが、その親バス ドライバーを使用して状態を成功に設定できることがあります。 ただし、これは危険な方法です。 一貫性と堅牢性を確保するために、ドライバーは、正常に処理する各 PnP IRP の IRP の状態を成功に設定する必要があります。

  • ドライバーが IRP に失敗した場合、ドライバーはエラー状態で IRP を完了します。IRP を次のドライバーに渡してはなりません。

    IRP_MN_QUERY_STOP_DEVICE などの IRP に失敗した場合、ドライバーは、Irp->IoStatus.Status を STATUS_UNSUCCESSFUL に設定します。 他の IRP に対する追加のエラー状態値には、STATUS_INSUFFICIENT_RESOURCES と STATUS_INVALID_DEVICE_STATE があります。

    ドライバーは、自身が処理する IRP に対して STATUS_NOT_SUPPORTED を設定しません。 これは、PnP マネージャーによって設定される初期状態です。 この状態で IRP が完了した場合は、スタック内のどのドライバーも IRP を処理せず、すべてのドライバーが次のドライバーにこの IRP を渡したことを意味します。

  • ドライバーは、ディスパッチ ルーチン (IRP によるデバイス スタックの下り時)、IoCompletion ルーチン (IRP によるデバイス スタックの上り時)、またはその両方で PnP IRP を処理する必要があります。

    IRP_MN_REMOVE_DEVICE などの一部の PnP IRP は、最初にデバイス スタックの上部にあるドライバーによって処理され、次に次の下位のドライバーごとに処理する必要があります。 他の一部の PnP IRP (IRP_MN_START_DEVICE など) は、親バス ドライバーによって最初に処理される必要があります。 さらに、IRP_MN_QUERY_CAPABILITIES などの他の PnP IRP は、デバイス スタックの途中とバックアップの両方で処理できます。 各 PnP IRP に適用される規則については、「プラグ アンド プレイのマイナー IRP」を参照してください。 親バス ドライバーで最初に処理する必要がある PnP IRP の処理については、「下位のドライバーが完了するまで PnP IRP 処理を延期する」を参照してください。

  • ドライバーは、デバイス スタックの IRP の方法で IRP に情報を追加し、IRP のバックアップ方法に関する情報を変更または削除する必要があります。

    PnP クエリ IRP に応答して情報を返す場合、ドライバーは、この規則に従って、デバイスの階層化されたドライバーによって渡される順序の情報を有効にする必要があります。

  • 明示的に文書化されている場合を除き、ドライバーは、特定の順序で送信される PnP IRP に依存してはなりません。

  • ドライバーは、PnP IRP を送信するときに、デバイス スタックの最上位のドライバーに IRP を送信する必要があります。

    ほとんどの PnP IRP は PnP マネージャーによって送信されますが、一部はドライバー (たとえば、IRP_MN_QUERY_INTERFACE) によって送信できます。 ドライバーは、デバイス スタックの上部にあるドライバーに PnP IRP を送信する必要があります。 デバイス スタックの上部にあるドライバーのデバイス オブジェクトへのポインターを取得するには、IoGetAttachedDeviceReference を呼び出します。