Как отправить передачу элементов управления ЧЕРЕЗ 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, LeCroy USB. Устройство анализатора показывает, как данные отправляются или получаются с USB-устройства по проводной сети. В этом примере давайте рассмотрим некоторые трассировки, захваченные USB-анализатором LeCroy. Этот пример предназначен только для получения сведений. Это не одобрено корпорацией Майкрософт.

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

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

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

В предыдущей трассировке узел инициирует передачу элемента управления (обозначается H);, отправляя пакет маркера установки No 434. Обратите внимание, что в piD указано значение SETUP, указывающее маркер установки. За piD следует адрес устройства и адрес конечной точки. Для передачи элементов управления адрес конечной точки всегда равен 0.

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

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

Поле Size Значение Описание
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 байтов зависит от того, сколько данных конечная точка по умолчанию может отправить в одной транзакции. Эти сведения включаются в дескриптор устройства, возвращаемый устройством в транзакции данных.

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

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

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

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

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

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

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

Примечание

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

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

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

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

Следующая транзакция данных:

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

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

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

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

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

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

Примечание

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

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

Поле Size Значение Описание
bLength 1 0x12 Длина дескриптора устройства, которая составляет 18 байт.
bDescriptorType 1 0x01 Тип дескриптора — device.
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 (No 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-стек обрабатывает все протоколы связи с устройством, как показано в предыдущих трассировках. Драйвер предоставляет интерфейсы драйверов устройств (DIS), которые позволяют клиентскому драйверу отправлять передачи управления различными способами. Если драйвер клиента является драйвером Windows Driver Foundation (WDF), он может вызывать подпрограммы напрямую для отправки общих типов запросов на управление. WDF поддерживает передачу элементов управления как для KMDF, так и для UMDF.

Некоторые типы запросов элементов управления не предоставляются через WDF. Для этих запросов драйвер клиента может использовать модель WDF-hybrid. Эта модель позволяет драйверу клиента создавать и форматировать запросы в стиле 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 или 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_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. В зависимости от того, отправляете ли вы запрос синхронно или асинхронно, укажите параметры отправки:

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

      Для этого объявите структуру 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. Вызовите вспомогательный метод SendControlTransferSynchronously, чтобы отправить запрос синхронно.

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

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

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

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;
 }

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

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 .