Что такое usb hid
СОДЕРЖАНИЕ
Устройства
Класс USB HID описывает устройства, используемые практически на каждом современном компьютере. В классе USB HID существует множество предопределенных функций. Эти функции позволяют производителям оборудования разрабатывать продукт в соответствии со спецификациями класса USB HID и ожидать, что он будет работать с любым программным обеспечением, которое также соответствует этим спецификациям.
Клавиатуры
Некоторые клавиатуры реализуют профиль загрузочной USB-клавиатуры, указанный в определении класса USB-устройств для устройств с интерфейсом пользователя (HID) v1.11, и явно настроены на использование протокола загрузки. Они ограничены 6-клавишным переключением клавиш (6KRO) и будут прерывать работу ЦП каждый раз при опросе клавиатуры (даже если нет изменения состояния), если USB-контроллер не отменяет это поведение. Этот профиль предназначен для того, чтобы BIOS могла работать с USB-клавиатурой в отсутствие операционной системы, поддерживающей USB. Рекомендуемый профиль для клавиатур, которые не находятся в режиме загрузки в этой спецификации, ограничивает количество клавиатур до 6KRO и заставляет их отвечать на прерывание отчетом о состоянии не реже, чем каждые полсекунды (опять же, даже если нет изменения состояния), чтобы реализовать typematic (повторение скан-кода при достаточно долгом нажатии клавиши), если USB-контроллер не запрограммирован так, чтобы клавиатура не делала этого. Однако клавиатуры в режиме без загрузки могут использовать альтернативный профиль HID.
Вышеупомянутое поведение отличается от интерфейса PS / 2 (не путать с PlayStation 2), который поддерживает одновременное нажатие клавиш n (NKRO) для клавиатур, способных его поддерживать. Интерфейс PS / 2 вообще не прерывает работу ЦП, когда нет изменений состояния, за исключением случаев, когда клавиша удерживается достаточно долго, чтобы активировать typematic. Отсутствие необходимости отвечать на повторный опрос экономит электроэнергию, поэтому интерфейс PS / 2 часто используется во внутренних клавиатурах ноутбуков.
мышей
USB-мыши имеют меньшую задержку, чем мыши PS / 2, потому что стандартные USB-мыши часто опрашиваются с частотой по умолчанию 125 Гц, в то время как стандартные мыши PS / 2 отправляют прерывания с частотой по умолчанию 100 Гц, когда у них есть данные для отправки на компьютер. Кроме того, USB-мыши не заставляют USB-контроллер прерывать работу системы, если у них нет изменений состояния, чтобы сообщить о них в соответствии с профилем по умолчанию спецификации USB HID для устройств мыши. И PS / 2, и USB позволяют переопределить частоту дискретизации, причем PS / 2 поддерживает частоту дискретизации до 200 Гц, а USB поддерживает частоту опроса до 1 кГц, пока USB-мышь работает на полной скорости или выше. Скорость USB.
Благодаря тому, что интерфейс мыши PS / 2 управляется прерываниями и не требует периодического опроса, интерфейс PS / 2 экономит электроэнергию, что делает его популярным выбором для указывающих устройств, встроенных в ноутбуки.
Игровые контроллеры
Другие устройства
Спецификации класса USB HID позволяют использовать множество других устройств в классе USB HID. Некоторыми примерами являются контроллеры для моделирования автомобилей, тренажеры, телефонные устройства, термометры, средства управления аудиосистемой и медицинские приборы. Даже источники бесперебойного питания и программные защитные ключи заявляют о себе под этим классом, несмотря на то, что зачастую они вообще не имеют человеческого интерфейса. Любое устройство может быть устройством класса USB HID, если разработчик соответствует логическим спецификациям класса USB HID. Это не означает, что нет необходимости поставлять драйверы для этих устройств или что операционная система немедленно распознает устройство. Это означает только то, что устройство может объявить себя в классе устройства интерфейса пользователя.
Уязвимости безопасности
Интерфейс USB уязвим для уязвимостей безопасности, таких как BadUSB, которые злоупотребляют комбинацией способности USB подключать множество различных типов устройств, его неспособностью проверить, действительно ли устройства являются тем, за что они претендуют, возможностью для USB-устройств изменить свой тип или объявляет о дополнительных подустройствах, когда они подключены, и о своем поведении по умолчанию, принимающем любое подключенное к нему устройство. В качестве частичной меры противодействия вместо этого можно использовать периферийные устройства PS / 2 с отключением всех портов USB.
Драйверы
Одним из преимуществ четко определенной спецификации, такой как класс USB HID, является обилие драйверов устройств, доступных в большинстве современных операционных систем. Устройства класса USB HID и их основные функции определены в документации USB-IF без учета какого-либо специального программного обеспечения. Благодаря этим общим описаниям разработчики операционных систем могут легко включить работающие драйверы для таких устройств, как клавиатуры, мыши и другие универсальные устройства с интерфейсом пользователя. Включение этих универсальных драйверов позволяет ускорить развертывание устройств и упростить установку конечным пользователям.
Логические спецификации
Функциональные характеристики
Класс USB-устройства с интерфейсом пользователя можно использовать для описания классов устройств и интерфейсов. Класс интерфейса используется, когда устройство USB может содержать более одной функции. Следовательно, можно иметь USB-устройства с двумя разными интерфейсами одновременно (например, USB-телефон может использовать клавиатуру, относящуюся к классу HID, и динамик, относящийся к классу USB-устройств связи ).
Отчеты
Класс USB HID требует, чтобы каждое устройство описывало, как оно будет взаимодействовать с главным устройством, чтобы точно предсказать и определить все текущие и будущие устройства с интерфейсом пользователя. Во время перечисления устройство описывает, как должны быть структурированы его отчеты, чтобы хост-устройство могло должным образом подготовиться к приему этой информации.
Хост периодически опрашивает конечную точку прерывания IN устройства во время работы. Когда у устройства есть данные для отправки, оно формирует отчет и отправляет его в качестве ответа на токен опроса. Обычные устройства, такие как клавиатуры и мыши, отправляют отчеты, соответствующие стандартам, установленным Форумом разработчиков USB (USB-IF). Когда поставщик создает пользовательское устройство класса USB HID, отчеты, формируемые устройством, должны соответствовать описанию отчета, приведенному во время перечисления, и драйверу, установленному в хост-системе. Таким образом, класс USB HID может быть чрезвычайно гибким.
USB HID API
STM Урок 34. HAL. USB. HID
Урок 34
HAL. USB. HID
Сегодня мы познакомимся с новым классом для USB — это Human Interface Device или как в народе говорят HID.
Данный класс отличается тем, что здесь мы посылаем короткие сообщения, у нас особой вероятности в том, что наши данные все дойдут, но в данный момент это не совсем и важно. Как правило скорость настраивается так, что данные все равно доходят. Самое главное, чтобы данные доходили быстро, поэтому такие интерфейсы, такие классы используют при программировании таких устройств, как манипулятор мышь, джойстик. клавиатура и им подобных. HID класс может быть как предопределённым, то есть предназначенным для конкретных существующих типов устройств, так и произвольный (custom). Со вторым типом мы немного поработаем на следующим занятием, а сегодня поработаем с первым классом и попробуем эмулировать манипулятор «мышь».
И чтобы с данным классом немного поподробнее разобраться, мы попробуем его реализовать в нашем контроллере STM32F407VG.
Для этого мы сначала конечно же сделаем проект.
Проект создаём из проекта TEST002. Назовем его USB_DEVICE_HID. Запустим проект в Cube, отключим выходные светодиоды, кнопку оставим
Включим USB_OTG_FS в режим Device_Only.
В USB Device выбираем Human Interface Device Class (HID)
В Clock Configuration выберем следующие делители
В Configuration ничего не трогаем.
Сгенерируем и запустим проект.
Соберем проект и настроим программатор на авторезет.
Скачаем файл USB Library User manual.pdf с официального сайта ST Microelectronics и откроем его на странице 39. Там дана функция отправки отчета устройством на host. В качестве хоста у нас будет выступать ПК
Подключим файл в main.c
/* USER CODE END Includes */
Добавим переменные туда же
/* USER CODE BEGIN PV */
#define CURSOR_STEP 1
extern USBD_HandleTypeDef hUsbDeviceFS;
Напишем функцию подготовки буфера для передачи в шину
static void GetPointerData(uint8_t *pbuf)
static uint8_t cnt = 0; //счетчик циклов
static uint8_t drct = 0; //направление курсора
Работаем с USB Custom HID на Android
В современных Android — приложениях для взаимодействия с другими устройствами чаще всего используются беспроводные протоколы передачи данных, как например Bluetooth. В годы, когда часть устройств имеют беспроводную зарядку, сложно представить себе связку Android устройства и периферийного модуля, в которой необходимо использование проводных интерфейсов. Однако когда такая необходимость возникает, на ум сразу же приходит USB.
Давайте разберем с вами гипотетический кейс. Представьте, что к вам приходит заказчик и говорит: “Мне нужно Android приложение для управления устройством сбора данных и вывода этих самых данных на экран. Есть одно НО — приложение надо написать на одноплатный компьютер с операционной системой Android, а периферийное устройство подключено по USB”
Звучит фантастически, но и такое иногда случается. И тут как нельзя кстати пригодится глубокое знание USB стека и его протоколов, но данная статья не об этом. В данной статье мы рассмотрим, как управлять периферийным устройством по протоколу USB Custom HID с Android устройства. Для простоты напишем Android-приложение (HOST), которое будет управлять светодиодом на периферийным устройством (DEVICE) и получать состояние кнопки (нажатия). Код для периферийной платы приводить не буду, кому интересно — пишите в комментариях.
Итак, приступим.
Теория. Максимально коротко
Для начала немного теории, максимально коротко. Это упрощенный минимум, достаточный для понимания кода, но для большего понимания советую ознакомиться с этим ресурсом.
Для общения по USB на периферийном устройстве необходимо реализовать интерфейс взаимодействия. Разные функции (например, USB HID, USB Mass Strorage или USB CDC) будут реализовывать свои интерфейсы, а некоторые будут иметь несколько интерфейсов. Каждый интерфейс содержит в себе конечные точки — специальные каналы связи, своего рода буферы обмена.
На моем периферийном устройстве реализован Custom HID с одним интерфейсом и с двумя конечными точками, одной для приёма, другой для передачи. Обычно информация с существующими на устройстве интерфейсами и конечными точками написана в спецификации на устройство, в противном случае определить их можно через специальные программы, к примеру USBlyzer.
Устройства в USB HID общаются через репорты. Что такое репорты? Так как данные передаются через конечные точки, то нам надо как-то идентифицировать, а также распарсить в соответствие с протоколом. Устройства не просто кидают друг другу байты данных, а обмениваются пакетами, имеющими четко определенную структуру, которая описывается на устройстве в специальном дескрипторе репорта. Таким образом, по дескриптору репорта, мы можем точно определить, какой идентификатор, структуру, размер и частоту передачи имеют те или иные данные. Идентификация пакета происходит по первому байту, который представляет из себя ID репорта. Например данные о состоянии кнопки, идут в репорта с а светодиодом мы управляем через репорт с >
Подальше от железа, поближе к Android
В Android поддержка USB устройств появилась начиная с API версии 12 (Android 3.1) Для работы с периферийным устройством нам необходимо реализовать режим USB host. Работа с USB достаточно неплохо описана в документации.
Для начала необходимо идентифицировать ваше подключаемое устройство, среди всего разнообразия USB девайсов. USB девайсы идентифицируются по сочетанию vid (vendor id) и pid (product id). Создадим в папке xml файл device_filter.xml со следующим содержимым:
Теперь необходимо внести соответствующие разрешения и action (если вам они необходимы) в манифест приложения:
В android:resource мы указываем файл с необходимыми фильтрами для устройств. Также, как я уже говорил ранее, можно назначить intent фильтры, для запуска приложения, к примеру, в результате подключения вашего устройства.
Для начала необходимо получить UsbManager, найти устройство, интерфейс и конечные точки устройства. Это необходимо делать при каждом подключении устройства.
Здесь мы видим те самые интерфейсы и конечные точки, речь о которых шла в прошлом разделе. Зная номер интерфейса, мы находим обе конечные точки, на прием и передачу, и инициируем usb соединение. На этом все, теперь можно читать данные.
Как я уже говорил ранее, устройства общаются через репорты.
В метод sendReport мы передаем массив байт, в котором нулевым байтом является репорт ID, берем текущее USB подключение к устройству и выполняем передачу. В качестве параметров в метод BulkTransfer передаем номер конечной точки, данные, их размер и таймаут передачи. Стоит отметить, что класс UsbDeviceConnection имеет методы для реализации обмена данными с устройством USB — методы bulkTransfer и controlTransfer. Их использование зависит от типа передачи, который поддерживает та или иная конечная точка. В данном случае используем bulkTransfer, хотя для HID чаще всего характерно использование конечных точек с типом control. Но у нас Custom HID, так что делаем что хотим. Про тип передачи советую почитать отдельно, так как от него зависит объем и частота передаваемых данных.
Для получения данных необходимо знать размер получаемых данных, который можно, как знать заранее, так и получить из конечной точки.
Метод получения данных по USB HID является синхронным и блокирующим и выполнять его необходимо в другом потоке, кроме того, репорты от устройства могут приходить постоянно, либо в любое время, поэтому необходимо реализовать постоянный опрос репорта, чтобы не пропустить данные. Сделаем это при помощи RxJava:
Получив массив байт, мы должны проверить нулевой байт, так как он является report ID и в соответствии с ним парсить полученные данные.
По завершении всех действий с USB нужно закрыть соединение. Можно выполнять это в onDestroy activity или в onCleared во ViewModel.
Заключение
В статье рассмотрен очень небольшой и примитивный, исключительно демонстративный код с реализацией для конкретного устройства. Конечно, классов USB существует много, не только HID и для них естественно реализация будет иная. Однако все методы достаточно неплохо документированы и имея хорошее представление о USB стеке можно легко разобраться в том, как их применять.
USB на регистрах: interrupt endpoint на примере HID
Продолжаем разбираться с USB на контроллерах STM32L151. Как и в предыдущей части, ничего платформо-зависимого здесь не будет, зато будет USB-зависимое. Если точнее, будем рассматривать третий тип конечной точки — interrupt. И делать мы это будем на примере составного устройства «клавиатура + планшет» (ссылка на исходники).
На всякий случай предупреждаю: данная статья (как и все остальные) — скорее конспект того, что я понял, разбираясь в этой теме. Многие вещи так и остались «магией» и я буду благодарен если найдется специалист, способный объяснить их.
Первым делом напомню, что протокол HID (Human Interface Device) не предназначен для обмена большими массивами данных. Весь обмен строится на двух понятиях: событие и состояние. Событие это разовая посылка, возникающая в ответ на внешнее или внутреннее воздействие. Например, пользователь кнопочку нажал или мышь передвинул. Или на одной клавиатуре отключил NumLock, после чего хост вынужден и второй послать соответствующую команду, чтобы она это исправила, также послав сигнал нажатия NumLock и включила его обратно отобразила это на индикаторе. Для оповещения о событиях и используются interrupt точки. Состояние же это какая-то характеристика, которая не меняется просто так. Ну, скажем, температура. Или настройка уровня громкости. То есть что-то, посредством чего хост управляет поведением устройства. Необходимость в этом возникает редко, поэтому и взаимодействие самое примитивное — через ep0.
Таким образом назначение у interrupt точки такое же как у прерывания в контроллере — быстро сообщить о редком событии. Вот только USB — штука хост-центричная, так что устройство не имеет права начинать передачу самостоятельно. Чтобы это обойти, разработчики USB придумали костыль: хост периодически посылает запросы на чтение всех interrupt точек. Периодичность запроса настраивается последним параметром в EndpointDescriptor’е (это часть ConfigurationDescriptor’а). В прошлых частях мы уже видели там поле bInterval, но его значение игнорировалось. Теперь ему наконец-то нашлось применение. Значение имеет размер 1 байт и задается в миллисекундах, так что опрашивать нас будут с интервалом от 1 мс до 2,55 секунд. Для низкоскоростных устройств минимальный интервал составляет 10 мс. Наличие костыля с опросом interrupt точек для нас означает, что даже в отсутствие обмена они будут впустую тратить полосу пропускания шины.
Логичный вывод: interrupt точки предназначены только для IN транзакций. В частности, они используются для передачи событий от клавиатуры или мыши, для оповещения об изменении служебных линий COM-порта, для синхронизации аудиопотока и тому подобных вещей. Но для всего этого придется добавлять другие типы точек. Поэтому, чтобы не усложнять пример, ограничимся реализацией HID-устройства. Вообще-то, такое устройство мы уже делали в первой части, но там дополнительные точки не использовались вовсе, да и структура HID-протокола рассмотрена не была.
ConfigurationDescriptor
Внимательный читатель тут же может обратить внимание на описания конечных точек. Со второй все в порядке — IN точка (раз произведено сложение с 0x80) типа interrupt, заданы размер и интервал. А вот первая вроде бы объявлена как OUT, но в то же время interrupt, что противоречит сказанному ранее. Да и здравому смыслу тоже: хост не нуждается в костылях чтобы передать в устройство что угодно и когда угодно. Но таким способом обходятся другие грабли: тип конечной точки в STM32 устанавливается не для одной точки, а только для пары IN/OUT, так что не получится задать 0x81-й точке тип interrupt, а 0x01-й control. Впрочем, для хоста это проблемой не является, он бы, наверное, и в bulk точку те же данные посылал… что, впрочем, я проверять не стану.
HID descriptor
Структура HID descriptor’а больше всего похожа на конфигурационных файл «имя=значение», но в отличие от него, «имя» представляет собой числовую константу из списка USB-специфичных, а «значение» — либо тоже константу, либо переменную размером от 0 до 3 байт.
Важно: для некоторых «имен» длина «значения» задается в 2 младших битах поля «имени». Например, возьмем LOGICAL_MINIMUM (минимальное значение, которое данная переменная может принимать в штатном режиме). Код этой константы равен 0x14. Соответственно, если «значения» нет (вроде бы такого не бывает, но утверждать не буду — зачем-то же этот случай ввели), то в дескрипторе будет единственное число 0x14. Если «значение» равно 1 (один байт) то записано будет 0x15, 0x01. Для двухбайтного значения 0x1234 будет записано 0x16, 0x34, 0x12 — значение записывается от младшего к старшему. Ну и до кучи число 0x123456 будет 0x17, 0x56, 0x34, 0x12.
Естественно, запоминать все эти числовые константы мне лень, поэтому воспользуемся макросами. К сожалению, я так и не нашел способа заставить их самостоятельно определять размер переданного значения и разворачиваться в 1, 2, 3 или 4 байта. Поэтому пришлось сделать костыль: макрос без суффикса отвечает за самые распространенные 8-битные значения, с суффиксом 16 за 16-битные, а с 24 — за 24-битные. Также были написаны макросы для «составных» значений вроде диапазона LOGICAL_MINMAX24(min, max), которые разворачиваются в 4, 6 или 8 байтов.
Как и в конфигурационных файлах, здесь присутствуют «секции», называемые страницами (usage_page), которые группируют устройства по назначению. Скажем, есть страница с базовой периферией вроде клавиатур, мышек и просто кнопок, есть джойстики и геймпады (искренне рекомендую посмотреть какие именно! Там и для танков, и для космических кораблей, и для подводных лодок и для всего чего угодно), даже дисплеи есть. Правда, где искать софт, умеющий со всем этим работать, я без понятия.
Внутри каждой страницы выбирается конкретное устройство. Например, для мышки это указатель и кнопки, а для планшета — стилус или палец юзера (что?!). Ими же обозначаются составные части устройства. Так, частью указателя являются его координаты по X и Y. Некоторые характеристики можно сгруппировать в «коллекцию», но для чего это делается я толком не понял. В документации к полям иногда ставится пометка из пары букв о назначении поля и способе работы с ним:
CA | Collection(application) | Служебная информация, никакой переменной не соответствующая |
CL | Collection(logical) | -/- |
CP | Collection(phisical) | -/- |
DV | Dynamic Value | входное или выходное значение (переменная) |
MC | Momentary Control | флаг состояния (1-флаг взведен, 0-сброшен) |
OSC | One Shot Control | однократное событие. Обрабатывается только переход 0->1 |
Есть, разумеется, и другие, но в моем примере они не используются. Если, например, поле X помечено как DV, то оно считается переменной ненулевой длины и будет включено в структуру репорта. Поля MC или OSC также включаются в репорт, но имеют размер 1 бит.
Один репорт (пакет данных, посылаемый или принимаемый устройством) содержит значения всех описанных в нем переменных. Описание кнопки говорит о всего одном занимаемом бите, но для относительных координат (насколько передвинулась мышка, например) требуется как минимум байт, а для абсолютных (как для тачскрина) уже нужно минимум 2 байта. Плюс к этому, многие элементы управления имеют еще свои физические ограничения. Например, АЦП того же тачскрина может иметь разрешение всего 10 бит, то есть выдавать значения от 0 до 1023, которое хосту придется масштабировать к полному разрешению экрана. Поэтому в дескрипторе помимо предназначения каждого поля задается еще диапазон его допустимых значений (LOGICAL_MINMAX), плюс иногда диапазон физических значений (в миллиматрах там, или в градусах) и обязательно представление в репорте. Представление задается двумя числами: размер одной переменной (а битах) и их количество. Например, координаты касания тачскрина в создаваемом нами устройстве задаются так:
Здесь видно, что объявлены две переменные, изменяющиеся в диапазоне от 0 до 10000 и занимающие в репорте два участка по 16 бит.
Последнее поле говорит, что вышеописанные переменные будут хостом читаться (IN) и поясняется как именно. Описывать его флаги подробно я не буду, остановлюсь только на нескольких. Флаг HID_ABS показывает, что значение абсолютное, то есть никакая предыстория на него не влияет. Альтернативное ему значение HID_REL показывает что значение является смещением относительно предыдущего. Флаг HID_VAR говорит, что каждое поле отвечает за свою переменную. Альтернативное значение HID_ARR говорит, что передаваться будут не состояния всех кнопок из списка, а только номера активных. Этот флаг применим только к однобитным полям. Вместо того, чтобы передавать 101/102 состояния всех кнопок клавиатуры можно ограничиться несколькими байтами со списком нажатых клавиш. Тогда первый параметр REPORT_FMT будет отвечать за размер номера, а второй — за количество.
Поскольку размер всех переменных задается в битах, логично спросить: а что же с кнопками, ведь их количество может быть не кратно 8, а это приведет к трудностям выравнивания при чтении и записи. Можно было бы выделить каждой кнопке по байту, но тогда бы сильно вырос объем репорта, что для скоростных передач вроде interrupt, неприятно. Вместо этого кнопки стараются расположить поближе друг к другу, а оставшееся место заполняют битами с флагом HID_CONST.
Теперь мы можем если не написать дескриптор с нуля, то хотя бы попытаться его читать, то есть определить, каким битам соответствует то или иное поле. Достаточно посчитать INPUT_HID’ы и соответствующие им REPORT_FMT’ы. Только учтите, что именно такие макросы придумал я, больше их никто не использует. В чужих дескрипторах придется искать input, report_size, report_count, а то и вовсе числовые константы.
Вот теперь можно привести дескриптор целиком:
Помимо рассмотренных ранее полей тут есть и такое интересное поле, как REPORT_ID. Поскольку, как понятно из комментариев, устройство у нас составное, хосту надо как-то определить, чьи данные он принимает. Для этого данное поле и нужно.
И еще одно поле, на которое хотелось бы обратить внимание — OUTPUT_HID. Как видно из названия, оно отвечает не за прием репорта (IN), а за передачу (OUT). Расположено оно в разделе клавиатуры и описывает индикаторы CapsLock, NumLock, ScrollLock а также два экзотических — Compose (флаг ввода некоторых символов, для которых нет собственных кнопок вроде á, µ или ) и Kana (ввод иероглифов). Собственно, ради этого поля мы и заводили OUT точку. В ее обработчике будем проверять не надо ли зажечь индикаторы CapsLock и NumLock: на плате как раз два диодика и разведено.
Существует и третье поле, связанное с обменом данными — FEATURE_HID, мы его использовали в первом примере. Если INPUT и OUTPUT предназначены для передачи событий, то FEATURE — состояния, которое можно как читать, так и писать. Правда, делается это не через выделенные endpoint’ы, а через обычную ep0 путем соответствующих запросов.
Если внимательно рассмотреть дескриптор, можно восстановить структуру репорта. Точнее, двух репортов:
Отправлять их будем по нажатию кнопок на плате, причем. поскольку пишем мы всего лишь пример реализации, а не законченное устройство, делать это будем по-варварски — посылая два репорта, в первом из которых «нажимая» клавиши, а во втором — «отпуская». Причем с огромной «тупой» задержкой между посылками. Если не посылать репорт с «отпущенными» клавишами, система посчитает что клавиша осталась нажатой и будет ее повторять. Естественно, ни о какой эффективности тут не идет и речи, о безопасности тоже, но для теста сойдет. Ах да, куда ж без очередных граблей! Размер структуры должен совпадать с тем, что описано в дескрипторе, иначе винда сделает вид, что не понимает чего от нее хотят. Как обычно, линукс подобные ошибки игнорирует и работает как ни в чем не бывало.
В процессе тестирования наткнулся на забавный побочный эффект: в Windows7 при нажатии на «тачскрин» вылезает окошко рукописного ввода. Я об этой фиче не знал.
Если к вам попало готовое устройство
… и хочется посмотреть на него изнутри. Первым делом, естественно, смотрим, можно даже от обычного пользователя, ConfigurationDescriptor:
Для HID-дескриптора же я не нашел (да и не искал) способа лучше, чем от рута:
Для полноты картины сюда стоило бы добавить как смотреть подобные вещи в других ОС. Но у меня соответствующих знаний нет, может в комментариях подскажут. Желательно, конечно, без установки стороннего софта.
Заключение
Вот, собственно, и все, что я нарыл по HID. План-минимум — научиться читать готовые дескрипторы, эмулировать несколько устройств одновременно и реализовать планшетный ввод — выполнен. Ну и философию interrupt точек рассмотрели заодно.
Как и в плошлый раз, немножко документации оставил в репозитории на случай если дизайнеры USB-IF снова решат испортить сайт.