다음을 통해 공유


하위 드라이버가 완료될 때까지 PnP IRP 처리를 연기하다.

일부 PnP 및 전원 IRP는 먼저 디바이스에 대한 부모 버스 드라이버에서 처리한 다음 디바이스 스택의 각 다음 상위 드라이버에 의해 처리되어야 합니다. 예를 들어 부모 버스 드라이버는 디바이스(IRP_MN_START_DEVICE)에 대한 시작 작업을 수행한 후 다음으로 높은 각 드라이버에 대한 첫 번째 드라이버여야 합니다. 이러한 IRP의 경우 함수 및 필터 드라이버는 I/O 완료 루틴을 설정하고, IRP를 다음 하위 드라이버로 전달하고, 하위 드라이버가 IRP를 완료할 때까지 IRP를 처리하는 작업을 연기해야 합니다.

IoCompletion 루틴은 IRQL DISPATCH_LEVEL에서 호출할 수 있지만 함수 또는 필터 드라이버는 IRQL = PASSIVE_LEVEL에서 IRP를 처리해야 할 수도 있습니다. IoCompletion 루틴에서 PASSIVE_LEVEL 돌아가려면 드라이버는 커널 이벤트를 사용할 수 있습니다. 드라이버는 커널 모드 이벤트를 설정하는 IoCompletion 루틴을 등록한 다음 드라이버는 DispatchPnP 루틴에서 이벤트를 기다립니다. 이벤트가 설정되면 하위 단계의 드라이버가 IRP를 완료하고 그 후에 드라이버가 IRP를 처리할 수 있습니다.

드라이버는 하위 드라이버가 전원 IRP(IRP_MJ_POWER)를 완료할 때까지 기다리는 데 이 방법을 사용해서는 안 됩니다. IoCompletion 루틴에 설정된 DispatchPower 루틴에서 이벤트를 대기하면 교착 상태가 발생할 수 있습니다. 자세한 내용은 전원 IRP을 참조하세요.

다음 두 그림은 상위 드라이버가 하위 드라이버가 PnP IRP를 완료할 때까지 기다리는 방법을 보여줍니다. 이 예제에서는 함수 및 버스 드라이버가 수행해야 하는 작업과 PnP 관리자 및 I/O 관리자와 상호 작용하는 방법을 보여줍니다.

플러그 앤 플레이 IRP 처리를 연기하는 것을 보여주는 다이어그램 , 1부.

다음 주석은 이전 그림의 동그라미로 표시된 숫자에 해당합니다.

  1. PnP 관리자는 I/O 관리자를 호출하여 IRP를 디바이스 스택의 최상위 드라이버로 보냅니다.

  2. I/O 관리자는 상위 드라이버의 DispatchPnP 루틴을 호출합니다. 이 예제에서는 디바이스 스택에 두 개의 드라이버(함수 드라이버 및 부모 버스 드라이버)만 있으며 함수 드라이버는 최상위 드라이버입니다.

  3. 함수 드라이버는 커널 모드 이벤트를 선언하고 초기화하며, 다음 하위 드라이버에 대한 스택 위치를 설정하고, 이 IRP에 대한 IoCompletion 루틴을 설정합니다.

    함수 드라이버는 IoCopyCurrentIrpStackLocationToNext 사용하여 스택 위치를 설정할 수 있습니다.

    IoSetCompletionRoutine호출에서 함수 드라이버는 InvokeOnSuccess, InvokeOnError, InvokeOnCancel 설정하여 TRUE 커널 모드 이벤트를 컨텍스트 매개 변수의 일부로 전달합니다.

  4. 함수 드라이버는 IRP를 처리하는 작업을 수행하기 전에 IoCallDriver 사용하여 IRP를 디바이스 스택 아래로 전달합니다.

  5. I/O 관리자는 해당 드라이버의 DispatchPnP 루틴을 호출하여 디바이스 스택의 다음 하위 드라이버에 IRP를 보냅니다.

  6. 이 예제의 다음 하위 드라이버는 디바이스 스택에서 가장 낮은 드라이버인 부모 버스 드라이버입니다. 버스 드라이버는 해당 작업을 수행하여 디바이스를 시작합니다. 버스 드라이버는 Irp->IoStatus.Status를 설정하고, 이 IRP와 관련이 있을 경우 Irp->IoStatus.Information를 설정한 다음, IoCompleteRequest를 호출하여 IRP를 완료합니다.

    버스 드라이버가 다른 드라이버 루틴을 호출하거나 시작하기 위해 디바이스에 I/O를 보내는 경우 버스 드라이버는 DispatchPnP 루틴에서 PnP IRP를 완료하지 않습니다. 대신 IoMarkIrpPending로 IRP를 보류 상태로 표시하고 DispatchPnP 루틴에서 STATUS_PENDING을 반환해야 합니다. 드라이버는 나중에 다른 드라이버 루틴, 아마도 DPC 루틴에서 IoCompleteRequest 호출합니다.

