Я разрабатываю пользовательский HID-совместимый ИБП на базе Arduino Micro. Когда я подключаю его к Apple OSX (я использую Macbook в качестве хост-машины) или Windows 10 VM machine, мой "UPS" правильно определяется операционной системой, и я также могу сообщать об оставшейся емкости батареи и других параметрах обратно на хост.
Однако, когда я подключаю его к Ubuntu 18.04 LTS, он не работает (не отображается в настройках питания). В то же время коммерческий ИБП APC прекрасно работает под Ubuntu. Ниже приведена распечатка lsusb:
abratchik@ubuntu-parallels-vm:~$ lsusb
Bus 001 Device 003: ID 203a:fffa
Bus 001 Device 002: ID 203a:fffa
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 002: ID 203a:fff9
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 004: ID 2341:8036 Arduino SA Leonardo (CDC ACM, HID)
Bus 002 Device 006: ID 051d:0003 American Power Conversion UPS
Bus 002 Device 003: ID 203a:fffe
Bus 002 Device 002: ID 203a:fffc
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
abratchik@ubuntu-parallels-vm:~$ lsusb -t
/: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/12p, 5000M
|__ Port 1: Dev 2, If 0, Class=Video, Driver=uvcvideo, 5000M
|__ Port 1: Dev 2, If 1, Class=Video, Driver=uvcvideo, 5000M
/: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/2p, 480M
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=uhci_hcd/2p, 12M
|__ Port 1: Dev 2, If 0, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 1: Dev 2, If 1, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 2: Dev 3, If 0, Class=Hub, Driver=hub/15p, 12M
|__ Port 5: Dev 4, If 2, Class=Human Interface Device, Driver=usbhid, 12M
|__ Port 5: Dev 4, If 0, Class=Communications, Driver=cdc_acm, 12M
|__ Port 5: Dev 4, If 1, Class=CDC Data, Driver=cdc_acm, 12M
|__ Port 4: Dev 6, If 0, Class=Human Interface Device, Driver=usbhid, 12M
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/15p, 480M
|__ Port 1: Dev 2, If 0, Class=Printer, Driver=usblp, 480M
|__ Port 2: Dev 3, If 0, Class=Printer, Driver=usblp, 480M
В первой распечатке мой пользовательский ИБП идет с ID 2341:8036, а ИБП APC - 051d:0003. Вторая распечатка также показывает, что оба они правильно идентифицированы как HID-устройства (Bus 02 порт 5 интерфейс 2 для моего ИБП и порт 4 интерфейс 0 для APC) и оба используют usbhid драйвер, что также правильно и как ожидалось.
Однако APC правильно определяется Ubuntu как ИБП, в то время как мой ИБП вообще не отображается:
abratchik@ubuntu-parallels-vm:~$ upower -e
/org/freedesktop/UPower/devices/line_power_ADP0
/org/freedesktop/UPower/devices/battery_BAT0
/org/freedesktop/UPower/devices/ups_hiddev3
/org/freedesktop/UPower/devices/DisplayDevice
abratchik@ubuntu-parallels-vm:~$ upower -i /org/freedesktop/UPower/devices/ups_hiddev3
native-path: /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2.4/2-2.4:1.0/usbmisc/hiddev3
vendor: American Power Conversion
model: Smart-UPS C 1500 FW:UPS 10.0 / ID=1005
serial: 3S1838X02676
power supply: yes
updated: Thu 03 Dec 2020 10:00:04 AM +04 (-11 seconds ago)
has history: yes
has statistics: yes
ups
present: yes
state: fully-charged
warning-level: none
time to empty: 2.0 hours
percentage: 100%
icon-name: 'battery-full-charged-symbolic'
Также светодиоды RX/TX не мигают на плате Arduino, так что похоже, что нет обмена между платой и виртуальной машиной. Эта же плата прекрасно работает под OSX и Windows 10, как я уже говорил выше.
Я немного погуглил и обнаружил, что многие статьи на эту тему ссылаются на драйвер usbhid-ups, который не установлен по умолчанию и требует некоторой настройки, как я понял. Я бы очень хотел избежать этого и сделать свой ИБП полностью "plug-and-play", подобно ИБП APC. Уже потерял идеи, что может быть другим для моего ИБП, кроме, может быть, ID поставщика/ID продукта, но это был бы мой последний вариант, чтобы попытаться изменить их. Любая подсказка, что я упускаю, будет очень признательна.
Наконец-то я понял, как это работает. Драйвер usbhid в Linux не виноват, это просто низкоуровневый синтаксический анализатор протокола HID, который на самом деле не выполняет никакой интеллектуальной работы, кроме расшифровки ответов устройства и передачи их на уровень управления, который udev (диспетчер устройств ядра Linux) и UPower manager, который находится поверх udev.
UPower фактически определяет список всех поддерживаемых Vendor ID/Product ID и передает его udev в виде правил udev. Так что я был прав - в этом случае идентификатор поставщика / идентификатор продукта имеет значение - если вы являетесь APC, ваш ИБП будет обнаружен автоматически, в противном случае устройство просто игнорируется UPower, даже если оно совместимо с HID.
К счастью, есть обходной путь. Правила udev хранятся в папке /etc/udev/rules.d/ в текстовом формате, поэтому можно легко определить дополнительные правила. Нужно создать файл 98-upower-hid.rules (думаю, точное имя файла не так важно) в этой папке и добавить следующие строки:
ATTRS{idVendor}=="2341", ENV{UPOWER_VENDOR}="Arduino"
ATTRS{idVendor}=="2341", ATTRS{idProduct}=="8036", ENV{UPOWER_BATTERY_TYPE}="ups"
Reboot. После этого плата Arduino со скетчем ИБП прекрасно распознается Ubuntu.