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


Динамическое перечисление

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

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

Например, количество и тип устройств, подключенных к шине 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 должен включать число поколений. Так как эти сведения об адресе могут измениться, драйвер должен хранить его в описании адреса.

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

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

Добавление устройств в динамический дочерний список

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

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

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

После вызова, выполненного драйвером, WdfChildListAddOrUpdateChildDescriptionAsPresent для сообщения о новом устройстве, платформа информирует PnP менеджера о том, что новое устройство существует. Диспетчер PnP создает стек устройств и стек драйверов для нового устройства. В рамках этого процесса платформа вызывает функцию обратного вызова драйвера шины EvtChildListCreateDevice. Эта функция обратного вызова должна вызывать WdfDeviceCreate для создания PDO для нового устройства.

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

  1. Вызов WdfChildListBeginScan.

  2. Вызов WdfChildListAddOrUpdateChildDescriptionAsPresent для каждого дочернего устройства.

  3. Вызов WdfChildListEndScan.

Если вы окружаете динамическое перечисление драйвера вызовами WdfChildListBeginScan и WdfChildListEndScan, фреймворк сохраняет все изменения в дочернем списке. Драйвер уведомляет диспетчера PnP об изменениях при вызове функции WdfChildListEndScan. В некоторый момент фреймворк вызывает функцию обратного вызова драйвера шины EvtChildListCreateDevice для каждого устройства в дочернем списке. Эта функция обратного вызова вызывает WdfDeviceCreate для создания PDO для каждого нового устройства.

Когда драйвер вызывает WdfChildListBeginScan, платформа помечает все ранее сообщаемые устройства как недоступные. Поэтому драйвер должен вызывать WdfChildListAddOrUpdateChildDescriptionAsPresent для всех детей, которые водитель может обнаружить, а не только недавно обнаруженных детей. Чтобы добавить один дочерний элемент в дочерний список, драйвер может выполнить вызов WdfChildListUpdateAllChildDescriptionsAsPresent, не вызывая сначала WdfChildListBeginScan.

Обновление динамического дочернего списка

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

  1. Когда родительское устройство получает прерывание, указывающее на прибытие или удаление ребенка, функция обратного вызова драйвера EvtInterruptDpc вызывает вызовы функции обратного вызова WdfChildListAddOrUpdateChildDescriptionAsPresent, если устройство подключено или WdfChildListUpdateChildDescriptionAsMissing, если устройство отключено.

  2. Драйвер может предоставить функцию обратного вызова EvtChildListScanForChildren, которую фреймворк вызывает каждый раз, когда родительское устройство переходит в рабочее состояние (D0). Эта функция обратного вызова должна перечислить все дочерние устройства путем вызова WdfChildListBeginScan, WdfChildListAddOrUpdateChildDescriptionAsPresent (или WdfChildListUpdateAllChildDescriptionsAsPresent) и WdfChildListEndScan.

Вы можете использовать один или оба этих метода в драйвере.

Обход динамического дочернего списка

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

  • Чтобы получить содержимое каждого дочернего описания устройства одновременно, драйвер может:

    1. Вызов WdfChildListBeginIteration.
    2. Вызовите WdfChildListRetrieveNextDeviceстолько раз, сколько необходимо.
    3. Вызов WdfChildListEndIteration.

    При вызове WdfChildListBeginIterationдрайвер задает флаг типа WDF_RETRIEVE_CHILD_FLAGS, указывающий, должен ли фреймворк получать все описания устройств или только их часть. Когда WdfChildListRetrieveNextDevice находит совпадение, он извлекает идентификатор и адресные описания дочернего устройства, а также предоставляет дескриптор для объекта этого устройства.

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

  • Если необходимо получить дескриптор объекта устройства фреймворка, связанного с определенным дочерним устройством, драйвер может вызвать WdfChildListRetrievePdo. Платформа проходит по дочернему списку, пока не найдет дочернее устройство с соответствующим описанием идентификации, а затем возвращает дескриптор объекта устройства. Чтобы защитить вызов от внезапного удаления PDO в другом потоке, заключите вызов с помощью WdfChildListBeginIteration и WdfChildListEndIteration.

Доступ к описаниям идентификации и адресов PDO

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

  • WdfPdoRetrieveIdentificationDescription, который получает описание идентификации, связанное с PDO.

  • WdfPdoRetrieveAddressDescription, который получает описание адреса, связанное с PDO.

  • WdfPdoUpdateAddressDescription, который обновляет описание адреса, связанного с PDO.

Обработка запросов повторной нумерации

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