Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Некоторые PnP и IRP питания должны быть сначала обработаны родительским драйвером шины устройства, а затем каждым последующим драйвером в стеке устройств. Например, водитель родительской шины должен первым выполнить начальные операции устройства (IRP_MN_START_DEVICE), после чего следует каждый следующий драйвер устройства более высокого уровня. Для таких IRP драйверам функций и фильтров необходимо задать подпрограмму завершения ввода-вывода, передать IRP следующему нижестоящему драйверу и отложить все действия для обработки IRP до тех пор, пока нижестоящие драйверы не завершат работу с IRP.
Подпрограмма IoCompletion может вызываться на уровне IRQL DISPATCH_LEVEL, но функция или драйвер фильтра может нуждаться в обработке IRP на уровне IRQL = PASSIVE_LEVEL. Чтобы вернуться к PASSIVE_LEVEL из подпрограммы IoCompletion , драйвер может использовать событие ядра. Драйвер регистрирует подпрограмму IoCompletion , которая задает событие в режиме ядра, а затем драйвер ожидает события в подпрограмме DispatchPnP . Когда событие установлено, более низкие драйверы завершили IRP, и драйвер может обрабатывать IRP.
Обратите внимание, что драйвер не должен использовать этот метод, чтобы ждать, пока более низкие драйверы не завершат обработку power IRP (IRP_MJ_POWER). Ожидание события в подпрограмме DispatchPower , заданной в подпрограмме IoCompletion , может привести к взаимоблокировке. Дополнительные сведения см. в разделе о передаче ip-адресов Power IRP .
На следующих двух рисунках показан пример того, как драйвер ожидает завершения PnP IRP драйверами более низкого уровня. В примере показано, что должны делать драйверы функций и шины, а также как они взаимодействуют с менеджером Plug and Play (PnP) и диспетчером ввода-вывода.
Следующие заметки соответствуют обведенным числам на предыдущем рисунке:
Диспетчер PnP вызывает диспетчер ввода-вывода для отправки IRP в самый верхний драйвер в стеке устройств.
Диспетчер ввода-вывода вызывает подпрограмму DispatchPnP верхнего драйвера. В этом примере есть только два драйвера в стеке устройств (драйвер-функция и драйвер родительской шины), а драйвер-функция является главным драйвером.
Драйвер функции объявляет и инициализирует событие режима ядра. Он настраивает расположение стека для драйвера, находящегося ниже по цепочке, и задает подпрограмму IoCompletion для этого IRP.
Драйвер функции может использовать IoCopyCurrentIrpStackLocationToNext для настройки расположения стека.
В вызове IoSetCompletionRoutine драйвер функции задает InvokeOnSuccess, InvokeOnError и InvokeOnCancel в TRUE и передает событие режима ядра в рамках параметра контекста.
Драйвер функции передает IRP вниз по стеку устройства с использованием IoCallDriver перед выполнением каких-либо операций для обработки IRP.
Диспетчер ввода-вывода отправляет IRP следующему ниже расположенному драйверу в стеке устройств, вызвав подпрограмму DispatchPnP драйвера.
Драйвер, расположенный ниже в этом примере, является самым нижним драйвером в стеке устройств, драйвером материнской шины. Драйвер устройства выполняет операции для запуска устройства. Драйвер шины задает Irp->IoStatus.Status, задает Irp->IoStatus.Information, если это относится к данному IRP, и завершает IRP, вызвав IoCompleteRequest.
Если драйвер шины вызывает другие подпрограммы драйвера или отправляет ввод-вывод на устройство, чтобы запустить его, он не завершает IRP PnP в своей подпрограмме DispatchPnP. Вместо этого он должен пометить IRP как ожидающий с помощью IoMarkIrpPending и вернуть STATUS_PENDING в своей подпрограмме DispatchPnP. Позже драйвер вызывает IoCompleteRequest из другой процедуры драйвера, возможно, подпрограмму DPC.
На следующем рисунке показана вторая часть примера, в которой более высокие драйверы в стеке устройств возобновляют их отложенную обработку IRP.
Следующие заметки соответствуют обведенным числам на предыдущем рисунке:
Когда драйвер шины вызывает IoCompleteRequest, диспетчер ввода-вывода проверяет расположения стека старших драйверов и вызывает все подпрограммы завершения IoCompletion, которые он находит. В этом примере диспетчер ввода-вывода находит и вызывает подпрограмму IoCompletion для следующего более высокого драйвера, функционального драйвера.
Подпрограмма IoCompletion драйвера функции задает событие в режиме ядра, предоставленное в параметре контекста, и возвращает STATUS_MORE_PROCESSING_REQUIRED.
Подпрограмма IoCompletion должна возвращать STATUS_MORE_PROCESSING_REQUIRED, чтобы диспетчер операций ввода-вывода не вызывал подпрограммы IoCompletion , заданные более высокими драйверами в настоящее время. Подпрограмма IoCompletion использует это состояние, чтобы задержать завершение, так как подпрограмма DispatchPnP драйвера может восстановить контроль. Диспетчер операций ввода-вывода возобновит вызов процедур завершения IoCompletion драйверов более высокого уровня для этого IRP, когда подпрограмма DispatchPnP этого драйвера завершит IRP.
Диспетчер ввода-вывода прекращает завершение IRP и возвращает управление подпрограмме, которая вызвала IoCompleteRequest, а в этом примере это подпрограмма DispatchPnP драйвера шины.
Драйвер шины возвращается из подпрограммы DispatchPnP с состоянием, указывающим результат обработки IRP: STATUS_SUCCESS или состояние ошибки.
IoCallDriver возвращает управление своему вызывающему, которым в этом примере является подпрограмма DispatchPnP драйвера функции.
Подпрограмма DispatchPnP драйвера функции возобновляет обработку IRP.
Если IoCallDriver возвращает STATUS_PENDING, подпрограмма DispatchPnP возобновила выполнение до вызова подпрограммы IoCompletion . Таким образом, подпрограмма DispatchPnP должна ожидать, пока событие ядра будет сигнализировать его подпрограммой IoCompletion . Это гарантирует, что подпрограмма DispatchPnP не будет продолжать обработку IRP до тех пор, пока все нижележащие драйверы его не завершат.
Если для Irp-IoStatus.Status> установлен статус ошибки, более низкий драйвер отклонил IRP из-за ошибки, и функциональный драйвер не должен продолжать обработку IRP (за исключением необходимой очистки).
После того как драйверы более низкого уровня успешно завершат обработку IRP, драйвер функции обрабатывает IRP.
Для IRPs, которые сначала обрабатываются драйвером родительской шины, драйвер шины обычно устанавливает успешный статус в Irp-IoStatus.Status и при необходимости задает значение в Irp-IoStatus.Information. Драйверы функций и фильтров оставляют значения в IoStatus , как только они не завершаются ошибкой IRP.
Подпрограмма DispatchPnP функционального драйвера вызывает IoCompleteRequest для завершения обработки IRP. Диспетчер ввода-вывода возобновляет обработку ввода-вывода. В этом примере нет драйверов фильтров над драйвером-функцией и, следовательно, больше не требуется вызывать подпрограммы IoCompletion . Когда IoCompleteRequest возвращает управление подпрограмме DispatchPnP драйвера функции, подпрограмма DispatchPnP возвращает состояние.
Для некоторых IRP, если драйвер функции или фильтра завершает IRP сбоем на обратном пути по стеку устройств, диспетчер PnP информирует нижележащие драйверы. Например, если функция или драйвер фильтра завершается ошибкой IRP_MN_START_DEVICE, диспетчер PnP отправляет IRP_MN_REMOVE_DEVICE в стек устройств.