Написание драйвера клиента контроллера функций
В этой статье описываются различные задачи, выполняемые драйвером клиента контроллера функций при взаимодействии с расширением контроллера функций USB (UFX).
Важные API
Описывает различные задачи, выполняемые драйвером клиента контроллера функций при взаимодействии с расширением контроллера функций USB (UFX). UFX и драйвер клиента взаимодействуют друг с другом с помощью методов экспорта и функций обратного вызова событий. Методы экспорта (с именем UfxDeviceXxx или UfxEndpointXxx) экспортируются UFX и вызываются клиентским драйвером. Функции обратного вызова (с именем EVT_UFX_Xxx) реализуются в драйвере клиента и вызываются UFX.
UFX вызывает все функции обратного вызова драйвера клиента асинхронно и по одному обратному вызову за раз для каждого объекта. Например, имеется объект USB-устройства и три объекта конечной точки. Одновременно можно вызывать не более четырех функций обратного вызова (по одной для устройства и по одной для каждой конечной точки). Для каждого метода обратного вызова UFX ожидает, пока драйвер клиента не вызовет UfxDeviceEventComplete , чтобы указать, что драйвер завершил запрос. Единственным другим методом экспорта, который UFX прослушивает во время ожидания этих экспортов, является UfxDeviceNotifyHardwareFailure. Многие функции обратного вызова клиента являются необязательными. Ниже перечислены обязательные функции.
- EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD
- EVT_UFX_DEVICE_ENDPOINT_ADD
- EVT_UFX_DEVICE_HOST_CONNECT
- EVT_UFX_DEVICE_HOST_DISCONNECT
- EVT_UFX_DEVICE_ADDRESSED
Инициализация
- Драйвер клиента контроллера функций запускает процесс инициализации, когда Windows Driver Foundation (WDF) вызывает реализацию клиентского драйвера обратного вызова EVT_WDF_DRIVER_DEVICE_ADD . В этой реализации драйвер клиента должен вызвать UfxFdoInit , а затем создать объект устройства, вызвав WdfDeviceCreate.
- Драйвер клиента вызывает UfxDeviceCreate , чтобы создать объект USB-устройства и получить дескриптор UFXDEVICE.
- Драйвер клиента вызывает UfxDeviceNotifyHardwareReady , чтобы указать UFX, что теперь он может вызывать функции обратного вызова драйвера клиента.
- UFX выполняет такие задачи инициализации, как:
- UFX вызывает реализацию EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD драйвера клиента для создания конечной точки по умолчанию.
- UFX создает дочерние физические объекты устройств (PDO) для интерфейсов, поддерживаемых устройством.
- UFX ожидает активации драйвера класса устройства при отправке запроса IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS . Он также ожидает, пока драйвер клиента вызовет UfxDeviceNotifyAttach , который указывает, что устройство подключено.
Уведомление драйвера класса
Чтобы получать уведомления о пакетах установки и состоянии шины, драйвер класса должен отправлять запросы IOCTL_INTERNAL_USBFN_ACTIVATE_USB_BUS . UFX помещает эти запросы в очереди уведомлений для конкретного драйвера класса. Получив уведомление о событии шины от драйвера клиента, UFX извлекает из каждой соответствующей очереди и завершает запрос. Чтобы предотвратить отсутствие уведомлений в драйверах классов, UFX сохраняет очередь уведомлений фиксированного размера для драйвера класса.
События подключения и отсоединения устройства
UFX предполагает, что устройство будет отсоединено до тех пор, пока драйвер клиента контроллера функций не вызовет UfxDeviceNotifyAttach.
После этого вызова UFX устанавливает состояние устройства в powered , как определено в спецификации USB. Чтобы уведомить драйвер клиента об изменении состояния, UFX вызывает реализацию EVT_UFX_DEVICE_USB_STATE_CHANGE клиентского драйвера.
UFX уведомляет драйвер зарядного устройства (Cad.sys), чтобы помочь с зарядкой устройства. UFX также уведомляет драйверы класса, выполняя IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION запросы, отправленные ранее драйверами класса.
Драйвер клиента должен вызвать UfxDeviceNotifyDetach , когда шина отсоединяется. Клиент должен вызывать отсоединение только один раз после каждого вызова UfxDeviceNotifyAttach. После вызова UfxDeviceNotifyDetach UFX вызывает EVT_UFX_DEVICE_HOST_DISCONNECT (если это не изменение интерфейса). Затем UFX выполняет все задачи очистки, такие как очистка всех очередей конечных точек и запуск очереди конечных точек по умолчанию. Вызовы UFX EVT_UFX_DEVICE_USB_STATE_CHANGE и уведомляют драйверы класса, выполняя IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION запросы.
Сбой оборудования
В случае ошибки оборудования драйвер клиента должен вызвать UfxDeviceNotifyHardwareFailure. В ответ UFX разорвет стек устройств и может попытаться восстановиться после этой ситуации, вызвав EVT_UFX_DEVICE_CONTROLLER_RESET драйвера клиента. Клиент должен сбросить контроллер в исходное состояние. В случае другого сбоя оборудования клиент должен снова вызвать UfxDeviceNotifyHardwareFailure. Во втором вызове UFX запишет свое состояние и проверка ошибок.
Обнаружение портов
Обнаружение портов выполняется UFX. Он вызывает функцию обратного вызова драйвера клиента контроллера функций EVT_UFX_DEVICE_PORT_DETECT для определения типа порта, к которому подключено устройство. Клиент отвечает вызовом UfxDevicePortDetectComplete или UfxDevicePortDetectCompleteEx с одним из типов портов, определенных в USBFN_PORT_TYPE.
Если клиент не может определить тип порта, клиент должен сообщить о usbfnUnknownPort. Если порт неизвестен или является подчиненным, UFX вызывает функцию EVT_UFX_DEVICE_HOST_CONNECT драйвера клиента. UFX прослушивает автобус в течение некоторого времени. Если порт неизвестен, но есть трафик, например пакет установки, UFX будет принимать usbfnStandardDownstreamPort. В противном случае UFX назначает порт UsbfnInvalidDedicatedChargingPort. После определения типа порта UFX уведомляет Cad.sys и вызывает функцию EVT_UFX_DEVICE_PORT_CHANGE драйвера клиента. В функции драйвер клиента должен изменить состояние оборудования в соответствии с типом порта UFX.
Создание конечной точки
UFX создает конечную точку по умолчанию (конечную точку 0), вызывая EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD драйвера клиента, чтобы она обрабатывала пакеты установки, отправленные узлом. UFX создает другие конечные точки, вызывая EVT_UFX_DEVICE_ENDPOINT_ADD. UFX создает конечные точки только после того, как драйвер клиента вызывает UfxDeviceNotifyHardwareReady. В этих функциях обратного вызова драйвер клиента должен вызвать UfxEndpointCreate к объекту конечной точки и получить его дескриптор UFXENDPOINT. UFX задает для родительского объекта PDO драйвера класса, связанного с интерфейсом, к которому принадлежит конечная точка. Родительским объектом конечной точки по умолчанию является объект USB-устройства. Конечная точка содержит два объекта очереди платформы: очередь передачи и команду Queue, доступ к которым можно получить только в том случае, если устройство находится в состоянии Настроено (за исключением конечной точки 0, доступ к которой можно получить после вызовов UFX EVT_UFX_DEVICE_HOST_CONNECT).
- Запросы очереди команд
- IOCTL_INTERNAL_USBFN_GET_PIPE_STATE
- IOCTL_INTERNAL_USBFN_SET_PIPE_STATE
- IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE
- Запросы на передачу очереди
- IOCTL_INTERNAL_USBFN_TRANSFER_IN
- IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT
- IOCTL_INTERNAL_USBFN_TRANSFER_OUT
- IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN
- IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT
Перечисление устройств
Драйвер клиента не должен разрешать подключения к узлу, прежде чем UFX вызовет EVT_UFX_DEVICE_HOST_CONNECT драйвера. Перечисление устройств начинается, когда драйвер клиента вызывает UfxDeviceNotifyReset. В состоянии По умолчанию UFX обрабатывает стандартные пакеты установки.
Reset
UFX очищает все очереди конечных точек и отправляет IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE запрос драйверу клиента на обновление wMaxPacketSize конечной точки 0. UFX запускает очередь конечной точки по умолчанию и устанавливает состояние По умолчанию.
Default
UFX вызывает функцию EVT_UFX_DEVICE_USB_STATE_CHANGE драйвера клиента. Он также уведомляет драйверы класса о состоянии. После того как UFX получит пакет SET_ADDRESS стандартной установки, UFX устанавливает состояние Addressed (Адресно).
Рассмотрены
UFX вызывает функцию EVT_UFX_DEVICE_ADDRESSED драйвера клиента, чтобы указать клиенту, какой адрес следует использовать. — Если адрес равен 0, UFX возвращает состояние по умолчанию и вызывает EVT_UFX_DEVICE_USB_STATE_CHANGE и уведомляет драйверы класса. При получении стандартного пакета установки SET_CONFIGURATION UFX устанавливает состояние Настроено.
Настроено
Если выбранная конфигурация имеет значение 0, UFX очищает конечные точки интерфейса и устанавливает состояние Addressed (Адресно). UFX отправляет драйверу клиента запрос IOCTL_INTERNAL_USBFN_DESCRIPTOR_UPDATE на обновление wMaxPacketSize конечных точек интерфейса. UFX гарантирует, что все очереди конечных точек интерфейса завершены и запускают очереди конечных точек интерфейса. Если тип порта не является UsbfnStandardDownstreamPort или UsbfnChargingDownstreamPort, UFX изменит тип порта на UsbfnStandardDownstreamPort и сообщает Cad.sys; драйвер клиента путем вызова EVT_UFX_DEVICE_PORT_CHANGE и EVT_UFX_DEVICE_USB_STATE_CHANGE для обновления состояния; драйверы класса настроенного состояния.
Стандартные передачи элементов управления
UFX может обрабатывать передачу управления в конечной точке по умолчанию в любое время после вызова EVT_UFX_DEVICE_DEFAULT_ENDPOINT_ADD, в котором драйвер клиента создает конечную точку по умолчанию с помощью . Все передачи управления начинаются с 8-байтового пакета установки. Чтобы отправить пакет установки на узел, драйвер клиента должен вызвать UfxEndpointNotifySetup. Стандартные передачи элементов управления выполняются UFX. Если с передачей элемента управления связаны данные, UFX считывает данные из конечной точки элемента управления по умолчанию и записывает их в нее соответствующим образом.
Нестандартные передачи элементов управления
Если UFX не может обработать передачу управления, передача пересылается соответствующему драйверу класса путем выполнения запроса IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION . Передача элементов управления может выполняться в любой конечной точке, которая определена как конечная точка элемента управления в дескрипторове конечной точки. Передача элементов управления для конечных точек, отличных от конечной точки управления по умолчанию, всегда является нестандартной передачей элементов управления. Если конечная точка управления является конечной точкой управления по умолчанию, UFX будет уведомлять драйверы класса о пакетах установки, которые помечены как запросы класса для этого драйвера класса. Если конечная точка управления принадлежит интерфейсу, UFX уведомляет драйвер класса, связанный с этим интерфейсом. При необходимости драйверы классов должны выполнять чтение и запись в конечную точку управления.
Передача данных
Передача данных инициируется драйверами классов путем отправки запросов IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT или IOCTL_INTERNAL_USBFN_TRANSFER_OUT . После проверки каждого из этих запросов UFX перенаправит его в соответствующую очередь конечной точки для обработки драйвером клиента. Ожидается, что драйвер клиента выполнит дополнительную проверку. Драйвер клиента получает запросы на передачу в очередях конечных точек. Драйвер клиента может получить столько запросов из этой очереди, сколько ему нужно для максимального использования шины. Драйвер клиента должен выполнять успешные запросы с STATUS_SUCCESS. Драйвер должен предпринять все возможное, чтобы отменить запросы, и завершить отмененные запросы с STATUS_CANCELLED в случае отмены. Если передаются недопустимые параметры, драйвер клиента завершает запрос с STATUS_INVALID_PARAMETER.
Передача элементов управления
Передача элементов управления начинается с 8-байтового пакета установки. Чтобы отправить пакет установки на узел, драйвер клиента должен вызвать UfxEndpointNotifySetup. UFX уведомляет драйверы класса о нестандартных передачах элементов управления, выполняя запросы уведомлений. Клиенты и UFX используют IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT или IOCTL_INTERNAL_USBFN_TRANSFER_OUT для чтения и записи в конечную точку управления по умолчанию. Однако интерфейс может определять другие конечные точки управления, которые может использовать только соответствующий драйвер класса. Конечные точки управления могут быть остановлены в ответ на пакет установки. Драйверы классов отправляют IOCTL_INTERNAL_USBFN_SET_PIPE_STATE запрос на остановку конечной точки. Ожидается, что оборудование или драйвер клиента немедленно возобновят трафик на конечной точке после отправки остановки. Конечные точки управления также могут отправлять и получать пакеты нулевой длины (ZLP) без каких-либо предварительных данных. Драйвер клиента и UFX могут сделать это с помощью IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_IN и IOCTL_INTERNAL_USBFN_CONTROL_STATUS_HANDSHAKE_OUT.
Массовая передача и прерывание передачи
Массовая передача гарантирует доставку данных и используется для отправки больших объемов данных. Передачи можно отправлять в конечную точку массовых операций с помощью IOCTL_INTERNAL_USBFN_TRANSFER_IN, IOCTL_INTERNAL_USBFN_TRANSFER_IN_APPEND_ZERO_PKT или IOCTL_INTERNAL_USBFN_TRANSFER_OUT. Массовые конечные точки могут быть остановлены аналогично конечным точкам управления с помощью IOCTL_INTERNAL_USBFN_SET_PIPE_STATE. Ожидается, что драйвер клиента отправляет пакет STALL в ответ на все запросы узла и хранит запросы IOCTL. В отличие от конечных точек управления, остановленная конечная точка массовых операций остается остановленной до тех пор, пока состояние остановки не будет явно очищено.
Прерывания передачи Прерывания передачи похожи на массовую передачу, но имеют гарантированную задержку. Прерывания передачи имеют тот же интерфейс, что и массовая передача, но не имеют возможностей потоковой передачи.
Изохронные передачи
Драйвер клиента не должен поддерживать изохронные передачи в этой версии.
Исключение брандмауэра Windows для прокси-сервера пробуждения
Драйвер клиента владеет всеми аспектами управления питанием. Так как функции обратного вызова являются асинхронными, драйвер клиента должен вернуться в соответствующее состояние питания и завершить запрос, прежде чем вызывать соответствующую функцию экспорта event-complete, например UfxDeviceEventComplete.
UFX находится в рабочем состоянии, если состояние устройства (определенное в USBFN_DEVICE_STATE) — UsbfnDeviceStateSuspended и UsbfnDeviceStateAttached и не сообщает тип порта. Кроме того, UFX сообщает тип порта (определенный в USBFN_PORT_TYPE) UsbfnStandardDownstreamPort или UsbfnChargingDownstreamPort.
UFX входит в рабочее состояние и выходит из нее, вызывая EVT_UFX_DEVICE_USB_STATE_CHANGE или EVT_UFX_DEVICE_PORT_CHANGE реализации. Переход в рабочее состояние или из нее завершается, когда драйвер клиента вызывает UfxDeviceEventComplete.
В рабочем состоянии UFX может вызывать любой обратный вызов. Хотя он не в рабочем состоянии, UFX только вызывает EVT_UFX_DEVICE_USB_STATE_CHANGE , чтобы войти в рабочее состояние; EVT_UFX_DEVICE_REMOTE_WAKEUP_SIGNAL выдавать удаленное пробуждение во время приостановки (если это поддерживается).
Приостановка устройства
Приостановка устройства происходит при отсутствии трафика в шине в течение 3 миллисекунда. В этом случае драйвер клиента должен сообщить UFX при обнаружении приостановки и возобновления, вызвав UfxDeviceNotifySuspend и UfxDeviceNotifyResume. При получении этих вызовов UFX EVT_UFX_DEVICE_USB_STATE_CHANGE и уведомляет драйверы классов, выполняя запросы IOCTL_INTERNAL_USBFN_BUS_EVENT_NOTIFICATION . Если удаленное пробуждение поддерживается устройством и включено узлом, UFX может вызывать вызовы EVT_UFX_DEVICE_USB_STATE_CHANGE пока приостановлено для выдачи сигнала удаленного пробуждения.