Здесь продолжение перевода на русский язык уникального документа USB in a NutShell (статья получилась большая, стало неудобно редактировать и пришлось разделить на 3 части).
[Начало статьи...]
[Глава 5: Дескрипторы USB]
Все устройства USB имеют иерархию дескрипторов, которые описывают информацию для хоста – такую, как например что это за устройство, кто его изготовил, какую версию USB поддерживает устройство, какими способами устройство может быть сконфигурировано, количество конечных точек и их типы и т. д.
Наиболее общие дескрипторы USB следующие:
Устройства USB могут иметь только один дескриптор устройства (device descriptor). Дескриптор устройства включает в себя такую информацию, как поддерживаемую устройством ревизию USB, Product ID (PID, идентификатор продукта), Vendor ID (VID, идентификатор производителя), используемые для загрузки соответствующего устройству драйвера, и количество возможных конфигураций устройства. Число конфигураций указывает, сколько имеется ответвлений по дескрипторам конфигурации.
Дескриптор конфигурации (configuration descriptor) указывает величину потребляемой мощности от шины, питается ли устройство от собственного источника (self powered) либо от шины USB (bus powered) и количество интерфейсов, которые есть у конфигурации. Когда устройство проходит энумерацию, хост читает дескриптор устройства и принимает решение, какую конфигурацию применить. Хост может разрешить только какую-то одну из конфигураций.
Например, возможно существование конфигурации с высоким потреблением мощности от шины, и есть конфигурация с собственным источником питания. Если устройство подсоединено к хосту-десктопу с сетевым блоком питания, драйвер может выбрать конфигурацию с высоким потреблением мощности от шины, несмотря на то, что устройство подключено к собственному источнику, а в случае подсоединения к хосту-ноутбуку (при питании его от аккумулятора) драйвер может принудительно выбрать конфигурацию с собственным блоком питания, что потребует от пользователя обязательного подключения внешнего блока питания для USB-устройства.
Параметры настройки конфигураций не ограничены различиями мощности. Каждая конфигурация может быть настроена на одинаковое питание, но иметь разные интерфейсы или наборы конечных точек. Однако нужно отметить, что изменение конфигурации требует, чтобы вся деятельность по каждой конечной точке остановилась. В то время как USB предлагает эту возможность, у очень немногих устройств есть больше чем 1 конфигурация.
Дескриптор интерфейса можно рассматривать как заголовок или группирование конечных точек в функциональную группу, выполняющую единственную особенность (feature) устройства. Например у Вас может быть многофункциональное устройство факса/сканера/принтера. Дескриптор интерфейса 1 может описывать конечные точки функции факса, дескриптор интерфейса 2 может описывать функцию сканера, и дескриптор интерфейса 3 может описывать функцию принтера. В отличие от дескриптора конфигурации, здесь нет ограничений на количество одновременно разрешенных интерфейсов. У устройства могут быть 1 или много интерфейсов, разрешенных одновременно.
Дескрипторы интерфейса имеют поле bInterfaceNumber, указывающее номер интерфейса, и поле bAlternateSetting, которое разрешает интерфейсу поменять установки на лету. Например, у Вас есть устройство с двумя интерфейсами – интерфейс 1 и интерфейс 2. У интерфейса 1 поле bInterfaceNumber установлено в 0, что показывает – это первый дескриптор интерфейса, и поле bAlternativeSetting, установленное в 0. У интерфейса 2 поле bInterfaceNumber установлено в 1, что показывает - это второй интерфейс, и поле bAlternativeSetting установленное в 0 (значение по умолчанию). Мы могли бы добавить сюда другой дескриптор, у которого поле bInterfaceNumber также установлено в 1 (показывает, что это второй интерфейс), но на этот раз поле bAlternativeSetting установлено в 1, что показывает – дескриптор интерфейса может иметь альтернативную настройку, взятую из другого описателя интерфейса 2.
Когда эта конфигурация разрешена, используются первые два дескриптора интерфейса, у которых поле bAlternativeSettings равно 0. Однако во время работы хост может послать запрос SetInterface, направленный на интерфейс с номером 1 (второй интерфейс) с альтернативной настройкой 1, что разрешает другой дескриптор интерфейса.
Это дает преимущество при использовании двух конфигураций – мы можем передавать данные через интерфейс 0, и в то же время менять настройки конечной точки, связанной с интерфейсом 1, не мешая работе интерфейса 0.
Каждый дескриптор конечной точки используется для указания типа передачи, направления, интервала опроса (polling interval) и максимального размера пакета для каждой конечной точки. Конечная точка 0 всегда подразумевается по умолчанию точкой для управления, и поэтому она не имеет дескриптора.
Композиция дескрипторов USB
Все дескрипторы имеют общий формат. Первый байт указывает длину дескриптора в байтах, второй байт показывает тип дескриптора. Если длина описателя будет меньшей, чем определено в спецификации, то главный компьютер должен проигнорировать его. Однако, если размер больше ожидаемого, хост будет игнорировать дополнительные байты, и будет искать следующий дескриптор в конце возвращенной действительной длины.
Смещ. |
Поле |
Размер |
Значение |
Описание |
0 |
bLength |
1 |
Число |
Размер дескриптора в байтах |
1 |
bDescriptionType |
1 |
Константа |
Тип дескриптора |
2 |
... |
n |
|
Начало параметров дескриптора |
Дескрипторы устройства
Дескриптор устройства для устройства USB представляет само устройство в целом. Как следствие – устройство USB может иметь только один дескриптор устройства. Этот дескриптор указывает некоторые основные (несомненно важные) сведения об устройстве, такие как поддерживаемая версия USB, максимальный размер пакета, идентификаторы ID вендора и продукта (VID и PID) и количество возможных конфигураций, которые может иметь устройство. Формат дескриптора устройства показан далее.
Смещ. |
Поле |
Размер |
Значение |
Описание |
0 |
bLength |
1 |
Число |
Размер дескриптора в байтах (для дескриптора устройства размер 18 байт) |
1 |
bDescriptorType |
1 |
Константа |
Тип - Device Descriptor (0x01) |
2 |
bcdUSB |
2 |
BCD |
Номер спецификации USB, с которой совместимо устройство. |
4 |
bDeviceClass |
1 |
Class (класс) |
Код класса (назначается организацией USB Org) Если равно 0, то каждый интерфейс указывает свой собственный код класса. Если равен 0xFF, то код класса определяется вендором. Иначе поле содержит код стандартного класса. |
5 |
bDeviceSubClass |
1 |
SubClass (подкласс) |
Код подкласса (назначается организацией USB Org) |
6 |
bDeviceProtocol |
1 |
Протокол |
Код протокола (назначается организацией USB Org) |
7 |
bMaxPacketSize |
1 |
Число |
Максимальный размер пакета для конечной точки 0. Допустимые размеры 8, 16, 32, 64 |
8 |
idVendor |
2 |
ID |
Vendor ID, VID (назначается организацией USB Org) |
10 |
idProduct |
2 |
ID |
Product ID, PID (назначается организацией - производителем) |
12 |
bcdDevice |
2 |
BCD |
Device Release Number (номер версии устройства) |
14 |
iManufacturer |
1 |
Индекс |
Индекс строки, описывающей производителя |
15 |
iProduct |
1 |
Индекс |
Индекс строки, описывающей продукт |
16 |
iSerialNumber |
1 |
Индекс |
Индекс строки, содержащей серийный номер |
17 |
bNumConfigurations |
1 |
Целое (Integer) |
Количество возможных конфигураций |
- Поле bcdUSB сообщает о самой высокой версии USB, которая поддерживается устройством. Величина кодируется в формате binary coded decimal (BCD, десятичное число, закодированное в двоичном формате) 0xJJMN, где JJ старшая часть номера версии, M младшая часть версии, и N младшая часть подверсии.Например,USB 2.0 кодируется как 0x0200, USB 1.1 как 0x0110 и USB 1.0 как 0x0100.
- Поля bDeviceClass, bDeviceSubClass и bDeviceProtocol используются операционной системой для того, чтобы подобрать драйвер класса (class driver) для Вашего устройства. Обычно только bDeviceClass установлен на уровне устройства. Большинство спецификаций класса хочет идентифицировать себя на уровне интерфейса, в результате bDeviceClass установлен в 0x00. Это позволяет одному устройству поддерживать несколько классов.
- Поле bMaxPacketSize сообщает максимальный размер пакета для конечной точки 0. Все устройства USB должны поддерживать конечную точку 0.
- Поля idVendor и idProduct используются операционной системой для нахождения драйвера для устройства, их также использует программа (ПО хоста), работающая с USB-устройством. Vendor ID назначается организацией USB-IF.
- Поле bcdDevice имеет тот же формат, что и поле bcdUSB, и используется для предоставления номера версии устройства. Его значение присваивается разработчиком устройства USB.
- Три строковых дескриптора существуют для предоставления подробной информации о производителе, продукте и серийном номере. Нет обязательных требований по наличию строковых дескрипторов. Если строковых дескрипторов нет, должен использоваться нулевой индекс.
- Поле bNumConfigurations задает количество конфигураций устройства, которые оно поддерживает на текущей скорости.
Дескрипторы конфигурации
Устройство USB может иметь несколько различных конфигураций, хотя большинство устройств просты и имеют только одну конфигурацию. Дескриптор конфигурации указывает, как устройство запитывается, какое у него максимальное энергопотребление, количество интерфейсов, которое имеет устройство. Поэтому для устройства возможно иметь 2 конфигурации – одну для питания от шины, другую для питания от основного (внешнего) источника. Поскольку это – заголовок к дескрипторам интерфейса, возможно также иметь разные конфигурации для различных режимов передачи.
Как только все конфигурации прочитаны и проанализированы хостом, он посылает команду SetConfiguration с ненулевым значением, которое соответствует bConfigurationValue одной из конфигураций. Это используется для выбора нужной конфигурации.
Смещ. |
Поле |
Размер |
Значение |
Описание |
0 |
bLength |
1 |
Число |
Размер дескриптора в байтах |
1 |
bDescriptorType |
1 |
Константа |
Дескриптор конфигурации (0x02) |
2 |
wTotalLength |
2 |
Число |
Полная длина возвращаемых данных в байтах |
4 |
bNumInterfaces |
1 |
Число |
Количество интерфейсов |
5 |
bConfigurationValue |
1 |
Число |
Величина, используемая как аргумент для выбора этой конфигурации |
6 |
iConfiguration |
1 |
Индекс |
Индекс строкового дескриптора, описывающего эту конфигурацию |
7 |
bmAttributes |
1 |
Набор бит (Bitmap) |
D7 зарезервировано, установлено в 1. (USB 1.0 Bus Powered) D6 самозапитываемое (Self Powered) D5 удаленное пробуждение (Remote Wakeup) D4..0 зарезервировано, установлено в 0. |
8 |
bMaxPower |
1 |
мА |
Максимальное энергопотребление в единицах 2 мА |
- Когда дескриптор конфигурации прочитан, он возвращает полное дерево иерархии, которое включает все используемые дескрипторы интерфейсов и дескрипторы конечных точек. Поле wTotalLength отражает количество байт в иерархии.
- bNumInterfaces указывает количество интерфейсов, представленных для этой конфигурации.
- bConfigurationValue используется в запросе SetConfiguration для выбора этой конфигурации.
- iConfiguration – индекс строкового дескриптора, описывающего конфигурацию в виде, удобном для восприятия человеком.
- bmAttributes задает параметры питания для конфигурации. Если устройство имеет собственное питание, устанавливается бит D6. Бит D7 ранее использовался в USB 1.0 для указания, что устройство питается от шины, но теперь это делается с помощью поля bMaxPower. Если устройство использует любую мощность, потребляемую от шины, в любом случае – либо это устройство, питаемое от шины, либо имеющее отдельный источник питания – устройство должно сообщить о своей максимальной потребляемой мощности в поле bMaxPower. Устройство может также поддерживать удаленное пробуждение (remote wakeup), которое позволяет устройству пробуждать хост, когда он находится в режиме приостановки.
- bMaxPower задает максимальную потребляемую мощность устройством от шины USB. Величина указывается в единицах 2 мА. Таким образом, может быть указан максимум потребления примерно 500 мА. Спецификация позволяет устройству, питающемуся от шины, потреблять ток не более 500 мА от провода Vbus. Если устройство теряет внешнее питание (приходящее не от Vbus), оно не должно потреблять больше, чем указано в bMaxPower. Это должно прервать по ошибке любую операцию, которую устройство не может выполнить без внешнего источника питания.
Дескрипторы интерфейса
Дескриптор интерфейса можно рассматривать как заголовок собрание конечных точек, объединенных в функциональную группу для реализации (feature) устройства. Дескриптор интерфейса имеет следующий формат.
Смещ. |
Поле |
Размер |
Значение |
Описание |
0 |
bLength |
1 |
Число |
Размер дескриптора в байтах (9 байт) |
1 |
bDescriptorType |
1 |
Константа |
Дескриптор интерфейса (0x04) |
2 |
bInterfaceNumber |
1 |
Число |
Индекс (порядковый номер) интерфейса |
3 |
bAlternateSetting |
1 |
Число |
Величина, используемая для выбора альтернативной установки |
4 |
bNumEndpoints |
1 |
Число |
Количество конечных точек, используемых в интерфейсе |
5 |
bInterfaceClass |
1 |
Класс |
Код класса (назначается организацией, следящей за стандартами USB) |
6 |
bInterfaceSubClass |
1 |
Подкласс (SubClass) |
Код подкласса (назначается организацией, следящей за стандартами USB) |
7 |
bInterfaceProtocol |
1 |
Протокол |
Код протокола (назначается организацией, следящей за стандартами USB) |
8 |
iInterface |
1 |
Индекс |
Индекс строкового дескриптора, описывающего этот интерфейс |
- bInterfaceNumber показывает индекс дескриптора интерфейса. Он указывается относительно нуля, и инкрементируется на 1 для каждого нового дескриптора интерфейса.
- bAlternativeSetting может использоваться для задания alternative interfaces (альтернативных интерфейсов). Эти альтернативные интерфейсы могут быть выбраны запросом Set Interface.
- bNumEndpoints показывает количество конечных точек, используемых в интерфейсе. Эта величина должна быть указана без учета конечной точки 0. Поле bNumEndpoints используется для указания количества идущих далее дескрипторов конечных точек.
- bInterfaceClass, bInterfaceSubClass и bInterfaceProtocol может использоваться для указания поддерживаемых классов - HID, коммуникационное устройство, mass storage (устройство хранения информации) и т. д. Это позволяет многим устройствам использовать драйверы класса (встроенные в операционную систему) – при этом отпадает необходимость в написании специального отдельного драйвера для Вашего устройства.
- iInterface используется для строкового описателя интерфейса.
Дескрипторы конечной точки
Дескрипторы конечной точки используются для описания конечных точек, отличных от конечной точки 0. Конечная точка 0 всегда используется как конечная точка управления, и она конфигурируется сразу автоматически, даже перед запросом информации всех дескрипторов. Хост использует информацию, полученную из описателей конечных точек, чтобы определить требования по полосе пропускания шины.
Смещ. |
Поле |
Размер |
Значение |
Описание |
0 |
bLength |
1 |
Число |
Размер дескриптора в байтах (7 байт) |
1 |
bDescriptorType |
1 |
Константа |
Дескриптор конечной точки (0x05) |
2 |
bEndpointAddress |
1 |
Конечная точка |
Адрес конечной точки биты 0..3 номер конечной точки биты 4..6 зарезервированы, установлены в 0 бит 7 направление 0 = Out, 1 = In (для конечных точек игнорируется) |
3 |
bmAttributes |
1 |
Набор бит (Bitmap) |
биты 0..1 тип передачи 00 = Control 01 = Isochronous 10 = Bulk 11 = Interrupt биты 2..7 зарезервированы. Если конечная точка изохронная, то: биты 3..2 = тип синхронизации (режим Iso) 00 = No Synchronisation 01 = Asynchronous 10 = Adaptive 11 = Synchronous биты 5..4 = тип использования Usage Type (режим Iso) 00 = конечная точка данных 01 = конечная точка обратной связи (Feedback Endpoint) 10 = явная конечная точка обратной связи данных (Explicit Feedback Data Endpoint) 11 = зарезервировано |
4 |
wMaxPacketSize |
2 |
Число |
Максимальный размер пакета этой конечной точки, подходящий для отправки или приема |
6 |
bInterval |
1 |
Число |
Интервал для того, чтобы опросить передачи данных конечной точки. Указывается в количестве фреймов. Поле игнорируется для конечных точек Bulk и Control. Для конечных точек Isochronous должно быть равно 1 и для конечных точек interrupt может лежать в диапазоне 1..255. |
- bEndpointAddress индицирует, какую конечную точку описывает этот дескриптор.
- bmAttributes указывает тип передачи. Это могут быть передачи Control, Interrupt, Isochronous или Bulk. Если указана контрольная точка изохронного типа, могут быть выбраны дополнительные атрибуты, такие как синхронизация и типы использования.
- wMaxPacketSize указывают максимальный размер полезной нагрузки в байтах для этой конечной точки.
- bInterval используется, чтобы определить интервал опроса определенных передач. Единицы измерения – фреймы, что для устройств low/full speed составляет 1 мс, и для high speed устройств – 125 мкс.
Строковые дескрипторы
Строковые дескрипторы предоставляют информацию в формате, удобном для чтения человеком, и их указывать необязательно. Если строковые дескрипторы не используются, поле индекса строки дескриптора должно быть установлено в 0, что указывает на отсутствие строкового дескриптора.
Строки закодированы в формате Unicode, и разрабатываемое устройство USB может быть изготовлено с поддержкой многих языков. Строка с индексом 0 должна вернуть список поддерживаемых языков. Список ID языков для USB может быть найден в документе Universal Serial Bus Language Identifiers (LANGIDs) version 1.0.
Смещ. |
Поле |
Размер |
Значение |
Описание |
0 |
bLength |
1 |
Число |
Размер дескриптора в байтах |
1 |
bDescriptorType |
1 |
Константа |
Строковый дескриптор (0x03) |
2 |
wLANGID[0] |
2 |
Число |
Код поддерживаемого языка 0 (например 0x0409 Английский - United States) |
4 |
wLANGID[1] |
2 |
Число |
Код поддерживаемого языка 1 (например 0x0c09 Английский – Австралия) |
n |
wLANGID[x] |
2 |
Число |
Код поддерживаемого языка x (например 0x0407 Немецкий - стандартный) |
Вышеупомянутый строковый дескриптор показывает формат строкового дескриптора 0. Хост должен прочитать этот дескриптор, чтобы определить, какие языки поддерживаются устройством. Если язык поддерживается, хост может запросом Get Descriptor(String) сослаться на него путем отсылки ID языка в поле wIndex.
Все последующие строки имеют формат:
Смещ. |
Поле |
Размер |
Значение |
Описание |
0 |
bLength |
1 |
Число |
Размер дескриптора в байтах |
1 |
bDescriptorType |
1 |
Constant |
Строковый дескриптор (0x03) |
2 |
bString |
n |
Unicode |
Строка, закодированная в Unicode |
[Глава 6: запросы USB]
Пакет Setup
Любое устройство USB должно ответить на пакеты установки (setup) по каналу по умолчанию (default pipe, конечная точка 0). Пакеты setup используются для обнаружения и конфигурирования устройства, и выполняют общие функции, такие как установка адреса устройства USB, запрос описателя устройства или проверка состояния конечной точки.
USB-совместимый хост предполагает, что все запросы будут обработаны в пределах максимального периода 5 секунд. Также определены более строгие лимиты времени для определенных запросов:
- Standard Device request (стандартный запрос к устройству) без стадии данных должен быть завершен в течение 50 мс.
- Standard Device request со стадией данных должен начать передавать данные не позже чем через 500 мс после запроса.
Каждый пакет данных должен быть отправлен в течение 500 мс после успешного завершения передачи предыдущего пакета. Стадия состояния должна быть завершена в течение 50 мс после передачи последнего пакета данных.
- Команда SetAddress (которая содержит фазу данных) должна быть обработана и вернуть статус в течение 50 мс. Устройство тогда имеет 2 мс, чтобы изменить адрес прежде, чем будет послан следующий запрос.
Эти периоды времени ожидания являются весьма приемлемыми для даже самого медленного из устройств, но могут быть ограничением во время отладки. Невозможно обеспечить 50 мс для многих отладочных символов, отправляемых на скорости 9600 bps через асинхронный последовательный порт, или во внутрисхемных отладчиках/эмуляторах при выполнении программы по шагам или при остановке по точке останова для просмотра внутренних регистров и переменных. Поэтому USB требует специальной техники отладки в отличие от других проектов на микроконтроллерах.
Бегло просматривая XP DDK, я заметил, что Host Controller Driver теперь имеет команду USBUSER_OP_SEND_ONE_PACKET, которая прокомментирована так:"Это API используется для реализации 'пошаговой отладки' в инструменте разработки транзакций USB (USB transaction development tool)." Такой инструмент еще не был выпущен. Мы можем только надеяться, что скоро его увидим.
Каждый запрос начинается с пакета Setup длиной 8 байт, который имеет следующий формат:
Смещ. |
Поле |
Размер |
Значение |
Описание |
0 |
bmRequestType |
1 |
Набор битов (BitMap) |
D7 направление передачи фазы данных 0 = хост передает в устройство 1 = устройство передает на хост D6..5 тип 0 = Standard 1 = Class 2 = Vendor 3 = зарезервировано D4..0 получатель 0 = устройство 1 = интерфейс 2 = конечная точка 3 = другое 4..31 = зарезервировано |
1 |
bRequest |
1 |
Значение |
Запрос |
2 |
wValue |
2 |
Значение |
Значение |
4 |
wIndex |
2 |
Индекс или смещение |
Индекс |
6 |
wLength |
2 |
Счетчик |
Если это фаза данных, то количество байт данных для передачи |
Поле bmRequestType определит направление запроса, тип запроса и назначенного получателя. Поле bRequest определит делаемый запрос. Поле bmRequestType анализируется, и выполнение ответвляется на несколько обработчиков, таких как Standard Device request handler (стандартный обработчик запроса устройства), Standard Interface request handler (стандартный обработчик запроса интерфейса), Standard Endpoint request handler (стандартный обработчик запроса конечной точки), Class Device request handler (классовый обработчик запроса устройства) и т. п. То, как Вы проанализируете пакет setup, зависит только от Ваших предпочтений. Кто-то еще может захотеть сначала анализировать bRequest и потом определить тип запроса и его получателя на основании каждого запроса.
Стандартные запросы являются общими для всех устройств USB и подробно рассмотрены на последующих страницах. Классовые запросы являются общими для классов драйверов. Например, все устройства, относящиеся к классу HID, будут иметь единый набор запросов, специфичных для класса. Они будут отличаться от запросов устройства, относящегося к классу communication или относящегося к классу mass storage.
И наконец – запросы, определенные вендором (производителем). Это запросы, которые Вы как разработчик устройства USB, можете назначить сами. Эти запросы отличаются от устройства к устройству (что нормально), но это все делается исключительно под Вашу реализацию алгоритма работы устройства.
Общие запросы могут быть перенаправлены на различных получателей, и в зависимости от конкретного получателя выполнять разные функции. Например, стандартный запрос GetStatus может быть направлен на устройство, интерфейс или конечную точку. Когда он направлен на устройство, он возвращает флаги, показывающие статус удаленного пробуждения (remote wakeup), и является ли устройство самопитаемым. Однако тот же запрос, направленный к интерфейсу, всегда вернет 0, или если запрос будет направлен на конечную точку, то он вернет состояние флага halt (флаг останова) для конечной точки.
Поля wValue и wIndex позволяют передавать параметры вместе с запросом, а поле wLength используется для указания количества байт, которые должны быть переданы на фазе данных.
Примечание переводчика: иногда поля wValue и wIndex применяют для передачи данных без участия специальной фазы данных (в поле wLength указывают 0), в этом случае можно передать не больше 4 байт. Пример такого использования таких управляющих запросов для передачи данных в обе стороны можно найти в примере hid-custom-rq из библиотеки V-USB (http://ru.wikipedia.org/wiki/V-USB), или в статье «V-USB и libusb: обмен с устройством USB HID с помощью управляющих сообщений (USB control messages)» http://microsin.ru/content/view/1084/44/.
Стандартные запросы
Секция 9.4 спецификации USB подробно описывают запросы "Standard Device", которые необходимо реализовать для каждого устройства USB. Стандарт предоставляет одну таблицу, группирующую запросы. Приняв во внимание, что большинство firmware анализирует пакет setup packet по получателю, мы можем разбить запросы на основе получателя для более простой обработки и реализации.
Стандартные запросы к устройству
В настоящий момент имеется 8 стандартных запросов к устройству, все они указаны в таблице ниже.
bmRequestType |
bRequest |
wValue |
wIndex |
wLength |
Data |
1000 0000b |
GET_STATUS (0x00) |
0 |
0 |
2 |
Статус устройства |
0000 0000b |
CLEAR_FEATURE (0x01) |
Селектор фичи |
0 |
0 |
Нет |
0000 0000b |
SET_FEATURE (0x03) |
Селектор фичи |
0 |
0 |
Нет |
0000 0000b |
SET_ADDRESS (0x05) |
Адрес устройства |
0 |
0 |
Нет |
1000 0000b |
GET_DESCRIPTOR (0x06) |
Тип дескриптора и индекс |
0 или ID языка |
Длина дескриптора |
Дескриптор |
0000 0000b |
SET_DESCRIPTOR (0x07) |
Тип дескриптора и индекс |
0 или ID языка |
Длина дескриптора |
Дескриптор |
1000 0000b |
GET_CONFIGURATION (0x08) |
0 |
0 |
1 |
Значение конфигурации |
0000 0000b |
SET_CONFIGURATION (0x09) |
Configuration Value |
0 |
0 |
Нет |
- Запрос Get Status, направленный на устройство, вернет 2 байта на стадии данных в следующем формате:
D15 |
D14 |
D13 |
D12 |
D11 |
D10 |
D9 |
D8 |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
Зарезервировано |
Remote Wakeup |
Self Powered |
- Если бит D0 (Self Powered) установлен, то это указывает на самопитаемое устройство (у устройства имеется собственный источник питания, и оно ничего не потребляет от шины USB), а если очищен, то устройство bus powered (питается от провода Vbus шины USB). Если бит D1 установлен, то у устройства разрешена возможность удаленного пробуждения хоста от спячки или приостановки (Remote Wakeup). Бит remote wakeup может быть изменен запросами SetFeature и ClearFeature с селектором фичи равным DEVICE_REMOTE_WAKEUP (0x01)
- Запросы Clear Feature и Set Feature могут использоваться для сброса или установки булевых (boolean) фич. Когда получатель – устройство, то возможны только два селектора фичи DEVICE_REMOTE_WAKEUP и TEST_MODE. Режим тестирования позволяет устройству выдавать (показывать) некоторые условия. Они позже были документированы в Ревизии 2.0 спецификации USB.
- Запрос Set Address используется во время энумерации для того, чтобы назначить уникальный адрес устройству USB. Адрес указывается в поле wValue и может принимать значение не более 127. Этот запрос уникален тем, что устройство не меняет свой адрес, пока не завершится стадия статуса (см. Control Transfers). Все другие запросы должны выполниться до стадии статуса.
- Запросы Set Descriptor/Get Descriptor используются для возврата дескриптора, указанного в wValue. Запрос для дескриптора конфигурации вернет дескриптор устройства и все дескрипторы интерфейса и конечной точки в одном запросе. Endpoint Descriptors (дескрипторы конечной точки) не могут быть запрошены напрямую запросами GetDescriptor/SetDescriptor. Interface Descriptors (дескрипторы интерфейса) не могут быть запрошены напрямую запросами GetDescriptor/SetDescriptor. String Descriptors (строковые дескрипторы) включают Language ID (идентификатор языка) в поле wIndex – для поддержки нескольких языков.
- Запросы Get Configuration/Set Configuration используются для запроса или установки текущей конфигурации устройства. В случае запроса Get Configuration будет возвращен байт на стадии данных, показывающий статус устройства. Нулевая величина показывает, что устройство не сконфигурировано, и ненулевое значение показывает, что устройство сконфигурировано. Set Configuration используется для разрешения (enable) устройства. Этот запрос должен содержать величину поля bConfigurationValue желаемого configuration descriptor (дескриптора конфигурации) в младшем байте wValue – для выбора разрешаемой конфигурации.
Стандартные запросы к интерфейсу
Спецификация в настоящий момент задает 5 стандартных запросов к интерфейсу, показанные в таблице ниже. Что интересно - только два запроса делают что-нибудь понятное.
bmRequestType |
bRequest |
wValue |
wIndex |
wLength |
Data |
1000 0001b |
GET_STATUS (0x00) |
0 |
Интерфейс |
2 |
Состояние интерфейса |
0000 0001b |
CLEAR_FEATURE (0x01) |
Селектор фичи |
Интерфейс |
0 |
Нет |
0000 0001b |
SET_FEATURE (0x03) |
Селектор фичи |
Интерфейс |
0 |
Нет |
1000 0001b |
GET_INTERFACE (0x0A) |
0 |
Интерфейс |
1 |
Альтернативный интерфейс |
0000 0001b |
SET_INTERFACE (0x11) |
Альтернативная установка |
Интерфейс |
0 |
Нет |
- Поле wIndex используется для указания ссылки на нужный интерфейс для запросов, направленных к интерфейсу. Формат поля следующий:
D15 |
D14 |
D13 |
D12 |
D11 |
D10 |
D9 |
D8 |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
Зарезервировано |
Номер интерфейса |
- Запрос Get Status используется для возврата статуса (состояния интерфейса). Такой запрос к интерфейсу должен возвратить два байта 0x00, 0x00 (оба байта зарезервированы для использования в будущем).
- Запросы Clear Feature и Set Feature могут использоваться для очистки и сброса булевых фич. Когда назначенный получатель – интерфейс, спецификация USB ревизии 2 не указывает конкретных фич интерфейса.
- Запросы Get Interface и Set Interface получают и устанавливают Alternative Interface (альтернативный интерфейс), который более подробно описан Interface Descriptor (дескриптором интерфейса).
Стандартные запросы к конечной точке
Запросы Standard Endpoint бывают 4-х видов, перечисленных в таблице ниже.
bmRequestType |
bRequest |
wValue |
Windex |
wLength |
Data |
1000 0010b |
GET_STATUS (0x00) |
0 |
Конечная точка |
2 |
Состояние конечной точки |
0000 0010b |
CLEAR_FEATURE (0x01) |
Селектор фичи |
Конечная точка |
0 |
Нет |
0000 0010b |
SET_FEATURE (0x03) |
Селектор фичи |
Конечная точка |
0 |
Нет |
1000 0010b |
SYNCH_FRAME (0x12) |
0 |
Конечная точка |
2 |
Номер фрейма |
- Поле wIndex в запросах к конечной точке используется для указания целевой конечной точки и направления запросов. Формат поля следующий:
D15 |
D14 |
D13 |
D12 |
D11 |
D10 |
D9 |
D8 |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
Зарезервировано |
Dir (направление) |
Зарезервировано |
Номер конечной точки |
- Запрос Get Status возвращает 2 байта, в которых возвращается статус конечной точки (пока только бит Halted/Stalled, т. е. бит приостановки). Формат двух возвращаемых байт показан ниже:
D15 |
D14 |
D13 |
D12 |
D11 |
D10 |
D9 |
D8 |
D7 |
D6 |
D5 |
D4 |
D3 |
D2 |
D1 |
D0 |
Зарезервировано |
Halt |
- Запрос Clear Feature и Set Feature используется для установки фич конечной точки. Стандарт в настоящее время определяет один селектор фичи конечной точки ENDPOINT_HALT (0x00), который позволяет хосту приостановить и очистить конечную точку. Только оконечным точкам, кроме заданной по умолчанию конечной точки (конечная точка 0) рекомендуют иметь эти функциональные возможности.
- Запрос Synch Frame используется, чтобы сообщить о кадре синхронизации конечной точки.
Глава 7 : обычный (Generic) драйвер USB
Энумерация
Энумерация – процесс определения факта, что устройство действительно подключено к шине USB и каких параметров это требует – потребляемая мощность, количество и тип конечной точки (или точек), класс устройства и т. д. В процессе энумерации хост назначает устройству адрес и разрешает конфигурацию, позволяющую устройству передавать данные по шине. Обычный процесс энумерации хорошо описан в секции 9.1.2 спецификации USB. Однако когда USB firmware пишется впервые, полезно знать не общий процесс энумерации, как он описан в стандарте, а то, как хост отвечает в процессе энумерации.
Общий процесс энумерации под операционной системой Windows включает в себя следующие шаги:
1. Хост или хаб детектирует подключение нового устройства с помощью pull-up резисторов, которое устройство подключает к паре сигнальных проводов данных (D+ и D-). Хост делает задержку как минимум 100 мс, что позволяет вставить коннектор полностью и застабилизировать питание устройства. 2. Хост выдает на шину сброс, который выводит устройство в состояние по умолчанию. Устройство может теперь ответить на заданный по умолчанию нулевой адрес. 3. Хост MS Windows запрашивает первые 64 байта дескриптора устройства (Device Descriptor). 4. После приема первых 8 байт дескриптора устройства, хост немедленно выдает новый сброс шины. 5. Теперь хост выдает команду Set Address, чем переводит устройство в адресуемое состояние. 6. Хост запрашивает все 18 байт дескриптора устройства. 7. Затем он запрашивает 9 байт дескриптора конфигурации (Configuration Descriptor), чтобы определить полный её размер. 8. Хост запрашивает 255 байт дескриптора конфигурации. 9. Хост запрашивает все строковые дескрипторы (String Descriptors), если они имеются.
По окончании шага 9 Windows запросит драйвер для Вашего устройства. Обычно он снова запросит все дескрипторы, перед тем как выдаст запрос Set Configuration.
Вышеописанный процесс энумерации работает одинаково в Windows 2000, Windows XP and Windows 98 SE.
При написании firmware в первый раз шаг 4 часто вводит новичков в затруднение. Хост запрашивает первые 64 байта дескриптора устройства, а затем когда хост сбрасывает Ваше устройство после получения первых 8 байт, естественно думать, что что-то не так с Вашим дескриптором устройства, или что firmware неправильно обрабатывает запрос. Однако если Вы осуществили команду Set Address, то она сработает, и затем будут запрошены полные 18 байт дескриптора устройства.
Обычно если что-то неправильно с дескриптором или с тем, как он был отправлен, хост попытается прочитать его 3 раза с большой паузой между запросами. После третьей неудачной попытки хост «сдается» и сообщает об ошибке с Вашим устройством.
[Окончание статьи...] |
Комментарии
Цитата:
3. Хост MS Windows запрашивает первые 64 байта дескриптора устройства (Device Descriptor).
4. После приема первых 8 байт дескриптора устройства, хост немедленно выдает новый сброс шины. 5. Теперь хост выдает команду Set Address, чем переводит устройство в адресуемое состояние.
6. Хост запрашивает все 18 байт дескриптора устройства.
Получается, хост запрашивает первые 64 байта, затем (приняв 8 из них) следует сброс, и затем читает полные 18 (???как тогда запрашивали 64???).
Исходя из текста, мне хочется думать, что на шаге 3 хост запрашивает все-таки 8 байт, а уже потом (после сброса) читает все 18 заново.
Это опечатка, или я все же понял неправильно?
P.S. не могу подписаться своим ником, т.к. такой уже занят = )
RSS лента комментариев этой записи