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


Обработка запроса IRP_MN_SURPRISE_REMOVAL

Диспетчер Windows 2000 и более поздних версий PnP отправляет этот IRP для уведомления драйверов о том, что устройство больше не доступно для операций ввода-вывода и, вероятно, неожиданно удалено с компьютера ("неожиданное удаление").

Диспетчер PnP отправляет запрос IRP_MN_SURPRISE_REMOVAL по следующим причинам:

  • Если в шине есть уведомление о горячем модуле, он уведомляет родительского водителя шины устройства о том, что устройство исчезло. Водитель автобуса вызывает IoInvalidateDeviceRelations. В ответ менеджер PnP запрашивает водителя шины для своих детей (IRP_MN_QUERY_DEVICE_RELATIONS для BusRelations). Диспетчер PnP определяет, что устройство не находится в новом списке дочерних устройств и инициирует операции его неожиданного удаления.

  • Шина перечисляется по другой причине, и устройство, удаляемое сюрпризом, не входит в список дочерних элементов. Диспетчер PnP инициирует операции по внезапному удалению.

  • Функциональный драйвер устройства определяет, что устройство больше не присутствует (так как, например, его запросы многократно не выполняются). Шина может быть перечислена, но у нее нет уведомления о горячем подключении. В этом случае драйвер функции вызывает IoInvalidateDeviceState. В ответ диспетчер PnP отправляет запрос IRP_MN_QUERY_PNP_DEVICE_STATE в стек устройств. Драйвер функции задает флаг PNP_DEVICE_FAILED в битовой маске PNP_DEVICE_STATE , указывающий на сбой устройства.

  • Стек драйверов успешно завершает запрос IRP_MN_STOP_DEVICE, но затем не справляется с выполнением последующего запроса IRP_MN_START_DEVICE. В таких случаях устройство, вероятно, все еще подключено.

Все драйверы PnP должны обрабатывать этот IRP и должны задать для Irp-IoStatus.Status> значение STATUS_SUCCESS. Драйвер для устройства PnP должен быть готов к обработке IRP_MN_SURPRISE_REMOVAL в любое время после вызова подпрограммы AddDevice драйвера. Правильная обработка IRP позволяет драйверам и диспетчеру PnP:

  1. Отключите устройство, если оно по-прежнему подключено.

    Если стек драйверов успешно завершил запрос IRP_MN_STOP_DEVICE , но по какой-то причине произошел сбой последующего запроса IRP_MN_START_DEVICE , устройство должно быть отключено.

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

    Как только устройство больше не доступно, его аппаратные ресурсы должны быть освобождены. Затем диспетчер PnP может переназначить ресурсы другому устройству, включая то же устройство, которое пользователь может снова подключиться к компьютеру.

  3. Свести к минимуму риск потери данных и нарушения системы.

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

Диспетчер PnP отправляет IRP_MN_SURPRISE_REMOVAL на уровне IRQL = PASSIVE_LEVEL в контексте системного процесса.

Диспетчер PnP отправляет этот IRP драйверам прежде чем уведомить приложения в пользовательском режиме и другие компоненты режима ядра. После завершения IRP диспетчер PnP отправляет уведомление EventCategoryTargetDeviceChange с GUID_TARGET_DEVICE_REMOVE_COMPLETE в компоненты, работающие в режиме ядра, которые зарегистрированы для такого уведомления на устройстве.

