Отправка передачи USB-элемента управления
В этой статье объясняется структура передачи элемента управления и способ отправки клиентского драйвера на устройство запроса элемента управления.
Сведения о конечной точке по умолчанию
Все USB-устройства должны поддерживать по крайней мере одну конечную точку, называемую конечной точкой по умолчанию. Любая передача, предназначенная для конечной точки по умолчанию, называется передачей элементов управления. Цель передачи элемента управления — разрешить узлу получать сведения об устройстве, настраивать устройство или выполнять операции управления, уникальные для устройства.
Начнем с изучения этих характеристик конечной точки по умолчанию.
- Адрес конечной точки по умолчанию — 0.
- Конечная точка по умолчанию двунаправленная, то есть узел может отправлять данные в конечную точку и получать данные от него в рамках одной передачи.
- Конечная точка по умолчанию доступна на уровне устройства и не определена в любом интерфейсе устройства.
- Конечная точка по умолчанию активна, как только подключение устанавливается между узлом и устройством. Он активен даже до выбора конфигурации.
- Максимальный размер пакета конечной точки по умолчанию зависит от скорости шины устройства. Низкая скорость, 8 байт; полная и высокая скорость, 64 байта; SuperSpeed, 512 байт.
Макет передачи элемента управления
Так как передача управления является высокоприоритетной передачей, определенная пропускная способность зарезервирована на шине узлом. Для устройств с низкой и полной скоростью 10 % пропускной способности; 20 % для устройств высокой и SuperSpeed передачи. Теперь рассмотрим макет передачи элемента управления.
Передача управления делится на три транзакции: настройка транзакции, транзакция данных и транзакция состояния. Каждая транзакция содержит три типа пакетов: пакет маркера, пакет данных и пакет подтверждения.
Некоторые поля являются общими для всех пакетов. В число этих полей входят следующие.
- Поле синхронизации, указывающее начало пакета.
- Идентификатор пакета (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 байта в другой транзакции данных следующим образом:
Таким образом, мы видим, что для передачи 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.
Модели драйверов
- Платформа драйверов в режиме ядра
- Платформа драйвера в режиме пользователя
- Общие сведения о WinUSB для разработчиков
Необходимые компоненты
Прежде чем драйвер клиента может перечислить каналы, убедитесь, что выполнены следующие требования:
Драйвер клиента должен создать объект целевого устройства 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. |
|
|
_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 выбирает первую конфигурацию по умолчанию. Чтобы получить определяемый устройством номер конфигурации, выполните следующие действия.
|
UMDF выбирает первую конфигурацию по умолчанию. Чтобы получить определяемый устройством номер конфигурации, выполните следующие действия.
|
_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. |
|
|
_URB_CONTROL_GET_INTERFACE_REQUEST URB_FUNCTION_GET_INTERFACE |
GET_STATUS. Получение битов состояния с устройства, конечной точки или интерфейса. См. раздел 9.4.5. в спецификации USB. |
|
|
_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-драйверов принимает такой запрос от драйвера клиента. |
|
|
_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. |
|
|
_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
|
|
_URB_SELECT_INTERFACE (USBD_SelectInterfaceUrbAllocateAndBuild) URB_FUNCTION_SELECT_INTERFACE |
SYNC_FRAME. Задайте и получите и номер кадра синхронизации конечной точки. См. раздел 9.4.10 в спецификации USB. | Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию. | Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию. | Этот запрос обрабатывается стеком USB-драйверов; Драйвер клиента не может выполнить эту операцию. |
Для запросов, относящихся к классу устройств, и команд поставщика. |
|
|
_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
В этой процедуре показано, как драйвер клиента может отправлять передачу элементов управления. В этом примере драйвер клиента отправляет команду поставщика, которая извлекает версию встроенного ПО с устройства.
Объявите константу для команды поставщика. Изучите спецификацию оборудования и определите команду поставщика, которую вы хотите использовать.
Объявите структуру WDF_MEMORY_DESCRIPTOR и инициализируйте ее, вызвав макрос WDF_MEMORY_DESCRIPTOR_INIT_BUFFER . Эта структура получит ответ от устройства после завершения запроса USB-драйвера.
В зависимости от того, отправляете ли запрос синхронно или асинхронно, укажите параметры отправки:
Если вы отправляете запрос синхронно путем вызова WdfUsbTargetDeviceSendControlTransferSynchronous, укажите значение времени ожидания. Это значение важно, так как без тайм-аута можно заблокировать поток на неопределенный срок.
Для этого объявите структуру WDF_REQUEST_SEND_OPTIONS и инициализировать ее, вызвав макрос WDF_REQUEST_SEND_OPTIONS_INIT . Укажите параметр как WDF_REQUEST_SEND_OPTION_TIMEOUT.
Затем задайте значение времени ожидания, вызвав макрос WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT .
Если вы отправляете запрос асинхронно, реализуйте подпрограмму завершения. Освободить все выделенные ресурсы в подпрограмме завершения.
Объявите структуру WDF_USB_CONTROL_SETUP_PACKET для хранения маркера установки и форматирования структуры. Для этого вызовите макрос WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR для форматирования пакета установки. В вызове укажите направление запроса, получатель, параметры отправки запроса (инициализированы на шаге 3) и константу для команды поставщика.
Отправьте запрос, вызвав WdfUsbTargetDeviceSendControlTransferSynchronously или WdfUsbTargetDeviceFormatRequestForControlTransfer.
Проверьте значение 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.
Включите файл заголовка Usb_hw.h, доступный в пакете обучения UMDF Sample Driver for OSR USB Fx2 Learning Kit.
Объявите структуру WINUSB_CONTROL_SETUP_PACKET .
Инициализировать пакет установки, вызвав вспомогательный макрос, WINUSB_CONTROL_SETUP_PACKET_INIT_GET_STATUS.
Укажите BmRequestToDevice в качестве получателя.
Укажите значение 0 в значении индекса .
Вызовите вспомогательный метод SendControlTransferSynchronous, чтобы отправить запрос синхронно.
Вспомогательный метод создает запрос путем связывания пакета инициализированной установки с объектом запроса платформы и буфером передачи путем вызова метода IWDFUsbTargetDevice::FormatRequestForControlTransfer . Вспомогательный метод отправляет запрос, вызвав метод IWDFIoRequest::Send . После возврата метода проверьте возвращаемое значение.
Чтобы определить, указывает ли состояние самостоятельное пробуждение, удаленное пробуждение, используйте следующие значения, определенные в перечислении 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 .