Jump to content

    

Linux: работа с USB HID устройством - чтение Input Report (Interrupr In EP).

Это оттуда:

    MaxPower              100mA; Рекомендую ставить 98mA.

Мммм...эээ... А в чем глубокий смысл?

У вас описаны Input и Output репорты. Для Input репорта имеется Interrupt In EP, а для Output репорта нет Interrupt Out EP. Т.е. Output будет передаваться через контрольный канал (EP N0). В таком случае я не вижу никаких преимуществ перед Feature репортом. Хотя с Output репортами не работал (именно из-за того, что преимуществ не нашёл). Единственное отличие - вместо WriteFile у Output, у Feature работа через API.

Ну я же говорю, у меня проще. На самом деле это BootLoader и сделан так чтоб поменьше кода было.

Спасибо за разъяснения. Вы это узнали копаясь в исходниках, или документация имеется? Мне только догадываться приходилось.

/usr/src/linux/Documentation/usb/usbmon.txt

http://www.linux-usb.org/USBMon/

http://people.redhat.com/zaitcev/linux/OLS05_zaitcev.pdf

http://www.linux-usb.org/

Помню долго искал программу - см. вложение.

Кстати насчёт размера буфера - это я правильно догадался? Если правильно - надо будет сообщение в Linux послать. Пусть ошибку у себя исправят.

Посмотрите списки рассылки и спросите туда.

http://www.linux-usb.org/

Сейчас пытаюсь опрос Interrupt In EP по таймеру сделать. Что-то в этом случае ReadFile очень долго выполняется - чуть-ли не 5 милисекунд. Видимо планировщику кадров USB задание даётся, а он только в следующий кадр USB опрос Interrupt In EP вставляет. А всё это время весь поток висит. Хотя это только 2 милисекунды д.б. максимум.

Сейчас разбираюсь нет-ли какого способа по прерыванию от USB всё это сделать. Или это только драйвер так работать может?

Или по другому: сначала опрос инициировать, а потом через 2 милисекунды результаты прочесть.

Ну на сколько, я знаю прерывания это только в ядре - т.е. драйвер.

А очередь надо делать.

usbmon.5.tar.gz

Share this post


Link to post
Share on other sites
Мммм...эээ... А в чем глубокий смысл?

Может не подключаться к 100 мА хосту (некоторые ноутбуки и все хабы без питания). Однажды такое наблюдал. Хотя м.б. это какой-то другой глюк так себя проявил.

Ну я же говорю, у меня проще. На самом деле это BootLoader и сделан так чтоб поменьше кода было.

Обработка SetFeature репортов и Output через контрольный канал (как у вас) ничем не отличается. Только у Feature 3 в старшем байте wValue (4й байт в пакете SETUP), а у Output там 2. Чтоб поменьше кода было - лучше без Input обойтись. Feature в обе стороны передаёт (GetFeatur и SetFeature). И ещё Interrupt In EP не нужна будет, со всеми её обработчиками. А все процедуры приёма и передачи через контрольный канал у вас уже есть. Их всё равно приходится делать для подключения к USB. И под Linux никаких проблем. У меня в устройстве (о котором эта тема) BootLoader именно так и сделан. И под Win и под Linux работает. А Interrupt In нужен только если по инициативе устройства надо данные в компьютер передавать.

Или м.б. я не понял? М.б. вы хотели чтоб поменьше кода в компьютере было?

А очередь надо делать.

Не понял какую очередь?

 

А за информацию большое спасибо!

Share this post


Link to post
Share on other sites
Может не подключаться к 100 мА хосту (некоторые ноутбуки и все хабы без питания). Однажды такое наблюдал. Хотя м.б. это какой-то другой глюк так себя проявил.

Понял, спасибо. Действительно не подумал об этом. У меня лаптоп питает от USB HDD там 500мА и никаких проблем. Не подумал, что есть и более другие :)

Обработка SetFeature репортов и Output через контрольный канал (как у вас) ничем не отличается. Только у Feature 3 в старшем байте wValue (4й байт в пакете SETUP), а у Output там 2. Чтоб поменьше кода было - лучше без Input обойтись. Feature в обе стороны передаёт (GetFeatur и SetFeature). И ещё Interrupt In EP не нужна будет, со всеми её обработчиками. А все процедуры приёма и передачи через контрольный канал у вас уже есть. Их всё равно приходится делать для подключения к USB. И под Linux никаких проблем. У меня в устройстве (о котором эта тема) BootLoader именно так и сделан. И под Win и под Linux работает. А Interrupt In нужен только если по инициативе устройства надо данные в компьютер передавать.

Или м.б. я не понял? М.б. вы хотели чтоб поменьше кода в компьютере было?

