Почему правило udev работает только один раз для случайного узла серийного USB-устройства из серии?

Вопрос или проблема

У меня есть многопортовое устройство USB-to-UART на основе чипа CH348, работающего на драйвере вне ядра, взятом с https://github.com/WCHSoftGroup/ch9344ser_linux

Драйвер создает 8 узлов символьных устройств (/dev/ttyCH9344USB0 .. /dev/ttyCH9344USB7).
Устройство не предоставляет серийный номер в дескрипторе USB устройства, но есть EEPROM, которую я хочу прочитать с устройства, извлечь серийный номер оттуда и использовать его для создания симлинка, например /dev/ttyUSB.CH348.<serial_number>.<instance>.

Я создал простое правило udev и поместил его в /etc/udev/rules.d/99-usb-serial.rules:

ACTION=="add", KERNEL=="*ttyCH9344USB*", OPTIONS="log_level=debug", PROGRAM="/usr/local/bin/ch34x_serial %E{DEVNAME}", SYMLINK+="ttyUSB.CH348.$result"

Правило работает, как ожидается, но только для ОДНОГО единственного СЛУЧАЙНОГО узла из 8.
На самом деле я пробовал множество различных правил совпадения, и независимо от того, какой метод я использую (имя ядра, usb-атрибуты и т. д.), если он совпадает, то только для ОДНОГО единственного СЛУЧАЙНОГО экземпляра серии. Он может создать мне симлинк для экземпляра 3, 6, 7 или любого другого, но только для одного.

Я проверил journalctl и udevadm monitor -p и выяснил, что есть ровно 8 различных событий add, приходящих в udev, когда я загружаю модуль драйвера. Все события идентичны, за исключением свойств KERNEL, DEVPATH, SEQNUM и MINOR, и выглядят следующим образом:

KERNEL[706136.962119] add      /devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.1/1-1.1.3/1-1.1.3.2/1-1.1.3.2.1/1-1.1.3.2.1:1.0/tty/ttyCH9344USB0 (tty)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1.1/1-1.1.3/1-1.1.3.2/1-1.1.3.2.1/1-1.1.3.2.1:1.0/tty/ttyCH9344USB0
SUBSYSTEM=tty
DEVNAME=/dev/ttyCH9344USB0
SEQNUM=26571
MAJOR=168
MINOR=0

Я не понимаю, почему только одно из этих событий фактически запускает правило, тогда как если я запускаю udevadm test для любого из 8 узлов устройств, правило работает нормально для любого из них.

Похоже, что udev как-то кэширует действие и отбрасывает “дубликаты”, хотя я не понимаю, как он приходит к такому выводу.

Я использую Ubuntu 24.04 Server с версией udev 255.4-1ubuntu8.4.

Буду признателен за любую помощь. Спасибо.

Ответ или решение

Проблема, с которой вы столкнулись, заключается в работе правил udev с несколькими последовательными устройствами, не имеющими уникальных идентификаторов, таких как серийные номера. Давайте рассмотрим возможные причины, почему ваше правило sudev срабатывает только для одного из восьми созданных устройств на базе чипа CH348, а также предложим решения.

Анализ проблемы

  1. Отсутствие уникальности в устройствах:
    Поскольку все восемь USB-UART устройств не имеют серийного номера в дескрипторе USB, каждый из них воспринимается системой как идентичные. Это приводит к ситуации, в которой одно и то же правило udev может неправильно применяться к нескольким устройствам, и, как следствие, ведет к тому, что только одно из них триггерит правило.

  2. Кэширование udev:
    udev имеет встроенные механизмы кэширования, которые могут ухудшать ситуацию при обработке массовых событий. Когда несколько устройств добавляются одновременно, система может проигнорировать дубликаты, думая, что они только одно устройство. Это объясняет, почему udev срабатывает только для случайного экземпляра.

  3. Правила выполнения:
    Указание, что правило udev срабатывает, лишь одним из событий (ACTION=="add"), также играет определенную роль. Если одно из устройств обрабатывается раньше других, последующие могут быть отброшены, если система увидит, что правила уже были применены.

Решения

Изменение правил udev

Для устранения данной проблемы стоит добавить в ваше правило дополнительный фильтр, чтобы дать понять udev, что каждое устройство является уникальным, даже если у них нет уникальных серийных номеров. Например, вы можете воспользоваться свойствами, присущими каждому экземпляру, такими как MINOR или DEVPATH.

Попробуйте изменить ваше правило следующим образом:

ACTION=="add", KERNEL=="*ttyCH9344USB*", ENV{ID_SERIAL}="%E{DEVNAME}", PROGRAM="/usr/local/bin/ch34x_serial %E{DEVNAME}", SYMLINK+="ttyUSB.CH348.$result"

Модификация скрипта

Также убедитесь, что ваш скрипт ch34x_serial корректно извлекает серийный номер и, возможно, добавляет уникальные обозначения на основе номера устройства или других уникальных идентификаторов (например, по порядку подключения).

Использование дополнительных атрибутов

Если это возможно, вы можете добавить дополнительные атрибуты в ваши правила, основываясь на других метаданных, которые передаются через udev, например, на базе DEVLINK или определенных характеристик устройства.

Заключение

Проблема с тем, что ваше правило sudev срабатывает только для одного из восьми устройств, в первую очередь связана с отсутствием уникальных идентификаторов у различных USB-UART устройств. Рассмотренные решения, включая модификацию правил udev и скрипта, а также использование дополнительных атрибутов, могут помочь исправить эту проблему. Помните, что программирование и работа с устройствами требуют внимательного анализа и порой нестандартного подхода.

Если у вас возникнут дополнительные вопросы или необходимость в более глубоком анализе, не стесняйтесь обращаться за поддержкой.

Оцените материал
Добавить комментарий

Капча загружается...