Добавление устройства PnP в запущенную систему
В этом разделе описывается последовательность событий, возникающих при настройке устройства PnP, добавленного пользователем на запущенный компьютер. В этом обсуждении освещаются роли диспетчера PnP, драйверов шины, функциональных драйверов и фильтров при детектировании и настройке нового устройства.
Большая часть этого обсуждения также относится к настройке устройства PnP, которое присутствует при загрузке компьютера. В частности, устройства, драйверы которых помечены в INF-файле как SERVICE_DEMAND_START, конфигурируются практически одинаково, независимо от того, добавляются ли они динамически или присутствуют при загрузке системы.
На следующем рисунке показаны первые шаги по настройке устройства, начиная с момента подключения оборудования к компьютеру.
Следующие заметки соответствуют обведенным числам на предыдущем рисунке:
Пользователь подключает устройство PnP к свободному слоту на шине PnP.
В этом примере пользователь подключает PnP USB-джойстик к концентратору, подключенному к USB-хост-контроллеру. USB-концентратор — это устройство PnP, поскольку к нему могут быть подключены дочерние устройства.
Функциональный драйвер для шины устройства определяет, что новое устройство подключено к его шине.
Как водитель определяет это, зависит от архитектуры шины. Для некоторых автобусов драйвер функции шины получает уведомление о новых устройствах при горячем подключении. Если шина не поддерживает уведомление о подключении оборудования, пользователь должен принять соответствующие меры в панели управления, чтобы шина была переопределена.
В этом примере шина USB поддерживает уведомления о горячей замене, поэтому функциональный драйвер для шины USB уведомляется о том, что его дочерние элементы изменились.
Функциональный драйвер для устройства шины уведомляет диспетчера PnP о том, что состав его дочерних устройств изменился.
Драйвер функции уведомляет диспетчера PnP путем вызова IoInvalidateDeviceRelations с типомBusRelations.
Диспетчер PnP запрашивает драйверы шины о текущем списке устройств на шине.
Диспетчер PnP отправляет запрос IRP_MN_QUERY_DEVICE_RELATIONS в стек устройств для шины. Значение parameters.QueryDeviceRelations.Type BusRelations, указывающее, что диспетчер PnP запрашивает текущий список устройств, присутствующих на шине (связи шины).
Диспетчер PnP отправляет IRP верхнему драйверу в стеке драйверов устройств для шины. В соответствии с правилами PnP IRPs каждый драйвер в стеке обрабатывает IRP, при необходимости и передает IRP до следующего драйвера.
Драйвер функции для устройства шины обрабатывает IRP.
См. справочную страницу для IRP_MN_QUERY_DEVICE_RELATIONS, для подробных сведений об обработке этого IRP.
В этом примере драйвер USB-концентратора обрабатывает этот IRP для концентратора FDO. Драйвер концентратора создает PDO для устройства джойстика и включает указатель на PDO джойстика в своем списке дочерних устройств, возвращенных с помощью IRP.
Когда родительский драйвер шины USB-концентратора (класс контроллера USB или пара драйверов миникласса) завершает IRP, IRP перемещается обратно вверх по стеку устройств с помощью любых IoCompletion рутин, зарегистрированных драйверами концентратора.
Обратите внимание, что драйвер функции шины сообщает об изменении списка дочерних элементов, запрашивая запрос диспетчера PnP к списку дочерних устройств. Полученный запрос IRP_MN_QUERY_DEVICE_RELATIONS видно всем драйверам для устройств шины. Как правило, драйвер шины – это единственный драйвер, который обрабатывает IRP и сообщает о дочерних устройствах. В некоторых стеках устройств драйвер фильтра шины присутствует и участвует в создании списка связей шины. Одним из примеров является ACPI, который подключается в качестве драйвера фильтра шины для устройств ACPI. В некоторых стеках устройств не относящиеся к шине драйверы фильтров обрабатывают запрос IRP_MN_QUERY_DEVICE_RELATIONS, что является нетипичным.
На этом этапе диспетчер PnP имеет текущий список устройств в шине. Затем диспетчер PnP определяет, были ли недавно доставлены какие-либо устройства или были удалены. В этом примере существует одно новое устройство. На следующем рисунке показан диспетчер PnP, создающий devnode для нового устройства и начинающий настраивать устройство.
Следующие заметки соответствуют обведенным числам на предыдущем рисунке:
Диспетчер PnP создает devnodes для любых новых дочерних устройств на шине.
Диспетчер PnP сравнивает список связей шины, возвращенных в IRP_MN_QUERY_DEVICE_RELATIONS IRP, со списком дочерних элементов шины, записанных в дереве устройств PnP. Диспетчер PnP создает devnode для каждого нового устройства и инициирует процесс удаления для всех устройств, которые уже были удалены.
В этом примере есть одно новое устройство (джойстик), поэтому диспетчер PnP создает devnode для джойстика. На этом этапе единственным драйвером, настроенным для джойстика, является родительский драйвер шины USB-концентратора, который создал PDO джойстика. Все необязательные драйверы фильтров для шины также будут присутствовать в стеке устройств, но в этом примере они опущены для упрощения.
Широкая стрелка между двумя devnodes на предыдущем рисунке указывает, что джойстик devnode является дочерним элементом USB-концентратора devnode.
Диспетчер PnP собирает сведения о новом устройстве и начинает настройку устройства.
Диспетчер PnP отправляет последовательность IRP в стек устройств для сбора сведений об устройстве. На этом этапе стек устройств состоит только из PDO, созданного родительским драйвером шины устройства, и фильтрующих DO для любых дополнительных драйверов фильтров шины. Таким образом, драйверы шины и драйверы фильтров шины являются единственными драйверами, которые реагируют на эти IRPs. В этом примере единственным драйвером в стеке устройств джойстика является родительский драйвер шины, драйвер USB-концентратора.
Диспетчер PnP собирает сведения о новом устройстве, отправляя IRPs в стек устройств. К этим IRPs относятся следующие:
IRP_MN_QUERY_ID— отдельный идентификатор IRP для каждого из следующих типов идентификаторов оборудования:
- BusQueryDeviceID
- BusQueryInstanceID
- BusQueryHardwareIDs
- BusQueryCompatibleIDs
- BusQueryContainerID
IRP_MN_QUERY_DEVICE_TEXT— отдельная IRP для каждого из следующих элементов:
- DeviceTextDescription
- DeviceTextLocationInformation
Диспетчер PnP отправляет указанные выше irPs на этом этапе обработки нового устройства PnP, но не обязательно в указанном порядке, поэтому не следует делать предположения о порядке отправки IRP. Кроме того, не следует предполагать, что диспетчер PnP отправляет только те IRPs, которые указаны выше.
Диспетчер PnP проверяет реестр, чтобы определить, установлено ли устройство на этом компьютере ранее. Диспетчер PnP проверяет
наличие перечислителя \ идентификатора устройства для устройства в ветви перечисления . В этом примере устройство является новым и должно быть настроено "с нуля".Диспетчер PnP хранит сведения об устройстве в реестре.
Ветвь перечисления реестра зарезервирована для использования компонентами операционной системы, и ее структура может изменяться в будущем. Разработчики драйверов должны использовать системные подпрограммы для извлечения информации, связанной с драйверами. Не обращайтесь непосредственно к ветке Enum из драйвера. Следующая информация о перечислении указана только для целей отладки.
Диспетчер PnP создает подраздел для устройства в разделе ключа перечислителя этого устройства.
Диспетчер PnP создает подраздел с именем HKLM\System\CurrentControlSet\Enum\<enumerator>\<deviceID>. Он создает перечислитель <и подраздел>, если они еще не существуют.
Перечислитель — это компонент, который обнаруживает устройства PnP на основе стандарта оборудования PnP. Задачи перечислителя выполняются водителем автобуса PnP в партнерстве с менеджером PnP. Устройство обычно перечисляется родительским драйвером шины, например PCI или PCMCIA. Некоторые устройства перечисляются драйвером фильтра шины, например ACPI.
Диспетчер PnP создает подключ для этого экземпляра устройства.
Если Capabilities.UniqueID возвращается как TRUE для IRP_MN_QUERY_CAPABILITIES, уникальный идентификатор устройства является уникальным в системе. Если нет, диспетчер PnP изменяет идентификатор таким образом, чтобы он был уникальным для всей системы.
Диспетчер PnP создает подраздел с именем HKLM\System\CurrentControlSet\Enum\<перечислитель>\<deviceID>\<instanceID>.
Диспетчер PnP записывает сведения об устройстве в подраздел для экземпляра устройства.
Диспетчер PnP хранит сведения, если они были предоставлены для устройства, включая следующие данные:
- DeviceDesc — от IRP_MN_QUERY_DEVICE_TEXT
- расположение — от IRP_MN_QUERY_DEVICE_TEXT
- возможности — флаги IRP_MN_QUERY_CAPABILITIES
- UINumber — из IRP_MN_QUERY_CAPABILITIES
- HardwareID — от IRP_MN_QUERY_ID
- совместимые идентификаторы — от IRP_MN_QUERY_ID
- ContainerID — из IRP_MN_QUERY_ID
- LogConf\BootConfig — из IRP_MN_QUERY_RESOURCES
- LogConf\BasicConfigVector — из IRP_MN_QUERY_RESOURCE_REQUIREMENTS
На этом этапе диспетчер PnP готов найти драйвер функции и драйверы фильтров для устройства, если таковые есть. (См. следующий рисунок.)
Следующие заметки соответствуют нумерованным кругам на предыдущем рисунке:
Диспетчер PnP в режиме ядра координирует работу с диспетчером PnP пользовательского режима и компонентами настройки пользовательского режима, чтобы найти драйверы функций и фильтров для устройства, если есть какие-либо.
Менеджер PnP в режиме ядра ставит событие в очередь для менеджера PnP пользовательского режима, чтобы определить устройство, которое нужно установить. После входа привилегированного пользователя компоненты пользовательского режима продолжают поиск драйверов. Сведения о компонентах установки и их роли при установке устройства см. в Установка устройств и драйверов.
Компоненты установки в пользовательском режиме направляют диспетчер PnP режима ядра на загрузку функциональных и фильтрующих драйверов.
Компоненты пользовательского режима вызывают режим ядра для загрузки драйверов, что приводит к вызову процедур AddDevice.
На следующем рисунке показано, как диспетчер PnP загружает драйверы (при необходимости), вызывая их подпрограммы AddDevice, и указывает драйверам запустить устройство.
Следующие заметки соответствуют нумерованным кругам на предыдущем рисунке:
Драйверы нижнего фильтра
Прежде чем драйвер функции подключается к стеку устройств, диспетчер PnP обрабатывает все драйверы более низкого фильтра. Для каждого драйвера нижнего фильтра диспетчер PnP вызывает driverEntry подпрограмму driverEntry, если драйвер еще не загружен. Затем диспетчер PnP вызывает процедуру AddDevice. В подпрограмме AddDevice драйвер фильтра создает объект устройства фильтра (DO фильтра) и присоединяет его к стеку устройств (IoAttachDeviceToDeviceStack). После подключения объекта устройства к стеку устройств драйвер участвует в качестве драйвера для устройства.
В примере usb-джойстика существует один драйвер нижнего фильтра для устройства.
Драйвер функции
После соединения всех нижних фильтров диспетчер PnP обрабатывает драйвер функции. Диспетчер PnP вызывает подпрограмму функционального драйвера DriverEntry, если драйвер еще не загружен, и вызывает подпрограмму AddDevice функционального драйвера. Драйвер функции создает объект устройства функции (FDO) и присоединяет его к стеку устройств.
В этом примере драйвер функции для USB-джойстика фактически является парой драйверов: драйвер класса HID и драйвер миникласса HID. Два драйвера работают вместе, чтобы служить драйвером функции. Пара драйверов создает только один FDO и присоединяет его к стеку устройств.
Драйверы верхнего фильтра
После присоединения драйвера функции диспетчер PnP обрабатывает все драйверы верхнего фильтра.
В этом примере существует один драйвер верхнего фильтра для устройства.
Назначение ресурсов и запуск устройства
При необходимости диспетчер PnP назначает ресурсы устройству и выдает IRP для запуска устройства.
Назначение ресурсов
Ранее в процессе настройки диспетчер PnP собрал требования к оборудованию для устройства из родительского драйвера шины устройства. После загрузки полного набора драйверов для устройства диспетчер PnP отправляет запрос IRP_MN_FILTER_RESOURCE_REQUIREMENTS на стек устройств. Все драйверы в стеке имеют возможность обрабатывать этот IRP и изменять список требований к ресурсам устройства при необходимости.
Диспетчер PnP назначает ресурсы устройству, если они требуются, в зависимости от требований устройства и доступных в данный момент ресурсов.
Диспетчер PnP может потребовать переупорядочения назначений ресурсов существующих устройств для удовлетворения потребностей нового устройства. Это переназначение ресурсов называется "перебалансирование". Драйверы для существующих устройств получают последовательность остановки и запуска IRP во время перебаланса, но перебалансация должна быть прозрачной для пользователей.
В примере USB-джойстика USB-устройства не требуют аппаратных ресурсов, поэтому диспетчер PnP задает список ресурсов для NULL.
Запуск устройства (IRP_MN_START_DEVICE)
Когда диспетчер PnP назначает ресурсы устройству, он отправляет IRP_MN_START_DEVICE IRP в стек устройств, чтобы направить драйверы для запуска устройства.
После запуска устройства диспетчер PnP отправляет три дополнительных IRP драйверам для устройства:
-
После успешного завершения IRP запуска диспетчер PnP отправляет другой IRP_MN_QUERY_CAPABILITIES IRP в стек устройств. Все драйверы для устройства имеют возможность обработки IRP. Диспетчер PnP отправляет этот IRP в это время, после подключения всех драйверов и запуска устройства, так как функциональным или фильтрующим драйверам может понадобиться доступ к устройству для сбора информации о его функциональных возможностях.
-
Этот IRP дает драйверу возможность, например, сообщить, что устройство не должно отображаться в пользовательских интерфейсах, таких как Диспетчер устройств и программа Hotplug. Это полезно для устройств, которые присутствуют в системе, но недоступны для использования в текущей конфигурации, например игровой порт на ноутбуке, который не подходит для использования, когда ноутбук откреплен.
IRP_MN_QUERY_DEVICE_RELATIONS для отношений с автобусом
Диспетчер PnP отправляет этот IRP, чтобы определить, имеет ли устройство какие-либо дочерние устройства. В этом случае диспетчер PnP настраивает каждое дочернее устройство.
Использование интерфейса GUID_PNP_LOCATION_INTERFACE
Интерфейс GUID_PNP_LOCATION_INTERFACE предоставляет свойство устройства SPDRP_LOCATION_PATHS Plug and Play (PnP) для устройства.
Чтобы реализовать этот интерфейс в драйвере, обработайте IRP_MN_QUERY_INTERFACE IRP с помощью InterfaceType = GUID_PNP_LOCATION_INTERFACE. Драйвер предоставляет указатель на структуру PNP_LOCATION_INTERFACE, содержащую указатели на отдельные подпрограммы интерфейса. Подпрограмма PnpGetLocationString предоставляет часть свойства устройства SPDRP_LOCATION_PATHS, специфичную для данного устройства.