Поделиться через


Обработка запроса IRP_MN_QUERY_STOP_DEVICE (Windows 2000 и более поздних версий)

Запрос IRP_MN_QUERY_STOP_DEVICE обрабатывается сначала верхним драйвером в стеке устройств, а затем каждым следующим более низким драйвером. Драйвер обрабатывает остановку IRP в своей подпрограмме DispatchPnP .

В ответ на IRP_MN_QUERY_STOP_DEVICE драйвер должен выполнить следующие действия:

  1. Определите, можно ли остановить устройство и освободить ли его аппаратные ресурсы без негативных последствий.

    Драйвер должен завершить запрос на ошибку, если выполняется одно из следующих действий:

    • Драйвер получил уведомление (через IRP_MN_DEVICE_USAGE_NOTIFICATION), что устройство находится в пути к файлу подкачки, гибернации или аварийного дампа.

    • Аппаратные ресурсы устройства не могут быть освобождены.

    Драйвер может завершиться ошибкой запроса при выполнении запроса, если верно следующее:

    • Драйвер не должен удалять запросы ввода-вывода и не имеет механизма для постановки в очередь irP.

      Пока устройство находится в остановленном состоянии, драйвер должен содержать irP, которым требуется доступ к устройству. Если драйвер не помещает в очередь irP, он не должен разрешать остановку устройства и, следовательно, должен завершать запрос.

      Исключением из этого правила является устройство, которое может удалять ввод-вывод. Драйверы для такого устройства могут успешно выполнять запросы на остановку и остановку запросов без очередей irP.

  2. Если устройство не может быть остановлено, завершите запрос.

    Задайте для Irp-IoStatus.Status> соответствующее состояние ошибки, вызовите IoCompleteRequest с IO_NO_INCREMENT и вернитесь из подпрограммы DispatchPnP драйвера. Не передавайте IRP следующему нижнему драйверу.

  3. Если устройство может быть остановлено и драйвер помещает в очередь irP, установите флаг HOLD_NEW_REQUESTS в расширении устройства, чтобы последующие irP были поставлены в очередь (см. раздел Удержание входящих irPs при приостановке устройства).

    Кроме того, драйверы для устройства могут отложить полную приостановку устройства до тех пор, пока драйверы не получат последующий запрос IRP_MN_STOP_DEVICE . Такие водители, однако, должны ставить в очередь все запросы, которые помешают им немедленно выполнить остановку IRP по прибытии. До перезапуска устройства такие драйверы должны помещать в очередь следующие запросы:

    • IRP_MN_DEVICE_USAGE_NOTIFICATION запросы (например, чтобы поместить файл подкачки на устройство).

    • Запросы на изохронную передачу.

    • Создавайте запросы, которые помешают драйверам успешно выполнять остановку IRP.

  4. Если устройство не может выполнить 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.

  5. Выполните все остальные действия, необходимые для того, чтобы поместить устройство в состояние ожидания остановки.

    После успешного выполнения запроса драйвер должен быть готов к успешному выполнению IRP_MN_STOP_DEVICE.

  6. Завершите 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.