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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Пакет данных

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

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

Пакет подтверждения

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

Схема макета пакета подтверждения.

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

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

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

Снимок экрана: трассировка транзакции установки.

В приведенной выше трассировке узел инициирует передачу элемента управления (указано Hfx), отправив пакет маркера установки #434. Обратите внимание, что PID указывает setup, указывающий маркер установки. За идентификатором следуют адрес устройства и адрес конечной точки. Для передачи элементов управления этот адрес конечной точки всегда равен 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 (No 452) на устройство.

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

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

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

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

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

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

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

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

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

Примечание.

Обратите внимание на ИДЕНТИФИКАТОР пакетов данных в транзакциях данных 19, 23, 26. Идентификатор личных данных чередуется между 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 Sample Driver for OSR USB Fx2 Learning Kit. Этот файл заголовка содержит полезные макросы и структуру для форматирования пакета установки для передачи элемента управления.

Все драйверы UMDF должны взаимодействовать с драйвером в режиме ядра для отправки и получения данных с устройств. Для драйвера USB UMDF драйвер в режиме ядра всегда является драйвером 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_FUNCTION_CLEAR_FEATURE_TO_INTERFACE

URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT

URB_FUNCTION_CLEAR_FEATURE_TO_OTHER
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_FUNCTION_GET_CONFIGURATION
GET_DESCRIPTOR. Получение дескрипторов устройств, конфигурации, интерфейса и конечных точек. См. раздел 9.4.3 в спецификации USB.

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

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

_URB_CONTROL_DESCRIPTOR_REQUEST

(UsbBuildGetDescriptorRequest)

URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE

URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT

URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE
GET_INTERFACE. Получение текущего альтернативного параметра для интерфейса. См. раздел 9.4.4 в спецификации USB.

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

URB_FUNCTION_GET_INTERFACE
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_GET_STATUS_FROM_INTERFACE

URB_FUNCTION_GET_STATUS_FROM_ENDPOINT

URB_FUNCTION_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_FUNCTION_SELECT_CONFIGURATION
SET_DESCRIPTOR. Обновление существующего устройства, конфигурации или дескриптора строки. См. раздел 9.4.8 в спецификации USB.

Этот запрос часто не используется. Однако стек USB-драйверов принимает такой запрос от драйвера клиента.
  1. Выделите и создайте URB для запроса.
  2. Укажите сведения о передаче в _URB_CONTROL_DESCRIPTOR_REQUEST структуре.
  3. Отправьте запрос, вызвав WdfUsbTargetDeviceFormatRequestForUrb или WdfUsbTargetDeviceSendUrbSynchronous.
  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_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT

URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE
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_DEVICE

URB_FUNCTION_SET_FEATURE_TO_INTERFACE

URB_FUNCTION_SET_FEATURE_TO_ENDPOINT

URB_FUNCTION_SET_FEATURE_TO_OTHER
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_FUNCTION_VENDOR_DEVICE

URB_FUNCTION_VENDOR_INTERFACE

URB_FUNCTION_VENDOR_ENDPOINT

URB_FUNCTION_VENDOR_OTHER

URB_FUNCTION_CLASS_DEVICE

URB_FUNCTION_CLASS_INTERFACE

URB_FUNCTION_CLASS_ENDPOINT

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 .