Все зависит от того, как устроен USB контроллер в MCU. В моем случае прием через EP0 и передача через Int IN EP экономит мне флеш в MCU.

Не понял какую очередь?

После некорого экспериментирования я пришел к выводу что для исключения затыков при приеме/передаче нужно делать в программе на PC очереди на прием и передачу.

Правда с HID я такого не делал, но с другими делаю так.

Отдельный поток на передачу пакетов во все OUT EP (иногда для каждой EP свой поток). Этот поток выбирает данные из очереди передачи и занимается сугубо передачей через USB.

Отдельный поток на прием пакетов по IN EP. Этот поток занимается только приемом пакетов из USB и постановкой их в очередь приема.

Отдельный поток (чаще всего основной поток программы) выполняющий формирование (на передачу) и анализ (на приеме) пакетов в обеих очередях. Здесь идет полезная работа с данными.

 

Без очереди (очередей) получается как у Вас, пока пакет поставится на передачу в ядре, пока отправиться, пока примутся данные, пока дойдут обратно до приложения - все времянки летят.

Share this post


Link to post
Share on other sites

Разработчики модуля USB для Linux прислали ответ. Действительно у них глюк с определением максимального размера буфера для HID устройства. Предлагают, как я им и написал, заменить несколько строчек, перетранслировать и проверить.

А как перетранслировать? Кто-нибудь пробовал? Как это сделать проще? Можно-ли откомпилить и заменить ТОЛЬКО модуль USB и как это сделать? Там СТОЛЬКО настроек! А я ещё и в английском-то не очень.

Если разберусь, думаю можно будет вообще HID в Linux переделать. Как я понял, они предложили этим занятся. Думаю о том, чтобы поддержку vendor defined page (0xFF00..0xFFFF) сделать. Тогда Linux все самодельные устройства без драйверов поддерживать будет. По исходникам полазил - вроде не особо сложным это дело показалось.

Share this post


Link to post
Share on other sites
Разработчики модуля USB для Linux прислали ответ. Действительно у них глюк с определением максимального размера буфера для HID устройства. Предлагают, как я им и написал, заменить несколько строчек, перетранслировать и проверить.

А как перетранслировать? Кто-нибудь пробовал? Как это сделать проще? Можно-ли откомпилить и заменить ТОЛЬКО модуль USB и как это сделать? Там СТОЛЬКО настроек! А я ещё и в английском-то не очень.

Если разберусь, думаю можно будет вообще HID в Linux переделать. Как я понял, они предложили этим занятся. Думаю о том, чтобы поддержку vendor defined page (0xFF00..0xFFFF) сделать. Тогда Linux все самодельные устройства без драйверов поддерживать будет. По исходникам полазил - вроде не особо сложным это дело показалось.

Ну перекомпилировать - это не так уж сложно.

Во первых - какой дистрибутив? Надо установить пакет с исходниками ядра.

Можно просто взять с kernel.org но тогда могут возникнуть ньюансы.

Лучше всего взять все-же из дистрибутива.

Обычно исходник лежит в /usr/src/linux. Тогда делаем так.

cd /usr/src/linux
zcat /proc/config.gz .config
make oldconfig
make
make modules_install

НЕ ПРОПУСТИТЕ ТОЧКУ в имени файла .config.

Предпоследняя команда будет выполняться долго (может час, может больше). Это потому, что в конфиге выбрано почти все.

Теперь Вы имеете только что скомпиленные ядро и модули. Модули уже установлены, ядро старое. Само собой, речь идет о ТОЙ ЖЕ ВЕРСИИ ядра, что и запущенная при загрузке.

Можно править нужные Вам и потом

make
make modules_install

Ну и перезагружаете правленный Вами модуль используя

modprobe -r <module_name>
modprobe <module_name>

Share this post


Link to post
Share on other sites
Теперь Вы имеете только что скомпиленные ядро и модули.

Да компилировать научился. Спасибо. Ошибку, связанную с неправильным определением максимального размера буфера, в Linux-е исправил.

Выяснил, что начиная с версии ядра 2.6.24 к устройству стал цеплятся драйвер usbhid, но опрос HID-овской Interrupt In EP всё равно не идёт. При наличии этого драйвера usb_claim_interface возвращает, что устройство занято. Можно отключить драйвер командой usb_detach_kernel_driver_np, и пользоваться устройством как раньше.

А как пользоваться устройством через драйвер???

Share this post


Link to post
Share on other sites
Да компилировать научился. Спасибо. Ошибку, связанную с неправильным определением максимального размера буфера, в Linux-е исправил.

:)

Выяснил, что начиная с версии ядра 2.6.24 к устройству стал цеплятся драйвер usbhid, но опрос HID-овской Interrupt In EP всё равно не идёт. При наличии этого драйвера usb_claim_interface возвращает, что устройство занято. Можно отключить драйвер командой usb_detach_kernel_driver_np, и пользоваться устройством как раньше.

