Обработка запроса IRP_MN_QUERY_STOP_DEVICE (Windows 2000 и более поздних версий)
Запрос IRP_MN_QUERY_STOP_DEVICE обрабатывается сначала верхним драйвером в стеке устройств, а затем каждым следующим более низким драйвером. Драйвер обрабатывает остановку IRP в своей подпрограмме DispatchPnP .
В ответ на IRP_MN_QUERY_STOP_DEVICE драйвер должен выполнить следующие действия:
Определите, можно ли остановить устройство и освободить ли его аппаратные ресурсы без негативных последствий.
Драйвер должен завершить запрос на ошибку, если выполняется одно из следующих действий:
Драйвер получил уведомление (через IRP_MN_DEVICE_USAGE_NOTIFICATION), что устройство находится в пути к файлу подкачки, гибернации или аварийного дампа.
Аппаратные ресурсы устройства не могут быть освобождены.
Драйвер может завершиться ошибкой запроса при выполнении запроса, если верно следующее:
Драйвер не должен удалять запросы ввода-вывода и не имеет механизма для постановки в очередь irP.
Пока устройство находится в остановленном состоянии, драйвер должен содержать irP, которым требуется доступ к устройству. Если драйвер не помещает в очередь irP, он не должен разрешать остановку устройства и, следовательно, должен завершать запрос.
Исключением из этого правила является устройство, которое может удалять ввод-вывод. Драйверы для такого устройства могут успешно выполнять запросы на остановку и остановку запросов без очередей irP.
Если устройство не может быть остановлено, завершите запрос.
Задайте для Irp-IoStatus.Status> соответствующее состояние ошибки, вызовите IoCompleteRequest с IO_NO_INCREMENT и вернитесь из подпрограммы DispatchPnP драйвера. Не передавайте IRP следующему нижнему драйверу.
Если устройство может быть остановлено и драйвер помещает в очередь irP, установите флаг HOLD_NEW_REQUESTS в расширении устройства, чтобы последующие irP были поставлены в очередь (см. раздел Удержание входящих irPs при приостановке устройства).
Кроме того, драйверы для устройства могут отложить полную приостановку устройства до тех пор, пока драйверы не получат последующий запрос IRP_MN_STOP_DEVICE . Такие водители, однако, должны ставить в очередь все запросы, которые помешают им немедленно выполнить остановку IRP по прибытии. До перезапуска устройства такие драйверы должны помещать в очередь следующие запросы:
IRP_MN_DEVICE_USAGE_NOTIFICATION запросы (например, чтобы поместить файл подкачки на устройство).
Запросы на изохронную передачу.
Создавайте запросы, которые помешают драйверам успешно выполнять остановку IRP.
Если устройство не может выполнить IRP, убедитесь, что все невыполненные запросы, переданные в другие подпрограммы драйвера и в более низкие драйверы, выполнены.
Один из способов, которыми драйвер может достичь этого, заключается в использовании счетчика ссылок и события, чтобы убедиться, что все запросы завершены:
В своей подпрограмме AddDevice драйвер определяет количество ссылок ввода-вывода в расширении устройства и инициализирует счетчик единицей.
Кроме того, в своей подпрограмме AddDevice драйвер создает событие с помощью KeInitializeEvent и инициализирует событие в состоянии Not-Signaled с помощью KeClearEvent.
Каждый раз при обработке IRP драйвер увеличивает количество ссылок с помощью InterlockedIncrement.
Каждый раз, когда выполняется запрос, драйвер уменьшает количество ссылок с помощью InterlockedDecrement.
Драйвер уменьшает количество ссылок в подпрограмме IoCompletion , если запрос имеет ее, или сразу после вызова IoCallDriver , если драйвер не использует подпрограмму IoCompletion для запроса.
Когда драйвер получает IRP_MN_QUERY_STOP_DEVICE, он уменьшает количество ссылок с interlockedDecrement. Если невыполненные запросы отсутствуют, количество ссылок уменьшается до нуля.
Когда число ссылок достигает нуля, драйвер задает событие с keSetEvent, сигналив о том, что код остановки запроса может продолжаться.
В качестве альтернативы описанной выше процедуре драйвер может сериализовать IRP_MN_QUERY_STOP_DEVICE IRP за любыми выполняющиеся IRP.
Выполните все остальные действия, необходимые для того, чтобы поместить устройство в состояние ожидания остановки.
После успешного выполнения запроса драйвер должен быть готов к успешному выполнению IRP_MN_STOP_DEVICE.
Завершите IRP.
В драйвере функции или фильтра:
Задайте для Irp-IoStatus.Status> значение STATUS_SUCCESS.
Настройте следующее расположение стека с помощью IoSkipCurrentIrpStackLocation и передайте IRP следующему более низкому драйверу с помощью IoCallDriver.
Распространение состояния из IoCallDriver в качестве состояния возврата из подпрограммы DispatchPnP .
Не завершайте IRP.
В водителе автобуса:
Задайте для Irp-IoStatus.Status> значение STATUS_SUCCESS.
Однако если устройства в шине используют аппаратные ресурсы, переоцените требования к ресурсам шины и дочерних устройств. Если какое-либо из требований изменилось, верните STATUS_RESOURCE_REQUIREMENTS_CHANGED вместо STATUS_SUCCESS. Это состояние указывает на успешное выполнение, но запрашивает, чтобы диспетчер PnP повторно запрашивал ресурсы перед отправкой останова IRP.
Завершите IRP (IoCompleteRequest) IO_NO_INCREMENT.
Возвращается из подпрограммы DispatchPnP .
Если какой-либо драйвер в стеке устройств не выполняет IRP_MN_QUERY_STOP_DEVICE, диспетчер PnP отправляет IRP_MN_CANCEL_STOP_DEVICE в стек устройств. Это предотвращает, чтобы драйверы не требовали подпрограмму IoCompletion для IRP остановки запроса, чтобы определить, не удалось ли драйверу более низкого уровня IRP.