Динамическое перечисление
Динамическое перечисление — это способность драйвера обнаруживать и сообщать об изменениях в количестве и типе устройств, подключенных к системе во время работы системы.
Драйверы шины должны использовать динамическое перечисление, если количество или типы устройств, подключенных к родительскому устройству, зависят от конфигурации системы. Некоторые из этих устройств могут быть всегда подключены к системе, а некоторые могут быть подключены и отключены во время работы системы.
Например, количество и тип устройств, подключенных к шине PCI системы, зависят от системы, но они являются постоянными, если пользователь не отключает питание, не открывает дело и не добавляет или удаляет устройство с помощью отвертки. С другой стороны, пользователь может добавлять или удалять USB-устройства, подключая или отключая кабель во время работы системы.
Динамические дочерние списки
Платформа позволяет драйверам поддерживать динамическое перечисление, предоставляя дочерние объекты платформы. Каждый дочерний объект представляет список дочерних устройств, подключенных к родительскому устройству. Драйвер шины для родительского устройства должен определить дочерние устройства родительского устройства, добавить их в список дочерних устройств и создать объект физического устройства (PDO) для каждого дочернего устройства.
Каждый раз, когда драйвер создает объект устройства платформы, представляющий FDO для устройства, платформа создает пустой дочерний список по умолчанию для устройства. Драйвер может получить дескриптор дочернего списка устройства по умолчанию, вызвав WdfFdoGetDefaultChildList. Как правило, если вы пишете драйвер автобуса, который перечисляет дочерние элементы устройства, ваш водитель может добавить дочерних элементов в список дочерних элементов по умолчанию. Если необходимо создать дополнительные дочерние списки, драйвер может вызвать WdfChildListCreate.
Прежде чем драйвер сможет использовать дочерний список, он должен настроить объект дочернего списка путем инициализации структуры WDF_CHILD_LIST_CONFIG и передачи структуры в WdfFdoInitSetDefaultChildListConfig для дочернего списка по умолчанию или в WdfChildListCreate для дополнительных дочерних списков.
Динамические дочерние описания
Каждый раз, когда водитель автобуса определяет дочернее устройство, он должен добавлять описание дочернего устройства в список дочерних устройств. Дочернее описание состоит из обязательного описания идентификации и необязательного описания адреса.
Описание идентификации Описание идентификации — это структура, содержащая сведения, однозначно определяющие каждое устройство, перечисленное драйвером. Драйвер определяет эту структуру, но его первым элементом должна быть структура WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER .
Как правило, описание идентификации содержит строки идентификации устройства, возможно, серийный номер и сведения о расположении устройства в шине, например номер слота.
Драйвер может предоставить следующий набор функций обратного вызова, которые позволяют платформе управлять информацией в описании идентификации:
EvtChildListIdentificationDescriptionCompare, который сравнивает содержимое двух структур описания идентификации.
EvtChildListIdentificationDescriptionCopy, копирующий содержимое одной структуры описания идентификации в другую.
EvtChildListIdentificationDescriptionDuplicate, который создает новое описание идентификации путем дублирования существующей структуры описания идентификации и, при необходимости, выделения дополнительных буферов.
EvtChildListIdentificationDescriptionCleanup, который освобождает буферы, выделенные функцией обратного вызова EvtChildListIdentificationDescriptionDuplicate .
Как правило, эти функции обратного вызова необходимо предоставить, если структуры описания идентификации драйвера содержат указатели на динамически выделенные буферы. Дополнительные сведения о назначении этих функций обратного вызова см. на их справочных страницах.
Описание адреса Описание адреса — это структура, содержащая сведения, необходимые водителю для доступа к устройству на шине, если данные могут измениться во время подключения устройства. Драйвер определяет эту структуру, но его первым элементом должна быть WDF_CHILD_ADDRESS_DESCRIPTION_HEADER структура.
Описания адресов являются необязательными. Если сведения об адресе устройства не могут измениться между временем подключения устройства и временем его отключения, все сведения об адресе устройства могут храниться в описании идентификации. Например, USB-контроллеры назначают адреса устройствам, когда устройства подключены, и эти адреса не меняются.
С другой стороны, некоторые автобусы используют адресную информацию, которая может измениться. Например, шина IEEE 1394 использует "число поколений", то есть количество выполненных сбросов шины. Каждый асинхронный запрос ввода-вывода к устройству IEEE 1394 должен включать число поколений. Так как эти сведения об адресе могут измениться, драйвер должен сохранить их в описании адреса.
Драйвер может предоставить следующий набор функций обратного вызова для управления информацией в описании адреса:
EvtChildListAddressDescriptionCopy, которая копирует содержимое одной структуры описания адреса в другую.
EvtChildListAddressDescriptionDuplicate, который создает новое описание адреса путем дублирования существующей структуры описания адреса и, при необходимости, выделения дополнительных буферов.
EvtChildListAddressDescriptionCleanup, который освобождает буферы, выделенные функцией обратного вызова EvtChildListAddressDescriptionDuplicate .
Как правило, эти функции обратного вызова необходимо предоставить, если структуры описания адресов драйвера содержат указатели на динамически выделенные буферы. Дополнительные сведения о назначении этих функций обратного вызова см. на их справочных страницах.
Добавление устройств в динамический дочерний список
Когда платформа вызывает функцию обратного вызова EvtDriverDeviceAdd водителя шины, функция обратного вызова должна вызвать WdfDeviceCreate , чтобы создать FDO для родительского устройства, которое обычно является адаптером шины. Дополнительные сведения о создании FDO см. в разделе Создание объектов устройств в драйвере функции. Затем драйвер должен перечислить дочерние элементы родительского устройства и добавить их в список дочерних элементов.
При необходимости драйвер может вызвать WdfDeviceSetBusInformationForChildren , чтобы предоставить платформе сведения о шине. Это рекомендуется, так как это упрощает идентификацию автобуса для дочерних устройств и приложений.
Чтобы добавить дочерние элементы в дочерний список, драйвер должен вызывать WdfChildListAddOrUpdateChildDescriptionAsPresent для каждого найденного дочернего устройства. Этот вызов информирует платформу о том, что драйвер обнаружил дочернее устройство, подключенное к родительскому устройству. Когда драйвер вызывает WdfChildListAddOrUpdateChildDescriptionAsPresent, он предоставляет описание идентификации и, при необходимости, описание адреса.
После того как драйвер вызывает WdfChildListAddOrUpdateChildDescriptionAsPresent , чтобы сообщить о новом устройстве, платформа сообщает диспетчеру PnP о том, что новое устройство существует. Затем диспетчер PnP создает стек устройств и стек драйверов для нового устройства. В рамках этого процесса платформа вызывает функцию обратного вызова EvtChildListCreateDevice водителя автобуса. Эта функция обратного вызова должна вызывать WdfDeviceCreate , чтобы создать PDO для нового устройства.
Как правило, к родительскому элементу подключено несколько дочерних устройств, поэтому драйверу автобуса потребуется несколько раз вызвать WdfChildListAddOrUpdateChildDescriptionAsPresent . Наиболее эффективным способом является следующее:
Вызовите WdfChildListBeginScan.
Вызовите WdfChildListAddOrUpdateChildDescriptionAsPresent для каждого дочернего устройства.
Вызовите WdfChildListEndScan.
Если динамическое перечисление драйвера заключено в вызовы WdfChildListBeginScan и WdfChildListEndScan, платформа сохраняет все изменения в дочернем списке и уведомляет диспетчер PnP об изменениях, когда драйвер вызывает WdfChildListEndScan. Позже платформа вызывает функцию обратного вызова EvtChildListCreateDevice водителя автобуса для каждого устройства в дочернем списке. Эта функция обратного вызова вызывает WdfDeviceCreate , чтобы создать PDO для каждого нового устройства.
Когда драйвер вызывает WdfChildListBeginScan, платформа помечает все ранее сообщаемые устройства как отсутствуют. Таким образом, драйвер должен вызывать WdfChildListAddOrUpdateChildDescriptionAsPresent для всех дочерних элементов, которые может обнаружить драйвер, а не только недавно обнаруженных дочерних элементов. Чтобы добавить одного дочернего элемента в дочерний список, драйвер может выполнить один вызов WdfChildListUpdateAllChildDescriptionsAsPresent без предварительного вызова WdfChildListBeginScan.
Обновление динамического дочернего списка
Существует два распространенных способа обновления сведений в динамическом дочернем списке.
Когда родительское устройство получает прерывание, указывающее на получение или удаление дочернего элемента, функция обратного вызова EvtInterruptDpc драйвера вызывает WdfChildListAddOrUpdateChildDescriptionAsPresent , если устройство подключено, или WdfChildListUpdateChildDescriptionAsMissing , если устройство было отсоединлено.
Драйвер может предоставить функцию обратного вызова EvtChildListScanForChildren , которую платформа вызывает каждый раз, когда родительское устройство переходит в рабочее состояние (D0). Эта функция обратного вызова должна перечислять все дочерние устройства, вызывая WdfChildListBeginScan, WdfChildListAddOrUpdateChildDescriptionAsPresent (или WdfChildListUpdateAllChildDescriptionsAsPresent) и WdfChildListEndScan.
Вы можете использовать один или оба этих метода в драйвере.
Обход динамического дочернего списка
Если вы хотите, чтобы драйвер проверял содержимое дочернего списка, он может просматривать список с помощью одного из следующих методов:
Чтобы получить содержимое описания каждого дочернего устройства по одному, драйвер может:
- Вызовите WdfChildListBeginIteration.
- Вызовите WdfChildListRetrieveNextDevice столько раз, сколько потребуется.
- Вызовите WdfChildListEndIteration.
При вызове WdfChildListBeginIteration драйвер задает WDF_RETRIEVE_CHILD_FLAGS типизированный флаг, который указывает, должна ли платформа получать все описания устройств или только подмножество. Когда WdfChildListRetrieveNextDevice находит совпадение, он получает идентификатор и описание адреса дочернего устройства, а также дескриптор объекта устройства.
Если необходимо получить описание адреса, которое в настоящее время содержится в описании дочернего устройства, драйвер может вызвать WdfChildListRetrieveAddressDescription, указав описание идентификации. Платформа просматривает дочерний список, пока не найдет дочернее устройство с соответствующим описанием идентификации, а затем извлекает описание адреса.
Если необходимо получить дескриптор объекта устройства платформы, связанного с определенным дочерним устройством, драйвер может вызвать WdfChildListRetrievePdo. Платформа просматривает дочерний список, пока не найдет дочернее устройство с соответствующим описанием идентификации, а затем возвращает дескриптор объекта устройства. Обязательно заключите вызов с помощью WdfChildListBeginIteration и WdfChildListEndIteration , чтобы защитить вызывающий объект от внезапного удаления PDO в другом потоке по PnP.
Доступ к описаниям идентификации и адреса PDO
Драйвер может вызывать следующие методы для доступа к описанию идентификации PDO или описанию адреса:
WdfPdoRetrieveIdentificationDescription, которое получает описание идентификации, связанное с PDO.
WdfPdoRetrieveAddressDescription, который получает описание адреса, связанное с PDO.
WdfPdoUpdateAddressDescription, которое обновляет описание адреса, связанное с PDO.
Обработка запросов на повторное перечисление
Драйверы шины на основе платформы, поддерживающие динамическое перечисление, могут получать запрос на повторную настройку определенного дочернего устройства через интерфейс REENUMERATE_SELF_INTERFACE_STANDARD . Дополнительные сведения см. в разделе Обработка запросов перечисления.