Все правильно. И по моему usb_detach_kernel_driver_np требует права root. Не помню точно.

А как пользоваться устройством через драйвер???

По идее, если драйвер распознал что-нибудь, и это что-то он поддерживает, то появится /dev/input/event или что-то еще, типа /dev/input/mice (USB мышь).

Как это устройство использовать не скажу - не пробовал, но в ядре можно посмотреть функции read/write, типы данных, IOCTL и пр. Ну и linux/Documentation/input конечно-же.

Думаю, для начала попробуйте опять же открыть устройство, ипосмотреть, идет ли опрос.

Share this post


Link to post
Share on other sites
Ну и linux/Documentation/input конечно-же.

Спасибо. Это был самый ценный совет :) . Действительно! Этого я не знал!

 

При втыкании устройства в каталоге /dev появляется файл (устройство) вида hidraw1. При втыкании 2го устройства hidraw2 и т.д. Опрос Interrupt In при этом не идёт (как вы и писали). Опрос начинается только если попытаться открыть этот файл. Данные Interrupt In EP идут в него, причём ReportId (0й байт этого репорта) отбрасывается. Т.е. можно работать с устройством :) .

 

Теперь собственно сам вопрос. Как узнать какому из устройств принадлежит каждый из этих файлов (hidraw)? Как найти соответствие между файлом и устройством? Имеется-ли какая-то определённая процедура открытия данного файла?

Share this post


Link to post
Share on other sites
Спасибо. Это был самый ценный совет :) . Действительно! Этого я не знал!

Как правило, документацию никто не читает. И зачем ее пишут? :)

При втыкании устройства в каталоге /dev появляется файл (устройство) вида hidraw1. При втыкании 2го устройства hidraw2 и т.д. Опрос Interrupt In при этом не идёт (как вы и писали). Опрос начинается только если попытаться открыть этот файл. Данные Interrupt In EP идут в него, причём ReportId (0й байт этого репорта) отбрасывается. Т.е. можно работать с устройством :) .

hidraw, судя по названию, не какое-то конкретное устройство, а просто как "точка входа" с неизвестными функциями.

Теперь собственно сам вопрос. Как узнать какому из устройств принадлежит каждый из этих файлов (hidraw)? Как найти соответствие между файлом и устройством? Имеется-ли какая-то определённая процедура открытия данного файла?

А никак. Зависит от порядка опроса драйвером usb_core шин. Порядок опроса может поменятся.

 

Гляньте еще в /sys. Там для каждого устройства есть файл dev, содержащий major:minor номера и файл name, сщдержащий имя устройства (типа hidraw2). Если есть какие либо опознавательные знаки, например SERIAL_DESCRIPTOR то в том же /sys/bus/usb/devices/номер-утройства/serial его можно прочитать и поставить в соответствие с dev, name и /dev/input/hidraw2.

Есть еще /proc/bus/usb/. Но с ним не работал. И возможно /dev/usbdev* может как-то помочь.

 

По поводу открытия. Ну не знаю, так далеко не копал. Но видимо по аналогии с libusb.

Может доках есть, а может придется поизучатьlinux/drivers/hid/hidraw.c

Edited by amw

Share this post


Link to post
Share on other sites
Гляньте еще в /sys. Там для каждого устройства есть файл dev, содержащий major:minor номера и файл name, сщдержащий имя устройства (типа hidraw2). Если есть какие либо опознавательные знаки, например SERIAL_DESCRIPTOR то в том же /sys/bus/usb/devices/номер-утройства/serial его можно прочитать и поставить в соответствие с dev, name и /dev/input/hidraw2.

Есть еще /proc/bus/usb/. Но с ним не работал. И возможно /dev/usbdev* может как-то помочь.

Проверил все варианты. Не нашёл никаких концов. Как сопоставить hidraw конкретному устройству непонятно.

Есть конечно способ с использованием dmesg. Там в логе есть строчка в которой можно посмотреть какой hidraw создаётся при подключении нашего устройства. Но неужели это единственный способ?

 

Если найти соответствующий hidraw, то с Input репортами (Interrupt In EP) всё в порядке - прочитать можно и данные не теряются. Но теперь другая проблемма - с Set(Get)Feature. Непонятно как ими пользоваться без libusb (ядро 2.6.24), через IOCTL что-ли?

 

Вобщем продолжаю копать...

Или м.б. выхода нового ядра стоит дождаться? М.б. в нём эти проблеммы будут решены?

Share this post


Link to post
Share on other sites
Проверил все варианты. Не нашёл никаких концов. Как сопоставить hidraw конкретному устройству непонятно.

