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


Как отправить управляющую передачу USB

В этой статье объясняется структура передачи управления и то, как клиентский драйвер должен отправлять запрос управления на устройство.

Сведения о конечной точке по умолчанию

Все USB-устройства должны поддерживать по крайней мере одну конечную точку, называемую конечной точкой по умолчанию. Любая передача, предназначенная для конечной точки по умолчанию, называется управляющей передачей. Цель передачи элемента управления — разрешить узлу получать сведения об устройстве, настраивать устройство или выполнять операции управления, уникальные для устройства.

Начнем с изучения этих характеристик конечной точки по умолчанию.

  • Адрес конечной точки по умолчанию — 0.
  • Конечная точка по умолчанию двунаправленная, то есть хост может отправлять данные в конечную точку и получать данные от неё в рамках одной передачи.
  • Конечная точка по умолчанию доступна на уровне устройства и не определена в любом интерфейсе устройства.
  • Конечная точка по умолчанию активна, как только подключение устанавливается между узлом и устройством. Он активен даже до выбора конфигурации.
  • Максимальный размер пакета конечной точки по умолчанию зависит от скорости шины устройства. Низкая скорость, 8 байт; полная и высокая скорость, 64 байта; SuperSpeed, 512 байт.

Макет передачи элемента управления

Поскольку передачи контроля имеют высокий приоритет, определённая пропускная способность резервируется на шине хостом. Для устройств с низкой и полной скоростью — 10 % пропускной способности; 20 % — для устройств с высокой скоростью и SuperSpeed-передачей. Теперь рассмотрим структуру передачи управления.

Схема передачи USB-элемента управления.

Передача управления делится на три транзакции: настройка транзакции, транзакция данных и транзакция состояния. Каждая транзакция содержит три типа пакетов: пакет маркера, пакет данных и пакет подтверждения.

Некоторые поля являются общими для всех пакетов. В число этих полей входят следующие.

  • Поле синхронизации, указывающее начало пакета.
  • Идентификатор пакета (PID), указывающий тип пакета, направление транзакции и в случае пакета подтверждения, он указывает на успешность или сбой транзакции.
  • Поле EOP указывает конец пакета.

Другие поля зависят от типа пакета.

Пакет токенов

Каждая транзакция установки начинается с пакета токенов. Ниже приведена структура пакета. Хост всегда отправляет пакет токена.

Схема макета пакета токенов.

Значение PID указывает тип пакета токенов. Возможные значения

  • SETUP: указывает начало настройки транзакции в передаче управления.
  • IN: указывает, что хост запрашивает данные с устройства (режим чтения).
  • OUT: указывает, что хост отправляет данные на устройство (запись).
  • SOF: указывает начало кадра. Этот тип пакета маркеров содержит 11-разрядный номер кадра. Хост отправляет пакет SOF. Частота отправки этого пакета зависит от скорости шины. Для полной скорости хост отправляет пакет каждую 1 миллисекунду. На скоростной шине это происходит каждые 125 микросекунд.

Пакет данных

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

Схема макета пакета данных.

Пакет установления связи

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

Схема макета пакета рукопожатия.

Структуру транзакций и пакетов можно увидеть с помощью любого USB-анализатора, например Beagle, Ellisys, анализаторов ПРОТОКОЛА USB LeCroy. Устройство анализатора показывает, как данные отправляются или получают от USB-устройства через провод. В этом примере рассмотрим некоторые сигналы, захваченные USB-анализатором от компании LeCroy. Этот пример предназначен только для сведений. Это не подтверждение корпорацией Майкрософт.

Настройка транзакции

Хост всегда инициирует управляющую передачу. Это делается путем отправки транзакции установки. Эта транзакция содержит пакет маркера, называемый маркером установки, за которым следует 8-байтовый пакет данных. На снимке экрана показан пример транзакции установки.

Снимок экрана следа установочной транзакции.

В приведенной выше трассировке хост инициирует передачу управления (указано H↓), отправив пакет маркера установки #434. Обратите внимание, что PID указывает на установку, обозначая маркер установки. За идентификатором следуют адрес устройства и адрес конечной точки. Для передачи элементов управления этот адрес конечной точки всегда равен 0.

Затем хост отправляет пакет данных #435. PiD — DATA0, и это значение используется для последовательности пакетов (для обсуждения). За piD следует 8 байтов, которые содержат основные сведения об этом запросе. Эти 8 байт указывают тип запроса и размер буфера, в котором устройство записывает свой ответ.

Все байты принимаются в обратном порядке. Как описано в разделе 9.3, мы видим следующие поля и значения:

Поле Размер значение Описание
bmRequestType (См. 9.3.1 bmRequestType ) 1 0x80 Направление передачи данных — от устройства к узлу (D7 — 1)

Запрос является стандартным запросом (D6... D5 равно 0)

Получатель запроса — DEVICE (D4 — 0)
bRequest (см. раздел 9.3.2 и таблица 9-4) 1 0x06 Тип запроса — GET_DESCRIPTOR.
wValue (см. таблицу 9-5) 2 0x0100 Значение запроса указывает, что тип дескриптора — DEVICE.
wIndex (см. раздел 9.3.4) 2 0x0000 Направление от хоста к устройству (D7 равно 1)

