Различаем USB-устройства с одинаковыми VID/PID
eddy_em — 10.04.2023 В возне с прототипом спектрографа ESPriF, наткнулся на то, что все мои три железяки (контроллер восьми шаговиков, контроллер объектива Canon и контроллер узла калибровки) абсолютно никак в системе не различаются: те же самые VID/PID/Manufacturer (собственно, эмулирую PL2303). Подсказали мне, что можно завести текстовое поле Interface, которое поможет в дальнейшей идентификации. И вот на "заполнялке азотом" я решил поиграться. Заодно лишний раз оптимизировал USB, выкинув ненужные флаги. Все индексы текстовых дескрипторов задаются в дескрипторе устройства и конфигурационном дескрипторе. Скажем: iManufacturer, iProduct, iSerialNumber и тот самый iInterface. Чтобы не запутаться, проще завести enum, его поля и использовать как индексы. Если мы не хотим отдавать дескрипторы, задаем вместо индекса нуль. Ну, а дальше компьютер запрашивает нужный индекс и получает текстовую строку, которую и можно использовать в правиле udev, чтобы вместо кучи /dev/ttyUSBx создать более понятные (например, /dev/nitrogen_flooding0 или /dev/canusb0).Вот с правилами UDEV пришлось повозиться подольше: благо, есть udevadm test, так что не пришлось постоянно шнурок туда-сюда втыкать/вытыкать. Сложность вызвало то, что поле Interface лежит в одном "устройстве", а поля VID/PID — в "родительских". Как обычно, SO помог в решении этой проблемы (что бы мы без Stack Overflow делали вообще? Я, например, по латеху там кучу проблем решил, ну и сам немного людям помог; да и по C, линуксу, башу…).
Одним словом, чтобы различить устройства с одинаковым VID/PID, нам нужно это правило:
ACTION=="add", DRIVERS=="usb", ENV{USB_IDS}="%s{idVendor}:%s{idProduct}" ACTION=="add", ENV{USB_IDS}=="067b:2303", ATTRS{interface}=="?*", SYMLINK+="$attr{interface}%n"
Т.е. когда udev будет пробегаться по всем "родительским устройствам", на стадии добавления в систему USB он заведет переменную USB_IDS, а когда пройдется по "дочернему" устройству, проверит, соответствует ли эта переменная нужному VID:PID. Если соответствует — проверит, есть ли поле iInterface (нам не нужно "настоящие" PL2303 там именовать, да и у них все равно нет этого поля), и если оно есть — создаст нужную ссылочку.
В простейшем же случае (в данном) наше устройство отличается от всех остальных полем "DRIVERS" (которое как раз является свойством "подустройства" с полем interface), поэтому можно упростить правило:
DRIVERS=="pl2303", ACTION=="add", ATTRS{interface}=="?*", SYMLINK+="$attr{interface}%n"
Все, как только добавили устройство с нужным полем DRIVERS и существующим атрибутом interface, создастся нужная символическая ссылка.
Теперь достаточно для каждого USB-устройства только лишь менять название этого поля. И в системе теперь не придется перебирать из кучи /dev/ttyUSBx, чтобы найти свое устройство — на него будет удобный симлинк. Да и все демоны будут элементарно стартовать (не нужно будет перебирать устройства и запрашивать "ТЫ ХТО, Э?").
|
</> |