IRP_MN_SURPRISE_REMOVAL IRP обрабатывается сначала верхним драйвером в стеке устройств, а затем каждым следующим нижним драйвером.

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

  1. Определите, удалено ли устройство.

    Драйвер должен всегда пытаться определить, подключено ли устройство. Если это так, драйвер должен попытаться остановить устройство и отключить его.

  2. Освободить аппаратные ресурсы устройства (прерывания, порты ввода-вывода, регистры памяти и каналы DMA).

  3. В родительском устройстве шины отключите слот шины, если устройство может это сделать. Вызовите PoSetPowerState, чтобы уведомить диспетчер питания. Для получения дополнительной информации см. Управление питанием.

  4. Запретить новые операции ввода-вывода на устройстве.

    Драйвер должен обрабатывать последующие IRP_MJ_CLEANUP, IRP_MJ_CLOSE, IRP_MJ_POWER и IRP_MJ_PNP запросов, но драйвер должен предотвратить любые новые операции ввода-вывода. Драйвер должен завершиться сбоем последующих операций IRP, которые драйвер обрабатывал бы, если бы устройство присутствовало, помимо закрытия, очистки и PnP IRPs.

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

  5. Отклонить невыполненные запросы ввода-вывода на устройстве.

  6. Продолжайте передавать любые запросы ввода-вывода (IRPs), которые драйвер не обрабатывает для устройства.

  7. Отключите интерфейсы устройств с помощью IoSetDeviceInterfaceState.

  8. Очистите выделения, связанные с устройствами, памятью, событиями или другими системными ресурсами.

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

  9. Оставьте объект устройства подключенным к стеку устройств.

    Не отсоединяйте и не удаляйте объект устройства до последующего запроса IRP_MN_REMOVE_DEVICE .

  10. Завершите IRP.

    В функции или драйвере фильтра:

    • Задайте значение Irp->IoStatus.Status на STATUS_SUCCESS.

    • Настройте следующее расположение стека с помощью IoSkipCurrentIrpStackLocation и передайте IRP следующему нижнему драйверу с помощью IoCallDriver.

    • Распространите состояние из IoCallDriver как возвращаемого состояния из подпрограммы DispatchPnP.

    • Не завершайте IRP.

    В водителе автобуса (который обрабатывает этот IRP для дочернего PDO):

    • Задайте значение Irp->IoStatus.Status на STATUS_SUCCESS.

    • Завершите IRP (IoCompleteRequest) с IO_NO_INCREMENT.

    • Вернитесь из подпрограммы DispatchPnP.

После успешного выполнения этого IRP и закрытия всех открытых дескрипторов на устройство диспетчер PnP отправляет запрос IRP_MN_REMOVE_DEVICE в стек устройств. В ответ на удаление IRP драйверы отсоединяют объекты устройства от стека и удаляют их. Если устаревший компонент имеет дескриптор, открытый для устройства, и он оставляет дескриптор открытым, несмотря на сбои ввода-вывода, диспетчер PnP никогда не отправляет удаление IRP.

Все драйверы должны обрабатывать этот IRP и должны отметить, что устройство физически удалено с компьютера. Однако некоторые драйверы не будут вызывать неблагоприятные результаты, если они не обрабатывают IRP. Например, устройство, которое не использует системные аппаратные ресурсы и находится на шине на основе протокола, например USB или 1394, не может связать аппаратные ресурсы, так как он не потребляет никаких. Нет риска, что драйверы попытаются получить доступ к устройству после его удаления, так как функциональные и фильтрующие драйверы получают доступ к устройству только через родительский драйвер шины. Так как шина поддерживает уведомление об удалении, драйвер родительской шины уведомляется, когда устройство исчезает, и водитель шины завершает все последующие попытки доступа к устройству.

В Windows 98/Me диспетчер PnP не отправляет этот IRP. Если пользователь удаляет устройство без первого использования соответствующего пользовательского интерфейса, диспетчер PnP отправляет только запрос IRP_MN_REMOVE_DEVICE драйверам устройства. Все драйверы WDM должны обрабатывать IRP_MN_SURPRISE_REMOVAL и IRP_MN_REMOVE_DEVICE. Код для IRP_MN_REMOVE_DEVICE должен проверить, получал ли драйвер неожиданный IRP на удаление, и должен обрабатывать оба случая.

Использование GUID_REENUMERATE_SELF_INTERFACE_STANDARD

Интерфейс GUID_REENUMERATE_SELF_INTERFACE_STANDARD позволяет драйверу запрашивать переопределение и реинициализацию устройства.

Чтобы использовать этот интерфейс, отправьте IRP_MN_QUERY_INTERFACE IRP драйверу шины с помощью InterfaceType = GUID_REENUMERATE_SELF_INTERFACE_STANDARD. Драйвер шины предоставляет указатель на структуру REENUMERATE_SELF_INTERFACE_STANDARD, содержащую указатели на отдельные процедуры интерфейса. Подпрограмма ReenumerateSelf запрашивает, чтобы водитель шины повторно распознал дочернее устройство.