Номер конечной точки равен 0.
wLength (см. раздел 9.3.5) 2 0x0012 Запрос — получить 18 байт.

Таким образом, можно заключить, что в этой передаче управления (чтение) хост отправляет запрос на получение дескриптора устройства и указывает 18 байт в качестве длины передачи для хранения этого дескриптора. Способ отправки устройством этих 18 байт зависит от объема данных, который конечная точка по умолчанию способна отправить за одну транзакцию. Эти сведения включаются в дескриптор устройства, возвращаемый устройством в транзакции данных.

В ответ устройство отправляет пакет рукопожатия (#436, указанный D↓). Обратите внимание, что значение PID равно ACK (пакет ACK). Это означает, что устройство признало транзакцию.

Транзакция данных

Давайте посмотрим, что устройство возвращает в ответ на запрос. Фактические данные передаются в рамках передачи данных.

Ниже приведена трассировка транзакции данных.

Снимок экрана, показывающий трассировку примера транзакции данных.

После получения пакета ACK хост инициирует транзакцию данных. Чтобы инициировать транзакцию, он отправляет пакет токена (#450) с направлением «IN» (называемый «IN-токен»).

В ответ устройство отправляет пакет данных (#451), который следует маркеру IN. Этот пакет данных содержит фактический дескриптор устройства. Первый байт указывает длину дескриптора устройства, 18 байт (0x12). Последний байт в этом пакете данных указывает максимальный размер пакета, поддерживаемый конечной точкой по умолчанию. В этом случае мы видим, что устройство может отправлять 8 байт за раз через конечную точку по умолчанию.

Примечание.

Максимальный размер пакета конечной точки по умолчанию зависит от скорости устройства. Конечная точка по умолчанию устройства с высокой скоростью составляет 64 байта; устройство с низкой скоростью составляет 8 байт.

Хост подтверждает транзакцию данных, отправив пакет ACK (№ 452) на устройство.

Давайте вычислим объем возвращаемых данных. В поле wLength пакета данных (#435) в операции установки хост запросил 18 байт. В транзакции данных видно, что от устройства были получены только первые 8 байт дескриптора устройства. Итак, как хост получает информацию, хранящуюся в оставшихся 10 байтах? Устройство делает это в двух транзакциях: 8 байтов, а затем последние 2 байта.

Теперь, когда узел знает максимальный размер пакета конечной точки по умолчанию, узел инициирует новую транзакцию данных и запрашивает следующую часть на основе размера пакета.

Ниже приведена следующая транзакция данных:

Снимок экрана: трассировка новой транзакции данных.

Узел инициирует предшествующую транзакцию данных, отправив токен IN (#463) и запросив следующие 8 байтов с устройства. Устройство отвечает с пакетом данных (#464), который содержит следующие 8 байт дескриптора устройства.

Получив 8 байтов, хост отправляет пакет ACK (No 465) на устройство.

Затем хост запрашивает последние 2 байта в следующей транзакции данных следующим образом:

Снимок экрана, показывающий трассировку новой транзакции данных, в которой хост запрашивает последние 2 байта.

Таким образом, мы видим, что для передачи 18 байт с устройства на хост, хост отслеживает количество переданных байт и инициирует три транзакции данных (8+8+2).

Примечание.

Обратите внимание на PID пакетов данных в транзакциях данных 19, 23, 26. PID чередуется между DATA0 и DATA1. Эта последовательность называется переключение данных. В случаях, когда существует несколько транзакций данных, для проверки последовательности пакетов используется переключение данных. Этот метод гарантирует, что пакеты данных не дублируются или теряются.

Сопоставляя объединенные пакеты данных со структурой дескриптора устройства (см. таблицу 9-8), мы видим эти поля и значения:

Поле Размер значение Описание
bLength 1 0x12 Длина дескриптора устройства, который составляет 18 байт.
bDescriptorType 1 0x01 Тип дескриптора — устройство.
bcdUSB 2 0x0100 Номер версии спецификации — 1.00.
bDeviceClass 1 0x00 Класс устройства равен 0. Каждый интерфейс в конфигурации содержит сведения о классе.
bDeviceSubClass 1 0x00 Подкласс равен 0, так как класс устройства равен 0.
bProtocol 1 0x00 Протокол равен 0. Это устройство не использует какие-либо протоколы, специфичные для класса.
bMaxPacketSize0 1 0x08 Максимальный размер пакета конечной точки составляет 8 байт.
idVendor 2 0x0562 Telex Communications.
idProduct 2 0x0002 USB-микрофон.
bcdDevice 2 0x0100 Указывает номер выпуска устройства.
iManufacturer 1 0x01 Строка производителя.
iProduct 1 0x02 Строка продукта.
iSerialNumber 1 0x03 Серийный номер.
bNumConfigurations 1 0x01 Количество конфигураций.

Проверив эти значения, у нас есть некоторые предварительные сведения об устройстве. Устройство — это микрофон USB с низкой скоростью. Максимальный размер пакета конечной точки по умолчанию составляет 8 байт. Устройство поддерживает одну конфигурацию.

Статус транзакции

Наконец, хост завершает передачу управления, инициируя последнюю транзакцию: транзакцию состояния.

Снимок экрана следа примера передачи данных.

Хост начинает транзакцию с токен-пакетом OUT (#481). Цель этого пакета — убедиться, что устройство отправило все запрошенные данные. В этой транзакции состояния не отправляется пакет данных. Устройство отвечает пакетом ACK. Если произошла ошибка, PID может быть либо NAK, либо STALL.

Модели драйверов

Предварительные требования

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

  • Драйвер клиента должен был создать объект целевого USB-устройства в рамках платформы.

    Если вы используете USB-шаблоны, предоставляемые Microsoft Visual Studio Professional 2012, код шаблона выполняет эти задачи. Код шаблона получает дескриптор целевого объекта устройства и сохраняет его в контексте устройства.

Драйвер клиента KMDF

Драйвер клиента KMDF должен получить дескриптор WDFUSBDEVICE, вызвав метод WdfUsbTargetDeviceCreateWithParameters . Дополнительные сведения см. в разделе "Исходный код устройства" в разделе "Общие сведения о структуре кода драйвера USB-клиента (KMDF)".

Драйвер клиента UMDF

Драйвер клиента UMDF должен получить указатель IWDFUsbTargetDevice , запрашивая целевой объект устройства платформы. Дополнительные сведения см. в статье "Реализация IPnpCallbackHardware и задачи, относящиеся к USB", в разделе "Общие сведения о структуре кода драйвера USB-клиента (UMDF)".

Наиболее важным аспектом передачи управления является правильное форматирование токена установки. Перед отправкой запроса соберите этот набор сведений:

  • Направление запроса: от хоста к устройству или от устройства к хосту.
  • Получатель запроса: устройство, интерфейс, конечная точка или другое.
  • Категория запроса: стандартный, класс или поставщик.
  • Тип запроса, например запрос GET_DESCRIPTPOR. Дополнительные сведения см. в разделе 9.5 спецификации USB.
  • значения wValue и значения wIndex. Эти значения зависят от типа запроса.

Вы можете получить все эти сведения из официальной спецификации USB.

Если вы пишете драйвер UMDF, возьмите файл заголовка Usb_hw.h из обучающего комплекта драйверов UMDF для OSR USB Fx2 Learning Kit. Этот файл заголовка содержит полезные макросы и структуру для форматирования установочного пакета при передаче управления.

Все драйверы UMDF должны взаимодействовать с драйвером в режиме ядра для отправки и получения данных с устройств. Для драйвера USB UMDF драйвер режима ядра всегда является драйвером от Microsoft WinUSB (Winusb.sys).

Всякий раз, когда драйвер UMDF отправляет запрос на стек USB-драйверов, диспетчер ввода-вывода Windows отправляет запрос в WinUSB. После получения запроса WinUSB обрабатывает запрос или пересылает его в стек USB-драйверов.

Определяемые корпорацией Майкрософт методы отправки запросов на передачу элементов управления

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

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

    Примечание.

    Цель передачи любого элемента управления всегда является конечной точкой по умолчанию. Получатель — это сущность устройства, информация о которой (дескриптор, состояние и т. д.) интересует хост.

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

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

    Дополнительные сведения см. в разделе 9.4 в спецификации USB версии 2.0. Стандартные типы запросов определены в файле заголовка Usbspec.h.

  • Запросы на класс определяются спецификацией определенного класса устройства.

  • Запросы поставщика предоставляются поставщиком и зависят от запросов, поддерживаемых устройством.

Стек USB, предоставляемый Корпорацией Майкрософт, обрабатывает все протоколы связи с устройством, как показано в предыдущих трассировках. Драйвер предоставляет интерфейсы драйверов устройств (DDIS), которые позволяют драйверу клиента отправлять передачу управления различными способами. Если драйвер клиента является драйвером Windows Driver Foundation (WDF), он может вызывать подпрограммы непосредственно для отправки распространенных типов запросов управления. WDF интегрированно поддерживает управляющие передачи как для KMDF, так и для UMDF.

Некоторые типы запросов управления недоступны через WDF. Для этих запросов драйвер клиента может использовать гибридную модель WDF. Эта модель позволяет драйверу клиента создавать и форматировать запросы в стиле WDM URB, а затем отправлять эти запросы с помощью объектов платформы WDF. Гибридная модель применяется только к драйверам режима ядра.

Для драйверов UMDF:

Используйте вспомогательные макросы и структуру, определенные в usb_hw.h. Этот заголовок входит в состав пакета обучения UMDF Sample Driver for OSR USB Fx2 Learning Kit.

Используйте эту таблицу, чтобы определить оптимальный способ отправки запросов управления в стек USB-драйверов.

Если вы хотите отправить запрос управления... Для драйвера KMDF... Для драйвера UMDF... Для драйвера WDM создайте структуру URB (вспомогательная функция)
CLEAR_FEATURE. Отключите определенные параметры функций на устройстве, его конфигурации, интерфейсы и конечные точки. См. раздел 9.4.1 в спецификации USB.
  1. Объявите пакет установки. См. структуру WDF_USB_CONTROL_SETUP_PACKET .
  2. Инициализируйте пакет настройки путем вызова WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE.
  3. Укажите значение получателя, определенное в WDF_USB_BMREQUEST_RECIPIENT.
  4. Укажите селектор компонентов (wValue). См. константы USB_FEATURE_XXX в Usbspec.h. Также см. таблицу 9-6 в спецификации USB.
  5. Задайте для SetFeature значение FALSE.
  6. Отправьте запрос, вызвав WdfUsbTargetDeviceSendControlTransferSynchronously или WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Объявите пакет установки. См. структуру WINUSB_CONTROL_SETUP_PACKET , объявленную в usb_hw.h.
  2. Инициализировать пакет установки, вызвав вспомогательный макрос, WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE, определенный в usb_hw.h.
  3. Укажите значение получателя, определенное в WINUSB_BMREQUEST_RECIPIENT.
  4. Укажите селектор компонентов (wValue). См. USB_FEATURE_XXX константы в Usbspec.h. Также см. таблицу 9-6 в спецификации USB.
  5. Задайте для SetFeature значение FALSE.
  6. Создайте запрос, связав пакет инициализированной установки с объектом запроса платформы и буфером передачи путем вызова метода IWDFUsbTargetDevice::FormatRequestForControlTransfer.
  7. Отправьте запрос, вызвав метод IWDFIoRequest::Send .
_URB_CONTROL_FEATURE_REQUEST

(UsbBuildFeatureRequest)

URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE

URB_ФУНКЦИЯ_СБРОС_ФУНКЦИИ_К_ИНТЕРФЕЙСУ

Функция URB для очистки признака до конечной точки

УРБ_ФУНКЦИЯ_ОЧИСТИТЬ_ФУНКЦИЮ_ДЛЯ_ДРУГИХ
GET_CONFIGURATION: Получить текущую конфигурацию USB. См. раздел 9.4.2 в спецификации USB. KMDF выбирает первую конфигурацию по умолчанию. Чтобы получить определяемый устройством номер конфигурации, выполните следующие действия.

  1. Отформатируйте WDF_USB_CONTROL_SETUP_PACKET и задайте для элемента bRequest значение USB_REQUEST_GET_CONFIGURATION.
  2. Отправьте запрос, вызвав WdfUsbTargetDeviceSendControlTransferSynchronously или WdfUsbTargetDeviceFormatRequestForControlTransfer.
UMDF выбирает первую конфигурацию по умолчанию. Чтобы получить определяемый устройством номер конфигурации, выполните следующие действия.

  1. Объявите пакет установки. См. структуру WINUSB_CONTROL_SETUP_PACKET , объявленную в usb_hw.h.
  2. Инициализировать пакет установки, вызвав вспомогательный макрос, WINUSB_CONTROL_SETUP_PACKET_INIT, определенный в usb_hw.h.
  3. Укажите BmRequestToDevice в качестве направления, BmRequestToDevice в качестве получателя и USB_REQUEST_GET_CONFIGURATION в качестве запроса.
  4. Создайте запрос, связав пакет инициализированной установки с объектом запроса платформы и буфером передачи путем вызова метода IWDFUsbTargetDevice::FormatRequestForControlTransfer.
  5. Отправьте запрос, вызвав метод IWDFIoRequest::Send .
  6. Получите номер конфигурации в буфере передачи. Доступ к буферу путем вызова методов IWDFMemory.
_URB_CONTROL_GET_CONFIGURATION_REQUEST

Функция URB_GET_CONFIGURATION
GET_DESCRIPTOR. Получение дескрипторов устройств, конфигурации, интерфейса и конечных точек. См. раздел 9.4.3 в спецификации USB.

Дополнительные сведения см. в разделе "Дескрипторы USB".
Вызовите следующие методы:

Вызовите следующие методы:

_URB_CONTROL_DESCRIPTOR_REQUEST

(UsbBuildGetDescriptorRequest)

Функция URB_GET_DESCRIPTOR_FROM_DEVICE

Функция URB_GET_DESCRIPTOR_FROM_ENDPOINT

УРБ_ФУНКЦИЯ_ПОЛУЧИТЬ_ДЕСКРИПТОР_ИЗ_ИНТЕРФЕЙСА
GET_INTERFACE: Получение текущего альтернативного параметра для интерфейса. См. раздел 9.4.4 в спецификации USB.

  1. Получите дескриптор WDFUSBINTERFACE для интерфейса целевого объекта, вызвав метод WdfUsbTargetDeviceGetInterface.
  2. Вызовите метод WdfUsbInterfaceGetConfiguredSettingIndex.
  1. Получите указатель IWDFUsbInterface на целевой объект интерфейса.
  2. Вызовите метод IWDFUsbInterface::GetConfiguredSettingIndex.
_URB_CONTROL_GET_INTERFACE_REQUEST

ФУНКЦИЯ_URB_ПОЛУЧИТЬ_ИНТЕРФЕЙС
GET_STATUS. Получение битов состояния с устройства, конечной точки или интерфейса. См. раздел 9.4.5. в спецификации USB.
  1. Объявите пакет установки. См. структуру WDF_USB_CONTROL_SETUP_PACKET .
  2. Инициализация пакета установки путем вызова WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.
  3. Укажите значение получателя, определенное в WDF_USB_BMREQUEST_RECIPIENT.
  4. Укажите состояние, которое требуется получить: устройство, интерфейс или конечная точка (wIndex).
  5. Отправьте запрос, вызвав WdfUsbTargetDeviceSendControlTransferSynchronously или WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Объявите пакет установки. См. структуру WINUSB_CONTROL_SETUP_PACKET , объявленную в usb_hw.h.
  2. Инициализировать пакет установки, вызвав вспомогательный макрос, WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS, определенный в usb_hw.h.
  3. Укажите значение получателя, определенное в WINUSB_BMREQUEST_RECIPIENT.
  4. Укажите состояние, которое требуется получить: устройство, интерфейс или конечная точка (wIndex).
  5. Создайте запрос, связав пакет инициализированной установки с объектом запроса платформы и буфером передачи путем вызова метода IWDFUsbTargetDevice::FormatRequestForControlTransfer.
  6. Отправьте запрос, вызвав метод IWDFIoRequest::Send .
  7. Получите значение состояния в буфере передачи. Доступ к буферу путем вызова методов IWDFMemory.
  8. Чтобы определить, указывает ли состояние на самообеспечение или удаленное пробуждение, используйте значения, определенные в перечислении WINUSB_DEVICE_TRAITS.
_URB_CONTROL_GET_STATUS_REQUEST

(UsbBuildGetStatusRequest)

URB_FUNCTION_GET_STATUS_FROM_DEVICE (получить статус от устройства)

Функция получения статуса от интерфейса

URB_FUNCTION_ПОЛУЧИТЬ_СТАТУС_С_КОНЕЧНОЙ_ТОЧКИ

ФУНКЦИЯ URB_GET_STATUS_FROM_OTHER.
SET_ADDRESS. См. раздел 9.4.6 в спецификации USB. Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию. Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию. Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию.
SET_CONFIGURATION. Настройка конфигурации. См. раздел 9.4.7 в спецификации USB.

Дополнительные сведения см. в разделе "Выбор конфигурации для USB-устройства".
По умолчанию KMDF выбирает конфигурацию по умолчанию и первый альтернативный параметр в каждом интерфейсе. Драйвер клиента может изменить конфигурацию по умолчанию, вызвав метод WdfUsbTargetDeviceSelectConfigType и указав WdfUsbTargetDeviceSelectConfigTypeUrb в качестве параметра запроса. Затем необходимо отформатировать URB для этого запроса и отправить его в стек USB-драйверов. По умолчанию UMDF выбирает конфигурацию по умолчанию и первый альтернативный параметр в каждом интерфейсе. Драйвер клиента не может изменить конфигурацию. _URB_SELECT_CONFIGURATION

(USBD_SelectConfigUrbAllocateAndBuild)

ФУНКЦИЯ_URB_ВЫБРАТЬ_КОНФИГУРАЦИЮ
SET_DESCRIPTOR. Обновление существующего устройства, конфигурации или дескриптора строки. См. раздел 9.4.8 в спецификации USB.

Этот запрос часто не используется. Однако стек USB-драйверов принимает такой запрос от драйвера клиента.
  1. Выделите и создайте URB для запроса.
  2. Укажите сведения о передаче в структуре _URB_CONTROL_DESCRIPTOR_REQUEST.
  3. Чтобы отправить запрос, вызовите функции WdfUsbTargetDeviceFormatRequestForUrb или WdfUsbTargetDeviceSendUrbSynchronously.
  1. Объявите пакет установки. См. структуру WINUSB_CONTROL_SETUP_PACKET , объявленную в usb_hw.h.
  2. Укажите сведения о передаче согласно спецификации USB.
  3. Создайте запрос, связав пакет инициализированной установки с объектом запроса платформы и буфером передачи путем вызова метода IWDFUsbTargetDevice::FormatRequestForControlTransfer.
  4. Отправьте запрос, вызвав метод IWDFIoRequest::Send .
_URB_CONTROL_DESCRIPTOR_REQUEST

URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE

URB_ФУНКЦИЯ_УСТАНОВИТЬ_ДЕСКРИПТОР_НА_КОНЕЧНУЮ ТОЧКУ

Функция работы URB: Установить дескриптор на интерфейс
SET_FEATURE: Включите определенные настройки функций на устройстве, в его конфигурациях, интерфейсах и конечных точках. См. раздел 9.4.9 в спецификации USB.
  1. Объявите пакет установки. См. структуру WDF_USB_CONTROL_SETUP_PACKET .
  2. Инициализируйте пакет настройки путем вызова WDF_USB_CONTROL_SETUP_PACKET_INIT_FEATURE.
  3. Укажите значение получателя (устройство, интерфейс, конечная точка), определенное в WDF_USB_BMREQUEST_RECIPIENT.
  4. Укажите селектор компонентов (wValue). См. константы USB_FEATURE_XXX в Usbspec.h. Также см. таблицу 9-6 в спецификации USB.
  5. Задайте для SetFeature значение TRUE
  6. Отправьте запрос, вызвав WdfUsbTargetDeviceSendControlTransferSynchronously или WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Объявите пакет установки. См. структуру WINUSB_CONTROL_SETUP_PACKET , объявленную в usb_hw.h.
  2. Инициализировать пакет установки, вызвав вспомогательный макрос, WINUSB_CONTROL_SETUP_PACKET_INIT_FEATURE, определенный в usb_hw.h.
  3. Укажите значение получателя, определенное в WINUSB_BMREQUEST_RECIPIENT.
  4. Укажите селектор компонентов (wValue). См. USB_FEATURE_XXX константы в Usbspec.h. Также см. таблицу 9-6 в спецификации USB.
  5. Задайте для SetFeature значение TRUE.
  6. Создайте запрос, связав пакет инициализированной установки с объектом запроса платформы и буфером передачи путем вызова метода IWDFUsbTargetDevice::FormatRequestForControlTransfer.
  7. Отправьте запрос, вызвав метод IWDFIoRequest::Send .
_URB_CONTROL_FEATURE_REQUEST

(UsbBuildFeatureRequest)

Установка функции на устройство

URB_FUNCTION_SET_FEATURE_TO_INTERFACE

Функция URB — установка функции для конечной точки

УРБ_ФУНКЦИЯ_УСТАНОВИТЬ_ФУНКЦИЮ_ДРУГОМУ
SET_INTERFACE. Изменяет альтернативный параметр в интерфейсе. См. раздел 9.4.9 в спецификации USB.

Дополнительные сведения см. в статье "Выбор альтернативного параметра в USB-интерфейсе".
WdfUsbTargetDeviceSelectConfig
  1. Получите хэндл WDFUSBINTERFACE для целевого объекта интерфейса.
  2. Вызовите метод WdfUsbInterfaceSelectSetting.
  1. Получите указатель IWDFUsbInterface на целевой объект интерфейса.
  2. Вызовите метод IWDFUsbInterface::SelectSetting.
_URB_SELECT_INTERFACE

(USBD_SelectInterfaceUrbAllocateAndBuild)

URB_FUNCTION_SELECT_INTERFACE
SYNC_FRAME. Установите и получите номер кадра синхронизации конечной точки. См. раздел 9.4.10 в спецификации USB. Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию. Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию. Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию.
Для запросов, относящихся к классам устройств и командам поставщика.
  1. Объявите пакет установки. См. структуру WDF_USB_CONTROL_SETUP_PACKET .
  2. Инициализируйте пакет установки через вызов запросов WDF_USB_CONTROL_SETUP_PACKET_INIT_CLASS или WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR для команд поставщика.
  3. Укажите значение получателя (устройство, интерфейс, конечная точка), определенное в WDF_USB_BMREQUEST_RECIPIENT.
  4. Отправьте запрос, вызвав WdfUsbTargetDeviceSendControlTransferSynchronously или WdfUsbTargetDeviceFormatRequestForControlTransfer.
  1. Объявите пакет установки. См. структуру WINUSB_CONTROL_SETUP_PACKET , объявленную в usb_hw.h.
  2. Инициализировать пакет установки, вызвав вспомогательный макрос, WINUSB_CONTROL_SETUP_PACKET_INIT_CLASS или WINUSB_CONTROL_SETUP_PACKET_INIT_VENDOR, определенный в usb_hw.h.
  3. Укажите направление (см. перечисление WINUSB_BMREQUEST_DIRECTION), получателя (см. перечисление WINUSB_BMREQUEST_RECIPIENT) и запрос, как это описано в классе или спецификации оборудования.
  4. Создайте запрос, связав пакет инициализированной установки с объектом запроса платформы и буфером передачи путем вызова метода IWDFUsbTargetDevice::FormatRequestForControlTransfer.
  5. Отправьте запрос, вызвав метод IWDFIoRequest::Send .
  6. Получайте сведения от устройства через буфер передачи. Доступ к буферу путем вызова методов IWDFMemory.
_URB_CONTROL_VENDOR_OR_CLASS_REQUEST

(UsbBuildVendorRequest)

ФУНКЦИЯ_УРБ_УСТРОЙСТВО_ПРОИЗВОДИТЕЛЯ

Функция URB: Вендорский интерфейс

URB_FUNCTION_VENDOR_ENDPOINT (Функция URB для конечной точки поставщика)

URB_ФУНКЦИЯ_ПРОЧЕЕ_ПОСТАВЩИКА

URB_Функциональный_класс_устройства

URB_FUNCTION_CLASS_INTERFACE

URB_ФУНКЦИЯ_КЛАСС_КОНЕЧНАЯ_ТОЧКА

URB_FUNCTION_CLASS_OTHER

Как выполнить контрольную передачу данных для команды производителя — KMDF

В этой процедуре показано, как драйвер клиента может отправлять передачу элементов управления. В этом примере драйвер клиента отправляет команду поставщика, которая извлекает версию встроенного ПО с устройства.

  1. Объявите константу для команды поставщика. Изучите спецификацию оборудования и определите команду поставщика, которую вы хотите использовать.

  2. Объявите структуру WDF_MEMORY_DESCRIPTOR и инициализируйте ее, вызвав макрос WDF_MEMORY_DESCRIPTOR_INIT_BUFFER . Эта структура получит ответ от устройства после завершения запроса USB-драйвера.

  3. В зависимости от того, отправляете ли запрос синхронно или асинхронно, укажите параметры отправки:

    • Если вы отправляете запрос синхронно путем вызова WdfUsbTargetDeviceSendControlTransferSynchronous, укажите значение времени ожидания. Это значение важно, так как без тайм-аута можно заблокировать поток на неопределенный срок.

      Для этого объявите структуру WDF_REQUEST_SEND_OPTIONS и инициализировать ее, вызвав макрос WDF_REQUEST_SEND_OPTIONS_INIT . Укажите параметр как WDF_REQUEST_SEND_OPTION_TIMEOUT.

      Затем задайте значение времени ожидания, вызвав макрос WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT.

    • Если вы отправляете запрос асинхронно, реализуйте подпрограмму завершения. Освободить все выделенные ресурсы в завершающем процессе.

  4. Объявите структуру WDF_USB_CONTROL_SETUP_PACKET для хранения маркера установки и отформатируйте структуру. Для этого вызовите макрос WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR для форматирования пакета установки. В вызове укажите направление запроса, получатель, параметры отправки запроса (инициализированы на шаге 3) и константу для команды поставщика.

  5. Отправьте запрос, вызвав WdfUsbTargetDeviceSendControlTransferSynchronously или WdfUsbTargetDeviceFormatRequestForControlTransfer.

  6. Проверьте значение NTSTATUS, возвращаемое платформой, и проверьте полученное значение.

В данном примере отправляется запрос на управление USB-устройством, чтобы получить его версию встроенного ПО. Запрос отправляется синхронно, а драйвер клиента задает относительное значение времени ожидания в 5 секунд (в 100 единицах с наносекундами). Драйвер сохраняет полученный ответ в контексте устройства, определяемого драйвером.

enum {
    USBFX2_GET_FIRMWARE_VERSION = 0x1,
....

} USBFX2_VENDOR_COMMANDS; 

#define WDF_TIMEOUT_TO_SEC              ((LONGLONG) 1 * 10 * 1000 * 1000)  // defined in wdfcore.h

const __declspec(selectany) LONGLONG
            DEFAULT_CONTROL_TRANSFER_TIMEOUT = 5 * -1 * WDF_TIMEOUT_TO_SEC; 


typedef struct _DEVICE_CONTEXT
{

    ...
       union {
        USHORT      VersionAsUshort;
        struct {
            BYTE Minor;
            BYTE Major;
        } Version;
    } Firmware; // Firmware version.

} DEVICE_CONTEXT, *PDEVICE_CONTEXT;


__drv_requiresIRQL(PASSIVE_LEVEL)
VOID  GetFirmwareVersion(
    __in PDEVICE_CONTEXT DeviceContext
)
{
    NTSTATUS                        status;
    WDF_USB_CONTROL_SETUP_PACKET    controlSetupPacket;
    WDF_REQUEST_SEND_OPTIONS        sendOptions;
    USHORT                          firmwareVersion;
    WDF_MEMORY_DESCRIPTOR           memoryDescriptor;

    PAGED_CODE();

    firmwareVersion = 0;

    WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memoryDescriptor, (PVOID) &firmwareVersion, sizeof(firmwareVersion));

    WDF_REQUEST_SEND_OPTIONS_INIT(
                                  &sendOptions,
                                  WDF_REQUEST_SEND_OPTION_TIMEOUT
                                  );

    WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
                                         &sendOptions,
                                         DEFAULT_CONTROL_TRANSFER_TIMEOUT
                                         );

    WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket,
                                        BmRequestDeviceToHost,       // Direction of the request
                                        BmRequestToDevice,           // Recipient
                                        USBFX2_GET_FIRMWARE_VERSION, // Vendor command
                                        0,                           // Value
                                        0);                          // Index 

    status = WdfUsbTargetDeviceSendControlTransferSynchronously(
                                        DeviceContext->UsbDevice,
                                        WDF_NO_HANDLE,               // Optional WDFREQUEST
                                        &sendOptions,
                                        &controlSetupPacket,
                                        &memoryDescriptor,           // MemoryDescriptor
                                        NULL);                       // BytesTransferred 

    if (!NT_SUCCESS(status)) 
    {
        KdPrint(("Device %d: Failed to get device firmware version 0x%x\n", DeviceContext->DeviceNumber, status));
        TraceEvents(DeviceContext->DebugLog,
                    TRACE_LEVEL_ERROR,
                    DBG_RUN,
                    "Device %d: Failed to get device firmware version 0x%x\n",
                    DeviceContext->DeviceNumber,
                    status);
    }
    else 
    {
        DeviceContext->Firmware.VersionAsUshort = firmwareVersion;
        TraceEvents(DeviceContext->DebugLog,
                    TRACE_LEVEL_INFORMATION,
                    DBG_RUN,
                    "Device %d: Get device firmware version : 0x%x\n",
                    DeviceContext->DeviceNumber,
                    firmwareVersion);
    }

    return;
}

Как отправить управляющую передачу для GET_STATUS — UMDF

В этой процедуре показано, как драйвер клиента может отправлять передачу элемента управления для команды GET_STATUS. Получатель запроса — это устройство, и запрос получает сведения в битах D1-D0. Дополнительные сведения см. на рисунке 9-4 в спецификации USB.

  1. Включите файл заголовка Usb_hw.h, доступный в пакете обучения UMDF Sample Driver for OSR USB Fx2 Learning Kit.

  2. Объявите структуру WINUSB_CONTROL_SETUP_PACKET .

  3. Инициализировать пакет установки, вызвав вспомогательный макрос, WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.

  4. Укажите BmRequestToDevice в качестве получателя.

  5. Укажите 0 в значении индекса.

  6. Вызовите вспомогательный метод SendControlTransferSynchronous, чтобы отправить запрос синхронно.

    Вспомогательный метод создает запрос путем связывания пакета инициализированной установки с объектом запроса платформы и буфером передачи путем вызова метода IWDFUsbTargetDevice::FormatRequestForControlTransfer . Вспомогательный метод отправляет запрос, вызвав метод IWDFIoRequest::Send . После возврата метода проверьте возвращаемое значение.

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

В этом примере кода отправляется запрос передачи управления для получения статуса устройства. В примере запрос отправляется синхронно путем вызова вспомогательного метода SendControlTransferSynchronous.

HRESULT
CDevice::GetDeviceStatus ()
{

    HRESULT hr = S_OK;

    USHORT deviceStatus;
    ULONG bytesTransferred;

    TraceEvents(TRACE_LEVEL_INFORMATION,
                DRIVER_ALL_INFO,
                "%!FUNC!: entry");

    // Setup the control packet.

    WINUSB_CONTROL_SETUP_PACKET setupPacket;

    WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(
                                      &setupPacket,
                                      BmRequestToDevice,
                                      0);

    hr = SendControlTransferSynchronously(
                 &(setupPacket.WinUsb),
                 & deviceStatus,
                 sizeof(USHORT),
                 &bytesReturned
                );

     if (SUCCEEDED(hr))
    {
        if (deviceStatus & USB_GETSTATUS_SELF_POWERED)
        {
             m_Self_Powered = true;
        } 
        if (deviceStatus & USB_GETSTATUS_REMOTE_WAKEUP_ENABLED)
        {
             m_remote_wake-enabled = true;
        }
    }

    return hr;
 }

В следующем примере кода показана реализация вспомогательного метода с именем SendControlTransferSynchronous. Этот метод отправляет запрос синхронно.

HRESULT
CDevice::SendControlTransferSynchronously(
    _In_ PWINUSB_SETUP_PACKET SetupPacket,
    _Inout_ PBYTE Buffer,
    _In_ ULONG BufferLength,
    _Out_ PULONG LengthTransferred
    )
{
    HRESULT hr = S_OK;
    IWDFIoRequest *pWdfRequest = NULL;
    IWDFDriver * FxDriver = NULL;
    IWDFMemory * FxMemory = NULL;
    IWDFRequestCompletionParams * FxComplParams = NULL;
    IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL;

    *LengthTransferred = 0;

    hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface
                                    NULL, //pParentObject
                                    &pWdfRequest);

    if (SUCCEEDED(hr))
    {
        m_FxDevice->GetDriver(&FxDriver);

        hr = FxDriver->CreatePreallocatedWdfMemory( Buffer,
                                                    BufferLength,
                                                    NULL,        //pCallbackInterface
                                                    pWdfRequest, //pParetObject
                                                    &FxMemory );
    }

    if (SUCCEEDED(hr))
    {
        hr = m_pIUsbTargetDevice->FormatRequestForControlTransfer( pWdfRequest,
                                                                   SetupPacket,
                                                                   FxMemory,
                                                                   NULL); //TransferOffset
    }

    if (SUCCEEDED(hr))
    {
        hr = pWdfRequest->Send( m_pIUsbTargetDevice,
                                WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,
                                0); //Timeout
    }

    if (SUCCEEDED(hr))
    {
        pWdfRequest->GetCompletionParams(&FxComplParams);

        hr = FxComplParams->GetCompletionStatus();
    }

    if (SUCCEEDED(hr))
    {
        HRESULT hrQI = FxComplParams->QueryInterface(IID_PPV_ARGS(&FxUsbComplParams));
        WUDF_TEST_DRIVER_ASSERT(SUCCEEDED(hrQI));

        WUDF_TEST_DRIVER_ASSERT( WdfUsbRequestTypeDeviceControlTransfer ==
                            FxUsbComplParams->GetCompletedUsbRequestType() );

        FxUsbComplParams->GetDeviceControlTransferParameters( NULL,
                                                             LengthTransferred,
                                                             NULL,
                                                             NULL );
    }

    SAFE_RELEASE(FxUsbComplParams);
    SAFE_RELEASE(FxComplParams);
    SAFE_RELEASE(FxMemory);

    pWdfRequest->DeleteWdfObject(); 
    SAFE_RELEASE(pWdfRequest);

    SAFE_RELEASE(FxDriver);

    return hr;
}

Если вы используете Winusb.sys в качестве драйвера функции для устройства, вы можете отправлять передачу элементов управления из приложения. Чтобы отформатировать пакет установки в WinUSB, используйте вспомогательные макросы и структуры UMDF, описанные в таблице в этой статье. Чтобы отправить запрос, вызовите функцию WinUsb_ControlTransfer .