Есть конечно способ с использованием dmesg. Там в логе есть строчка в которой можно посмотреть какой hidraw создаётся при подключении нашего устройства. Но неужели это единственный способ?

А как Вы их различать собираетесь? По какому критерию? Что первое воткнули в порт USB то и будет с номером 1. Следующий с номером 2. И т.д. А потом выткнув 1, 3, 5 и воткнув один из них снова появится 1 (хотя может и 6 - не копал, но по аналогии с usbserial и /dev/ttyUSB*).

Нужен признак в самом устройстве. Типа дескриптор SERIAL или еще что-то.

Если найти соответствующий hidraw, то с Input репортами (Interrupt In EP) всё в порядке - прочитать можно и данные не теряются. Но теперь другая проблемма - с Set(Get)Feature. Непонятно как ими пользоваться без libusb (ядро 2.6.24), через IOCTL что-ли?

Вероятно. Смотреть по коду hidraw.c.

Вобщем продолжаю копать...

Или м.б. выхода нового ядра стоит дождаться? М.б. в нём эти проблеммы будут решены?

Это вряд-ли.

Share this post


Link to post
Share on other sites

После годового перерыва вернулся к этой теме. Надеялся на новые версии linux. Кое что действительно подправили в т.ч. ту ошибку с размером буфера. Но так и не удалось получить/передать Get(Set)Feature репорты с помощью IOCTL через hidraw. В hidraw нет IOCTL работающих с HID-ом, а HID-овские IOCTL он не воспринимает (ядро 2.6.24 и выше).

В итоге вышел из положения следующим образом: устройство-то составное MassStorage+HID поэтому можно отключить драйвер от интерфейса MassStorage и посылать любые Setup-ные пакеты (Get(Set)Feature к HID-у в т.ч.) через libusb. Конечно при этом MassStorage не работает, но это и не обязательно. Т.е. InterruptIn читается через /dev/hidraw, а Get(Set)Feature через libusb к другому интерфейсу (MassStorage в этом случае). В принципе можно добавить ещё один интерфейс (ненужный) только для того, чтобы на него вешать libusb и работать с Get(Set)Feature репортами. Но этот способ какой-то "партизанский". Как правильно работать с HID-ом под Linux?

Share this post


Link to post
Share on other sites

linux-2.6.28.1/drivers/hid/Kconfig

Say Y here if you want to support HID devices (from the USB

specification standpoint) that aren't strictly user interface

devices, like monitor controls and Uninterruptable Power Supplies.

 

This module supports these devices separately using a separate

event interface on /dev/hidraw.

 

There is also a /dev/hiddev configuration option in the USB HID

configuration menu. In comparison to hiddev, this device does not process

the hid events at all (no parsing, no lookups). This lets applications

to work on raw hid events when they want to, and avoid using transport-specific

userspace libhid/libusb libraries.

http://libusb.wiki.sourceforge.net/

http://libhid.alioth.debian.org/

 

Как правильно работать с HID-ом под Linux?

Три варианта

1. Стандартное устройство - стандартный драйвер - стандартный интерфейс.

2. libusb

3. Свой драйвер.

Share this post


Link to post
Share on other sites
Три варианта

1. Стандартное устройство - стандартный драйвер - стандартный интерфейс.

2. libusb

3. Свой драйвер.

Почему вариантов всего 3? Теперь, после исправления ошибки в ядре, есть как минимум ещё один:

Нестандартное устройство (не клавиатура, мышь, джойстик). Для него Linux создаёт файл hidraw. Из это файла читаются HID репорты, посылаемые устройством через InterruptIn EP.

Найти своё устройство можно прочитав HID Usage (IOCTL к hidraw). Т.е. если у устройства все данные шлются ТОЛЬКО через InterruptIn (возможно InterruptOut - не проверял), то работать с данным НЕСТАНДАРТНЫМ устройством можно без libusb и без специального драйвера.

Другое дело, что почему-то нет возможности получать(передавать) Get(Set)Feature репорты ОДНОВРЕМЕННО с этим (без использования партизанских способов). Или м.б. такой способ есть, но я не знаю. Как появится время - ещё покопаю/отпишу.

Share this post


Link to post
Share on other sites

Вобщем-то под Linux мой HID работает на том-же уровне, что и под вин, но столкнулся с ещё одной проблеммой. Если к компу подключены 2 (или больше) моих девайса - не удаётся определить где чей hidraw. Почему-то сделали только чтение из hidraw VID и PID, а сериал нумбер не доступен. Можно конечно внести в HID Report Descriptor номер устройсва (в неявном виде, типа Physical Minimum/Maximum сделать номером), но это опять-таки партизанский способ. А м.б. в новой версии этих проблем уже не будет? Стоит просто подождать.

Попытаюсь разработчику написать, но мой английский таков, что скорее всего меня там не поймут.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this