О PNP_DEVICE_STATE

Тип PNP_DEVICE_STATE — это битовая маска, описывающая состояние PnP устройства. Драйвер возвращает значение этого типа в ответ на запрос IRP_MN_QUERY_PNP_DEVICE_STATE .

typedef ULONG PNP_DEVICE_STATE, *PPNP_DEVICE_STATE;

Биты флага в значении PNP_DEVICE_STATE определяются следующим образом.

Бит флага Описание
УСТРОЙСТВО_PNP_ОТКЛЮЧЕНО

Устройство физически присутствует, но отключено в оборудовании.

PNP_DEVICE_DONT_DISPLAY_IN_UI (Не отображать в пользовательском интерфейсе)

Не отображайте устройство в пользовательском интерфейсе. Установите для устройства, которое физически присутствует, но не может быть использовано в текущей конфигурации, например, игровой порт на ноутбуке, который невозможно использовать, когда ноутбук отсоединён от док-станции. (Также см. флаг NoDisplayInUI в структуре DEVICE_CAPABILITIES .)

PNP_УСТРОЙСТВО_НЕИСПРАВНО

Устройство присутствует, но не работает должным образом.

Если этот флаг и PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED заданы, устройство должно быть остановлено, прежде чем диспетчер PnP назначает новые аппаратные ресурсы (неконстантная перебалансировка не поддерживается для устройства).

УСТРОЙСТВО_PNP_НЕ_ОТКЛЮЧАЕМОЕ

Устройство требуется при запуске компьютера. Такое устройство не должно быть отключено.

Драйвер задает этот бит для устройства, необходимого для надлежащей системной операции. Например, если драйвер получает уведомление о том, что устройство находится в пути по страницам (IRP_MN_DEVICE_USAGE_NOTIFICATION для DeviceUsageTypePaging), драйвер вызывает IoInvalidateDeviceState и задает этот флаг в результате IRP_MN_QUERY_PNP_DEVICE_STATE запроса.

Если этот бит задан для устройства, диспетчер PnP передаёт эту настройку на родительское устройство данного устройства, на родительское устройство его родителя и так далее.

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

УСТРОЙСТВО_PNP_УДАЛЕНО

Устройство было физически удалено.

Требования к ресурсам устройства PNP изменены

Требования к ресурсам для устройства изменились.

Как правило, драйвер шины устанавливает этот флаг после того, как определит необходимость расширения требований к ресурсам для перечисления нового дочернего устройства.

PNP_DEVICE_DISCONNECTED

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

Водитель автобуса обычно не устанавливает этот флаг. Вместо этого водитель автобуса должен прекратить перечисление дочернего устройства, если устройство больше не подключено. Этот флаг используется только в том случае, если драйвер функции управляет подключением.

Единственной целью этого флага является предоставление клиентам сведений о том, подключено ли устройство. Установка флага не влияет на загрузку драйвера.

Диспетчер PnP запрашивает PNP_DEVICE_STATE устройства сразу после запуска устройства, отправив запрос IRP_MN_QUERY_PNP_DEVICE_STATE в стек устройств. В ответ на этот IRP драйверы устройства задают соответствующие флаги в PNP_DEVICE_STATE.

Если какие-либо характеристики состояния изменяются после первоначального запроса, драйвер уведомляет диспетчера PnP путем вызова IoInvalidateDeviceState. В ответ на вызов IoInvalidateDeviceState диспетчер PnP снова запрашивает PNP_DEVICE_STATE устройства.

Если устройство помечено PNP_DEVICE_NOT_DISABLEABLE, отладчик отображает флаг пользователя DNUF_NOT_DISABLEABLE для devnode. Отладчик также отображает значение DisableableDepends , которое подсчитывает количество причин, по которым устройство не может быть отключено. Это значение является суммой X+Y, где X является одной, если устройство не может быть отключено, и Y — количество дочерних устройств устройства, которые не могут быть отключены.