Ошибка STALL USB и отладка управляющих передач: разбор setup-пакета, bmRequestType, bRequest, wValue, wIndex
Исправление ошибок STALL и сбоев управляющих USB-передач. Диагностика setup-пакетов по bmRequestType, bRequest, wValue, wIndex и свидетельства запросов дескрипторов для отладки прошивок.
Управляющие USB-передачи — это первый серьёзный диалог между хостом и устройством. От них зависит перечисление. От них зависит настройка класса. От них часто зависит и вендорная инициализация. Когда управляющая передача падает, пользователь видит только «устройство не распознано» или «сбой драйвера», но доказательства почти всегда лежат в setup-пакете.
Для инженера по прошивкам умение читать bmRequestType, bRequest, wValue, wIndex и wLength — один из самых быстрых способов перейти от догадок к точечному исправлению.
Setup-пакет — это контракт запроса
Setup-пакет USB сообщает устройству:
- направление передачи
- тип запроса: стандартный, классовый, вендорный или зарезервированный
- получатель: устройство, интерфейс, конечная точка или другое
- код запроса
- поле значения
- индексное поле
- ожидаемый размер данных
Если прошивка декодирует эти поля неправильно, она может вернуть неверный дескриптор, застопорить корректный запрос через STALL или принять неверную команду. Если хост посылает неожиданный запрос, захват это тоже покажет.
GET_DESCRIPTOR — первое место для проверки
Во время перечисления хост отправляет стандартные запросы дескрипторов. Типичная картина выглядит так:
- запрос дескриптора устройства
- запрос дескриптора конфигурации
- запрос строкового дескриптора
- запрос HID report descriptor для HID-устройств
- запрос BOS-дескриптора на новых хостах
В setup-пакете bRequest идентифицирует GET_DESCRIPTOR, а wValue включает тип дескриптора и индекс. wIndex может задавать language ID для строковых дескрипторов или интерфейс для классовых. wLength говорит, сколько байт ждёт хост.
Когда длина ответа дескриптора неверна или когда прошивка возвращает меньше байт, чем требуется хосту, перечисление может позже упасть так, что это выглядит несвязанным.
Ошибки в направлении обходятся дорого
Управляющие передачи имеют направление. Запросы «устройство → хост» возвращают данные. Запросы «хост → устройство» несут данные или меняют состояние. Если прошивка трактует запрос на чтение как запись или возвращает данные во время запроса на запись, хост не будет вежливо угадывать намерение.
Следите за:
- направлением IN, но без data-стадии
- направлением OUT, но прошивка ждёт отправку данных
- отсутствием status-стадии нулевой длины
- STALL на корректном стандартном запросе
- классовым запросом, обработанным не тем интерфейсом
В захвате должны быть видны запрос, data-стадия и status-стадия.
Классовые и вендорные запросы требуют контекста интерфейса
После перечисления классовые драйверы шлют классовые запросы. CDC может слать запросы line coding. HID может запрашивать report descriptor или feature reports. Вендорные утилиты могут слать команды инициализации. Одно и то же значение bRequest может означать разное в зависимости от типа запроса и получателя.
Изучите:
- тип запроса
- получателя
- номер интерфейса в
wIndex - номер конечной точки, если получатель — конечная точка
- байты полезной нагрузки
- ответ или stall
Если в составном устройстве несколько интерфейсов, маршрутизация запроса на неправильный интерфейс — типичная ошибка.
Как Bus Scope помогает
Bus Scope создан для USB-доказательств. Отладка управляющих передач требует одновременно декодированных полей setup и сырых байт. Лучший вид позволяет инженеру читать семантические поля и при этом сверяться с точными байтами пакета.
Полезный сеанс Bus Scope для отладки управляющих передач должен давать ответы на такие вопросы:
- какой setup-пакет упал?
- это был стандартный, классовый или вендорный запрос?
- какой дескриптор или интерфейс запрашивался?
- вернуло ли устройство ожидаемую длину?
- был ли STALL намеренным или ошибочным?
- зависел ли следующий шаг перечисления от этого ответа?
О проблеме могут писать как «USB control transfer failed», но исправление почти всегда прячется в setup-пакете из пяти полей.