다음 그림에서는 디바이스 스택의 상위 드라이버가 연기된 IRP 처리를 다시 시작하는 예제의 두 번째 부분을 보여줍니다.

플러그 앤 플레이 irp 처리를 연기하는 것을 보여 주는 다이어그램( 2부).

다음 주석은 이전 그림의 동그라미로 표시된 숫자에 해당합니다.

  1. 버스 드라이버가 IoCompleteRequest호출하면 I/O 관리자는 상위 드라이버의 스택 위치를 검사하고 찾은 IoCompletion 루틴을 호출합니다. 이 예제에서 I/O 관리자는 다음 상위 드라이버인 함수 드라이버에 대한 IoCompletion 루틴을 찾아 호출합니다.

  2. 함수 드라이버의 IoCompletion 루틴은 컨텍스트 매개 변수에 제공된 커널 모드 이벤트를 설정하고 STATUS_MORE_PROCESSING_REQUIRED 반환합니다.

    I/O 관리자가 현재 상위 드라이버에서 설정한 IoCompletion 루틴을 호출하지 못하도록 IoCompletion 루틴은 STATUS_MORE_PROCESSING_REQUIRED 반환해야 합니다. IoCompletion 루틴은 이 상태를 사용하여 완료를 지연시켜 드라이버의 DispatchPnP 루틴이 제어를 다시 얻게 합니다. I/O 관리자는 이 드라이버의 DispatchPnP 루틴이 IRP를 완료할 때 이 IRP에 대해 더 높은 드라이버의 IoCompletion 루틴 호출을 다시 시작합니다.

  3. I/O 관리자는 IRP 완료를 중지하고 IoCompleteRequest호출한 루틴으로 컨트롤을 반환합니다. 이 예제에서는 버스 드라이버의 DispatchPnP 루틴입니다.

  4. 버스 드라이버는 DispatchPnP 루틴을 완료한 후 IRP 처리 결과를 나타내는 상태, 즉 STATUS_SUCCESS 또는 오류 상태로 반환됩니다.

  5. IoCallDriver 호출자에게 컨트롤을 반환합니다. 이 예제에서는 함수 드라이버의 DispatchPnP 루틴입니다.

  6. 함수 드라이버의 DispatchPnP 루틴은 IRP 처리를 다시 시작합니다.

    IoCallDriver STATUS_PENDING 반환하는 경우 IoCompletion 루틴이 호출되기 전에 DispatchPnP 루틴이 실행을 다시 시작합니다. 따라서 DispatchPnP 루틴은 커널 이벤트가 IoCompletion 루틴에 의해 신호를 받을 때까지 기다려야 합니다. 이렇게 하면 모든 하위 드라이버가 완료될 때까지 DispatchPnP 루틴이 IRP를 계속 처리하지 않습니다.

    Irp->IoStatus.Status에 오류가 설정된 경우에, 하위 드라이버가 IRP에 실패했으므로 함수 드라이버는 IRP를 계속 처리하면 안 됩니다(필요한 정리를 제외).

  7. 낮은 드라이버가 IRP를 성공적으로 완료하면 함수 드라이버는 IRP를 처리합니다.

    부모 버스 드라이버에서 먼저 처리되는 IRP의 경우 버스 드라이버는 일반적으로 Irp->IoStatus.Status 성공적인 상태를 설정하고 필요에 따라 Irp->IoStatus.Information값을 설정합니다. 함수 및 필터 드라이버는 IRP에 실패하지 않는 한 IoStatus 값을 그대로 둡니다.

    함수 드라이버의 DispatchPnP 루틴은 IoCompleteRequest를 호출하여 IRP를 완료합니다. I/O 관리자는 I/O 완료 처리를 다시 시작합니다. 이 예제에서는 함수 드라이버 위에 필터 드라이버가 없으므로 더 이상 호출할 IoCompletion 루틴을 없습니다. IoCompleteRequest 함수 드라이버 DispatchPnP 루틴에 컨트롤을 반환하면 DispatchPnP 루틴이 상태를 반환합니다.

일부 IRP의 경우 함수 또는 필터 드라이버가 디바이스 스택을 올라가는 과정에서 IRP 처리에 실패하면 PnP 관리자가 하위 드라이버에 알립니다. 예를 들어 함수 또는 필터 드라이버가 IRP_MN_START_DEVICE실패하면 PnP 관리자는 디바이스 스택에 IRP_MN_REMOVE_DEVICE 보냅니다.