Разбираемся со сканерами в Linux: Установка и конфигурирование устройства

в 16:27, , рубрики: astra, kernel, sane, udev, usb, сканеры

Перед вами продолжение первой части статьи Разбираемся со сканерами в Linux: получение информации об устройстве и поиск подходящего драйвера. Там же вы найдете список источников, на которые я периодически ссылаюсь по тексту.

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

udevadm (systemd)

Мощный инструмент для получения информации об устройстве из подсистемы udev, которая пришла на смену devfsudev представляет собой надстройку пространства пользователя над файловой системой /sys. Если в зону ответственности ядра входит:

  • слежение за изменениями в аппаратной конфигурации (например, подключение нового USB-устройства),

  • регистрация этих изменений и отражение их в директории /sys,

то udev отвечает за дальнейшую настройку устройства в системе для работы пользователей с ним.

Получить информацию об устройстве из подсистемы udev можно при помощи команды udevadm info <path>

udevadm info /dev/bus/usb/004/002

P: /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1
N: bus/usb/004/002
L: 0
E: DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1
E: DEVNAME=/dev/bus/usb/004/002
E: DEVTYPE=usb_device
E: DRIVER=usb
E: PRODUCT=232b/2732/100
E: TYPE=0/0/0
E: BUSNUM=004
E: DEVNUM=002
E: MAJOR=189
E: MINOR=385
E: SUBSYSTEM=usb
E: USEC_INITIALIZED=1063122535
E: ID_VENDOR=Pantum
E: ID_VENDOR_ENC=Pantum
E: ID_VENDOR_ID=232b
E: ID_MODEL=BM5100ADW_series
E: ID_MODEL_ENC=BM5100ADWx20series
E: ID_MODEL_ID=2732
E: ID_REVISION=0100
E: ID_SERIAL=Pantum_BM5100ADW_series_CK1A046238
E: ID_SERIAL_SHORT=CK1A046238
E: ID_BUS=usb
E: ID_USB_INTERFACES=:070102:070104:ffffff:ff0101:
E: SYSTEMD_WANTS=printer.target
E: TAGS=:systemd:

Сокращения [46], используемые в выводе:

  • P (path) — путь к устройству в sysfs

  • N (name) — имя, назначенное файлу в /dev

  • L (link) — приоритет ссылки (по умолчанию 0)

  • E (properties) — свойства устройства, которые можно использовать в правилах. Например, передать значение DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1 через переменную $env{DEVPATH}

Получить информацию о всех операциях udev, выполненных над устройством, можно командой udevadm monitor после подключения устройства.

udevadm monitor --environment --udev
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing

UDEV  [3293.766675] add      /class/usbmisc (class)
ACTION=add
DEVPATH=/class/usbmisc
SUBSYSTEM=class
SEQNUM=8140
USEC_INITIALIZED=3293766505

UDEV  [3293.905624] add      /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1 (usb)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1
SUBSYSTEM=usb
DEVNAME=/dev/bus/usb/004/005
DEVTYPE=usb_device
PRODUCT=232b/2732/100
TYPE=0/0/0
BUSNUM=004
DEVNUM=005
SEQNUM=8138
USEC_INITIALIZED=3293905345
ID_VENDOR=Pantum
ID_VENDOR_ENC=Pantum
ID_VENDOR_ID=232b
ID_MODEL=BM5100ADW_series
ID_MODEL_ENC=BM5100ADWx20series
ID_MODEL_ID=2732
ID_REVISION=0100
ID_SERIAL=Pantum_BM5100ADW_series_CK1A046238
ID_SERIAL_SHORT=CK1A046238
ID_BUS=usb
ID_USB_INTERFACES=:070102:070104:ffffff:ff0101:
DRIVER=usb
SYSTEMD_WANTS=printer.target
MAJOR=189
MINOR=388
TAGS=:systemd:

UDEV  [3293.913578] add      /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.1 (usb)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.1
SUBSYSTEM=usb
DEVTYPE=usb_interface
PRODUCT=232b/2732/100
TYPE=0/0/0
INTERFACE=255/255/255
MODALIAS=usb:v232Bp2732d0100dc00dsc00dp00icFFiscFFipFFin01
SEQNUM=8143
USEC_INITIALIZED=3293913413

UDEV  [3293.915419] add      /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.0 (usb)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.0
SUBSYSTEM=usb
DEVTYPE=usb_interface
PRODUCT=232b/2732/100
TYPE=0/0/0
INTERFACE=7/1/2
MODALIAS=usb:v232Bp2732d0100dc00dsc00dp00ic07isc01ip02in00
SEQNUM=8139
USEC_INITIALIZED=3293915248
DRIVER=usblp

UDEV  [3293.917365] add      /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.2 (usb)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.2
SUBSYSTEM=usb
DEVTYPE=usb_interface
PRODUCT=232b/2732/100
TYPE=0/0/0
INTERFACE=255/1/1
MODALIAS=usb:v232Bp2732d0100dc00dsc00dp00icFFisc01ip01in02
SEQNUM=8144
USEC_INITIALIZED=3293917202

UDEV  [3293.919158] add      /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.0/usbmisc/lp0 (usbmisc)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.0/usbmisc/lp0
SUBSYSTEM=usbmisc
DEVNAME=/dev/usb/lp0
SEQNUM=8141
USEC_INITIALIZED=3293919053
MAJOR=180
MINOR=0

UDEV  [3293.920383] bind     /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.0 (usb)
ACTION=bind
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1/4-1:1.0
SUBSYSTEM=usb
DEVTYPE=usb_interface
DRIVER=usblp
PRODUCT=232b/2732/100
TYPE=0/0/0
INTERFACE=7/1/2
MODALIAS=usb:v232Bp2732d0100dc00dsc00dp00ic07isc01ip02in00
SEQNUM=8142
USEC_INITIALIZED=3293920292

UDEV  [3294.007210] bind     /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1 (usb)
ACTION=bind
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1
SUBSYSTEM=usb
DEVNAME=/dev/bus/usb/004/005
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=232b/2732/100
TYPE=0/0/0
BUSNUM=004
DEVNUM=005
SEQNUM=8145
USEC_INITIALIZED=3293905345
ID_VENDOR=Pantum
ID_VENDOR_ENC=Pantum
ID_VENDOR_ID=232b
ID_MODEL=BM5100ADW_series
ID_MODEL_ENC=BM5100ADWx20series
ID_MODEL_ID=2732
ID_REVISION=0100
ID_SERIAL=Pantum_BM5100ADW_series_CK1A046238
ID_SERIAL_SHORT=CK1A046238
ID_BUS=usb
ID_USB_INTERFACES=:070102:070104:ffffff:ff0101:
SYSTEMD_WANTS=printer.target
MAJOR=189
MINOR=388
TAGS=:systemd:

Пару слов о MAJOR и MINORMAJOR — старший номер, определяющий класс устройства. MINOR — номер определенного экземпляра устройства в этом классе. По значениям старшего номера ядро идентифицирует тип устройства и загружает для него определенный модуль. MAJOR=189 соответствует usb_device.

cat /proc/devices | grep 189

189 usb_device

Если старший номер уникальный для каждого типа устройства, то младший определяется самим драйвером и в теории должен быть уникальным для каждого, чтобы драйвер смог корректно взаимодействовать именно с этим экземпляром. Драйвер libusb присвоил MINOR=388, который рассчитывается по формуле: (<номер_шины> - 1) * 128 + <номер_устройства> — 1.

Для удобства восприятия понятий старшего и младшего номеров представьте, что старший номер —это тип устройства, младший — класс устройства. Пространство старших номеров ограничено величиной 212 = 4096, младших 220 = 1047585 для каждого старшего номера.

Назначение major&minor номеров

Назначение major&minor номеров

Эти значения можно также получить, используя вывод ls -l для файла символьного устройства:

ls -l

ls -l /dev/usb/lp0
crw-rw---- 1 root lp 180, 0 мар 22 11:19 /dev/usb/lp0
ls -l /dev/bus/usb/004/005
crw-rw-r-- 1 root lp 189, 388 мар 22 11:19 /dev/bus/usb/004/005Файлы символьных устройств не имеют размера, так как они не предназначены для хранения данных. За создание файлов устройств (блочное, символьное) отвечает программа mknod.

Одной из главных задач udev является настройка устройства в соответствии с заданными udev-правилами. Файлы правил с расширением .rules расположены в /etc/udev/rules.d и /usr/lib/udev/rules.d. Файлы .rules обрабатываются в алфавитном порядке. Файл из директории /etc/udev/rules.d будет обработан в приоритетном порядке при наличии одноименного файла в /usr/lib/udev/rules.d. Посмотрим, какие правила и программы отработали для устройства /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1 при помощи udevadm test.

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

Одной из главных задач udev является настройка устройства в соответствии с заданными udev-правилами. Файлы правил с расширением .rules расположены в /etc/udev/rules.d и /usr/lib/udev/rules.d. Файлы .rules обрабатываются в алфавитном порядке. Файл из директории /etc/udev/rules.d будет обработан в приоритетном порядке при наличии одноименного файла в /usr/lib/udev/rules.d. Посмотрим, какие правила и программы отработали для устройства /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1 при помощи udevadm test.

Параметры выполнения udevadm test

Выполнение udevadm test с указанием пути до символьного файла устройства /dev/bus/usb/<bus>/<port> закончится ошибкой. udevadm test принимает только путь (devpath) из /sys. Например, /devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1 или /sys/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1. Объяснение довольно простое: символьное устройство может просто отсутствовать. Зная полный путь до символьного устройства, можно вызвать команду udevadm test нехитрой командой:

udevadm test $(udevadm info /dev/bus/usb/001/003 | grep DEVPATH | cut -d '=' -f2)

udevadm test
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.

Load module index
Network interface NamePolicy= disabled on kernel command line, ignoring.
Parsed configuration file /usr/lib/systemd/network/99-default.link
Created link configuration context.
Reading rules file: /usr/lib/udev/rules.d/50-firmware.rules
Reading rules file: /usr/lib/udev/rules.d/50-udev-default.rules
Reading rules file: /usr/lib/udev/rules.d/55-dm.rules
Reading rules file: /usr/lib/udev/rules.d/56-hpmud.rules
Reading rules file: /usr/lib/udev/rules.d/60-block.rules
Reading rules file: /usr/lib/udev/rules.d/60-cdrom_id.rules
Reading rules file: /usr/lib/udev/rules.d/60-drm.rules
Reading rules file: /usr/lib/udev/rules.d/60-evdev.rules
Reading rules file: /usr/lib/udev/rules.d/60-fly-brightness.rules
Reading rules file: /usr/lib/udev/rules.d/60-input-id.rules
Reading rules file: /usr/lib/udev/rules.d/60-libgphoto2-6.rules
Reading rules file: /usr/lib/udev/rules.d/60-libopenni2-0.rules
Reading rules file: /usr/lib/udev/rules.d/60-libsane1.rules
Reading rules file: /etc/udev/rules.d/60-pantum_mfp.rules
Reading rules file: /usr/lib/udev/rules.d/60-pcmcia.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-alsa.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-input.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage-dm.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage-tape.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-storage.rules
Reading rules file: /usr/lib/udev/rules.d/60-persistent-v4l.rules
Reading rules file: /usr/lib/udev/rules.d/60-sensor.rules
Reading rules file: /usr/lib/udev/rules.d/60-serial.rules
Reading rules file: /usr/lib/udev/rules.d/61-kde-bluetooth-rfkill.rules
Reading rules file: /usr/lib/udev/rules.d/64-btrfs.rules
Reading rules file: /usr/lib/udev/rules.d/64-xorg-xkb.rules
Reading rules file: /usr/lib/udev/rules.d/65-libwacom.rules
Reading rules file: /usr/lib/udev/rules.d/69-libmtp.rules
Reading rules file: /usr/lib/udev/rules.d/69-wacom.rules
Reading rules file: /usr/lib/udev/rules.d/70-joystick.rules
Reading rules file: /usr/lib/udev/rules.d/70-mouse.rules
Reading rules file: /usr/lib/udev/rules.d/70-power-switch.rules
Reading rules file: /usr/lib/udev/rules.d/70-touchpad.rules
Reading rules file: /usr/lib/udev/rules.d/70-uaccess.rules
Reading rules file: /usr/lib/udev/rules.d/71-seat.rules
Reading rules file: /usr/lib/udev/rules.d/73-seat-late.rules
Reading rules file: /usr/lib/udev/rules.d/73-special-net-names.rules
Reading rules file: /usr/lib/udev/rules.d/73-usb-net-by-mac.rules
Reading rules file: /usr/lib/udev/rules.d/75-net-description.rules
Reading rules file: /usr/lib/udev/rules.d/75-probe_mtd.rules
Reading rules file: /usr/lib/udev/rules.d/78-sound-card.rules
Reading rules file: /usr/lib/udev/rules.d/80-debian-compat.rules
Reading rules file: /usr/lib/udev/rules.d/80-drivers.rules
Reading rules file: /usr/lib/udev/rules.d/80-ifupdown.rules
Reading rules file: /usr/lib/udev/rules.d/80-iio-sensor-proxy.rules
Reading rules file: /usr/lib/udev/rules.d/80-libinput-device-groups.rules
Reading rules file: /usr/lib/udev/rules.d/80-net-setup-link.rules
Reading rules file: /usr/lib/udev/rules.d/80-udisks2.rules
Reading rules file: /usr/lib/udev/rules.d/84-nm-drivers.rules
Reading rules file: /usr/lib/udev/rules.d/85-hwclock.rules
Reading rules file: /usr/lib/udev/rules.d/85-nm-unmanaged.rules
Reading rules file: /usr/lib/udev/rules.d/89-alsa-ucm.rules
Reading rules file: /usr/lib/udev/rules.d/90-alsa-restore.rules
Reading rules file: /usr/lib/udev/rules.d/90-console-setup.rules
Reading rules file: /usr/lib/udev/rules.d/90-libinput-fuzz-override.rules
Reading rules file: /usr/lib/udev/rules.d/90-nm-thunderbolt.rules
Reading rules file: /usr/lib/udev/rules.d/90-pulseaudio.rules
Reading rules file: /usr/lib/udev/rules.d/91-group-floppy.rules
Reading rules file: /usr/lib/udev/rules.d/95-dm-notify.rules
Reading rules file: /usr/lib/udev/rules.d/95-upower-csr.rules
Reading rules file: /usr/lib/udev/rules.d/95-upower-hid.rules
Reading rules file: /usr/lib/udev/rules.d/95-upower-wup.rules
Reading rules file: /usr/lib/udev/rules.d/99-libsane1.rules
Reading rules file: /usr/lib/udev/rules.d/99-monitor-hotplug.rules
Reading rules file: /usr/lib/udev/rules.d/99-systemd.rules
Reading rules file: /etc/udev/rules.d/99-vmware-scsi-udev.rules
Rules contain 393216 bytes tokens (32768 * 12 bytes), 27847 bytes strings
20847 strings (164854 bytes), 18234 de-duplicated (139621 bytes), 2614 trie nodes used
Invalid inotify descriptor.
PDAC: PDPL is zero
PDAC: AUDIT is empty or invalid
DEVPATH=/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb4/4-1
DEVNAME=/dev/bus/usb/004/003
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=232b/2732/100
TYPE=0/0/0
BUSNUM=004
DEVNUM=003
MAJOR=189
MINOR=386
ACTION=add
SUBSYSTEM=usb
ID_VENDOR=Pantum
ID_VENDOR_ENC=Pantum
ID_VENDOR_ID=232b
ID_MODEL=BM5100ADW_series
ID_MODEL_ENC=BM5100ADWx20series
ID_MODEL_ID=2732
ID_REVISION=0100
ID_SERIAL=Pantum_BM5100ADW_series_CK1A046238
ID_SERIAL_SHORT=CK1A046238
ID_BUS=usb
ID_USB_INTERFACES=:070102:070104:ffffff:ff0101:
libsane_matched=yes
TAGS=:systemd:uaccess:seat:
ID_PATH=pci-0000:02:02.0-usb-0:1
ID_PATH_TAG=pci-0000_02_02_0-usb-0_1
ID_FOR_SEAT=usb-pci-0000_02_02_0-usb-0_1
SYSTEMD_WANTS=printer.target
USEC_INITIALIZED=1339862414
run: 'uaccess'
run: '/bin/setfacl -m g:scanner:rw /dev/bus/usb/004/003'
Unload module index
Unloaded link configuration context.

Вывод довольно большой. Информация об устройстве udevadm info дополнена сведениями о всех .rules правилах, присутствующих в ОС и представленных в порядке их считывания. Но из вывода неясно, какие действительно правила отработали для этого устройства. В конце листинга можно лишь увидеть фрагмент запущенных (run:) программ.

Кто такой PDAC?

Строки

PDAC: PDPL is zero
PDAC: AUDIT is empty or invalid

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

Обратите внимание на порядковые номера двух похожих libsane1 правил:

  • /usr/lib/udev/rules.d/60-libsane1.rules;

  • /usr/lib/udev/rules.d/99-libsane1.rules.

Первый в порядке выполнения файл правила 60-libsane1.rules отрабатывает для SCSI-устройств (а также некоторых USB-устройств Epson и HP), второй 99-libsane1.rules — для остальных USB-устройств, подпадающих под фильтр ENV{DEVNAME}!="", и ENV{libsane_matched}=="yes" устанавливает ACL [31] на символьные файлы этих устройств.

/usr/lib/udev/rules.d/99-libsane1.rules

ENV{DEVNAME}!="", ENV{libsane_matched}=="yes", RUN+="/bin/setfacl -m g:scanner:rw $env{DEVNAME}"

Одна из основных задач проприетарного бэкенда — установить метку ENV{libsane_matched}=="yes" через udev-правило из состава пакета драйвера. Фрагмент 60-pantum_mfp.rules:

60-pantum_mfp.rules

# BM5100ADW
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="232b", ATTR{idProduct}=="2732", MODE="0666", OWNER="root", GROUP="lp", ENV{libsane_matched}="yes"

Очень жаль, что при перечислении считанных udev-правил — а их, как видно в листинге, довольно много, — нет информации, какие правила действительно отработали для текущего устройства. Чтобы получить эту ценную для диагностики информацию, необходимо выполнить запуск udev с расширенным логированием.

Как включить отладку udev

Как постоянный параметр запуска службы udev,

sudo sed -i 's/#udev_log=info/udev_log=debug/g' /etc/udev/udev.conf
sudo systemctl restart udev.service

или только для текущей сессии до перезагрузки.

sudo udevadm control --log-priority=debug

Это добавит в вывод udevadm дополнительную информацию. Просмотреть события службы systemd-udevd при подключении устройства можно при помощи journalctl:

# вывод всего буфера журнала
sudo journalctl -u systemd-udevd
# отображение журнала в режиме реального времени
sudo journalctl -u systemd-udevd -f
# вывод журнала за текущий день
sudo journalctl -u systemd-udevd --since today
И вот здесь самое «мясо»
<...>
systemd-udevd[328]: 1-1: Device (SEQNUM=6868, ACTION=add) is queued
systemd-udevd[328]: Validate module index
systemd-udevd[328]: Check if link configuration needs reloading.
systemd-udevd[328]: Successfully forked off 'n/a' as PID 2604.
systemd-udevd[328]: 1-1: Worker [2604] is forked for processing SEQNUM=6868.
systemd-udevd[2604]: 1-1: Processing device (SEQNUM=6868, ACTION=add)
systemd-udevd[2604]: 1-1: IMPORT builtin 'usb_id' /usr/lib/udev/rules.d/50-udev-default.rules:13
systemd-udevd[328]: 1-1:1.0: Device (SEQNUM=6869, ACTION=add) is queued
systemd-udevd[328]: usbmisc: Device (SEQNUM=6870, ACTION=add) is queued
systemd-udevd[328]: Successfully forked off 'n/a' as PID 2605.
systemd-udevd[328]: usbmisc: Worker [2605] is forked for processing SEQNUM=6870.
systemd-udevd[328]: lp0: Device (SEQNUM=6871, ACTION=add) is queued
systemd-udevd[328]: 1-1:1.0: Device (SEQNUM=6872, ACTION=bind) is queued
systemd-udevd[2605]: usbmisc: Processing device (SEQNUM=6870, ACTION=add)
systemd-udevd[2605]: usbmisc: Device (SEQNUM=6870, ACTION=add) processed
systemd-udevd[2605]: usbmisc: sd-device-monitor: Passed 129 byte to netlink monitor
systemd-udevd[328]: 1-1:1.1: Device (SEQNUM=6873, ACTION=add) is queued
systemd-udevd[328]: 1-1:1.2: Device (SEQNUM=6874, ACTION=add) is queued
systemd-udevd[328]: 1-1: Device (SEQNUM=6875, ACTION=bind) is queued
systemd-udevd[2604]: 1-1: IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/50-udev-default.rules:13
systemd-udevd[2604]: 1-1: No entry found from hwdb.
systemd-udevd[2604]: 1-1: IMPORT builtin 'hwdb' fails: No data available
systemd-udevd[2604]: 1-1: MODE 0664 /usr/lib/udev/rules.d/50-udev-default.rules:45
systemd-udevd[2604]: 1-1: GROUP 7 /usr/lib/udev/rules.d/50-udev-default.rules:57
systemd-udevd[2604]: 1-1: OWNER 0 /etc/udev/rules.d/60-pantum_mfp.rules:242
systemd-udevd[2604]: 1-1: GROUP 7 /etc/udev/rules.d/60-pantum_mfp.rules:242
systemd-udevd[2604]: 1-1: MODE 0666 /etc/udev/rules.d/60-pantum_mfp.rules:242
systemd-udevd[2604]: 1-1: IMPORT builtin 'path_id' /usr/lib/udev/rules.d/71-seat.rules:51
systemd-udevd[2604]: 1-1: RUN 'uaccess' /usr/lib/udev/rules.d/73-seat-late.rules:17
systemd-udevd[2604]: 1-1: RUN '/bin/setfacl -m g:scanner:rw $env{DEVNAME}' /usr/lib/udev/rules.d/99-libsane1.rules:2
systemd-udevd[2604]: 1-1: Handling device node '/dev/bus/usb/001/004', devnum=c189:3, mode=0666, uid=0, gid=7
systemd-udevd[2604]: 1-1: Setting permissions /dev/bus/usb/001/004, 020666, uid=0, gid=7
systemd-udevd[2604]: PDAC: PDPL is zero
systemd-udevd[2604]: PDAC: AUDIT is empty or invalid
systemd-udevd[2604]: 1-1: Creating symlink '/dev/char/189:3' to '../bus/usb/001/004'
systemd-udevd[2604]: 1-1: sd-device: Created db file '/run/udev/data/c189:3' for '/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb1/1-1'
systemd-udevd[2604]: Starting '/bin/setfacl -m g:scanner:rw /dev/bus/usb/001/004'
systemd-udevd[2604]: Successfully forked off '(spawn)' as PID 2606.
systemd-udevd[2604]: Process '/bin/setfacl -m g:scanner:rw /dev/bus/usb/001/004' succeeded.
systemd-udevd[2604]: 1-1: Device (SEQNUM=6868, ACTION=add) processed
systemd-udevd[2604]: 1-1: sd-device-monitor: Passed 767 byte to netlink monitor
systemd-udevd[328]: 1-1:1.0: sd-device-monitor: Passed 305 byte to netlink monitor
systemd-udevd[328]: 1-1:1.1: sd-device-monitor: Passed 311 byte to netlink monitor
systemd-udevd[328]: Successfully forked off 'n/a' as PID 2607.
systemd-udevd[328]: 1-1:1.2: Worker [2607] is forked for processing SEQNUM=6874.
systemd-udevd[2607]: 1-1:1.2: Processing device (SEQNUM=6874, ACTION=add)
systemd-udevd[2607]: 1-1:1.2: IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/50-udev-default.rules:14
systemd-udevd[2607]: 1-1:1.2: No entry found from hwdb.
systemd-udevd[2607]: 1-1:1.2: IMPORT builtin 'hwdb' fails: No data available
systemd-udevd[2607]: 1-1:1.2: IMPORT builtin 'usb_id' /usr/lib/udev/rules.d/60-libgphoto2-6.rules:9
systemd-udevd[2607]: 1-1:1.2: Failed to access usb_interface: No such file or directory
systemd-udevd[2607]: 1-1:1.2: IMPORT builtin 'usb_id' fails: No such file or directory
systemd-udevd[2607]: 1-1:1.2: RUN 'kmod load $env{MODALIAS}' /usr/lib/udev/rules.d/80-drivers.rules:5
systemd-udevd[2607]: Loading module: usb:v232Bp2732d0100dc00dsc00dp00icFFisc01ip01in02
systemd-udevd[2607]: Failed to find module 'usb:v232Bp2732d0100dc00dsc00dp00icFFisc01ip01in02'
systemd-udevd[2607]: 1-1:1.2: Device (SEQNUM=6874, ACTION=add) processed
systemd-udevd[2607]: 1-1:1.2: sd-device-monitor: Passed 307 byte to netlink monitor
systemd-udevd[2605]: 1-1:1.1: Processing device (SEQNUM=6873, ACTION=add)
systemd-udevd[2605]: 1-1:1.1: IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/50-udev-default.rules:14
systemd-udevd[2605]: 1-1:1.1: No entry found from hwdb.
systemd-udevd[2605]: 1-1:1.1: IMPORT builtin 'hwdb' fails: No data available
systemd-udevd[2605]: 1-1:1.1: IMPORT builtin 'usb_id' /usr/lib/udev/rules.d/60-libgphoto2-6.rules:9
systemd-udevd[2605]: 1-1:1.1: Failed to access usb_interface: No such file or directory
systemd-udevd[2605]: 1-1:1.1: IMPORT builtin 'usb_id' fails: No such file or directory
systemd-udevd[2605]: 1-1:1.1: RUN 'kmod load $env{MODALIAS}' /usr/lib/udev/rules.d/80-drivers.rules:5
systemd-udevd[2605]: Loading module: usb:v232Bp2732d0100dc00dsc00dp00icFFiscFFipFFin01
systemd-udevd[2605]: Failed to find module 'usb:v232Bp2732d0100dc00dsc00dp00icFFiscFFipFFin01'
systemd-udevd[2605]: 1-1:1.1: Device (SEQNUM=6873, ACTION=add) processed
systemd-udevd[2605]: 1-1:1.1: sd-device-monitor: Passed 311 byte to netlink monitor
systemd-udevd[2604]: 1-1:1.0: Processing device (SEQNUM=6869, ACTION=add)
systemd-udevd[2604]: 1-1:1.0: IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/50-udev-default.rules:14
systemd-udevd[2604]: 1-1:1.0: No entry found from hwdb.
systemd-udevd[2604]: 1-1:1.0: IMPORT builtin 'hwdb' fails: No data available
systemd-udevd[2604]: 1-1:1.0: IMPORT builtin 'usb_id' /usr/lib/udev/rules.d/60-libgphoto2-6.rules:9
systemd-udevd[2604]: 1-1:1.0: Failed to access usb_interface: No such file or directory
systemd-udevd[2604]: 1-1:1.0: IMPORT builtin 'usb_id' fails: No such file or directory
systemd-udevd[2604]: 1-1:1.0: IMPORT builtin 'usb_id' fails: No such file or directory
systemd-udevd[2604]: 1-1:1.0: RUN 'kmod load $env{MODALIAS}' /usr/lib/udev/rules.d/80-drivers.rules:5
systemd-udevd[2604]: Loading module: usb:v232Bp2732d0100dc00dsc00dp00ic07isc01ip02in00
systemd-udevd[2604]: Module 'usblp' is already loaded
systemd-udevd[2604]: 1-1:1.0: Device (SEQNUM=6869, ACTION=add) processed
systemd-udevd[2604]: 1-1:1.0: sd-device-monitor: Passed 318 byte to netlink monitor
systemd-udevd[328]: lp0: sd-device-monitor: Passed 230 byte to netlink monitor
systemd-udevd[2607]: lp0: Processing device (SEQNUM=6871, ACTION=add)
systemd-udevd[2607]: lp0: GROUP 7 /usr/lib/udev/rules.d/50-udev-default.rules:55
systemd-udevd[2607]: lp0: Handling device node '/dev/usb/lp0', devnum=c180:0, mode=0660, uid=0, gid=7
systemd-udevd[2607]: lp0: Setting permissions /dev/usb/lp0, 020660, uid=0, gid=7
systemd-udevd[2607]: PDAC: PDPL is zero
systemd-udevd[2607]: PDAC: AUDIT is empty or invalid
systemd-udevd[2607]: lp0: Creating symlink '/dev/char/180:0' to '../usb/lp0'
systemd-udevd[2607]: lp0: sd-device: Created empty file '/run/udev/data/c180:0' for '/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb1/1-1/1-1:1.0/usbmisc/lp0'
systemd-udevd[2607]: lp0: Device (SEQNUM=6871, ACTION=add) processed
systemd-udevd[2607]: lp0: sd-device-monitor: Passed 230 byte to netlink monitor
systemd-udevd[328]: 1-1:1.0: sd-device-monitor: Passed 319 byte to netlink monitor
systemd-udevd[2607]: 1-1:1.0: Processing device (SEQNUM=6872, ACTION=bind)
systemd-udevd[2607]: 1-1:1.0: IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/50-udev-default.rules:14
systemd-udevd[2607]: 1-1:1.0: No entry found from hwdb.
systemd-udevd[2607]: 1-1:1.0: IMPORT builtin 'hwdb' fails: No data available
systemd-udevd[2607]: 1-1:1.0: IMPORT builtin 'usb_id' /usr/lib/udev/rules.d/60-libgphoto2-6.rules:9
systemd-udevd[2607]: 1-1:1.0: Failed to access usb_interface: No such file or directory
systemd-udevd[2607]: 1-1:1.0: IMPORT builtin 'usb_id' fails: No such file or directory
systemd-udevd[2607]: 1-1:1.0: Device (SEQNUM=6872, ACTION=bind) processed
systemd-udevd[2607]: 1-1:1.0: sd-device-monitor: Passed 319 byte to netlink monitor
systemd-udevd[328]: 1-1: sd-device-monitor: Passed 300 byte to netlink monitor
systemd-udevd[2607]: 1-1: Processing device (SEQNUM=6875, ACTION=bind)
systemd-udevd[2607]: 1-1: IMPORT builtin 'usb_id' /usr/lib/udev/rules.d/50-udev-default.rules:13
systemd-udevd[2607]: 1-1: IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/50-udev-default.rules:13
systemd-udevd[2607]: 1-1: No entry found from hwdb.
systemd-udevd[2607]: 1-1: IMPORT builtin 'hwdb' fails: No data available
systemd-udevd[2607]: 1-1: OWNER 0 /etc/udev/rules.d/60-pantum_mfp.rules:242
systemd-udevd[2607]: 1-1: GROUP 7 /etc/udev/rules.d/60-pantum_mfp.rules:242
systemd-udevd[2607]: 1-1: MODE 0666 /etc/udev/rules.d/60-pantum_mfp.rules:242
systemd-udevd[2607]: 1-1: IMPORT builtin 'path_id' /usr/lib/udev/rules.d/71-seat.rules:51
systemd-udevd[2607]: 1-1: RUN 'uaccess' /usr/lib/udev/rules.d/73-seat-late.rules:17
systemd-udevd[2607]: 1-1: RUN '/bin/setfacl -m g:scanner:rw $env{DEVNAME}' /usr/lib/udev/rules.d/99-libsane1.rules:2
systemd-udevd[2607]: 1-1: Handling device node '/dev/bus/usb/001/004', devnum=c189:3, mode=0666, uid=0, gid=7
systemd-udevd[2607]: 1-1: Preserve permissions of /dev/bus/usb/001/004, 020666, uid=0, gid=7
systemd-udevd[2607]: PDAC: PDPL is zero
systemd-udevd[2607]: PDAC: AUDIT is empty or invalid
systemd-udevd[2607]: 1-1: Preserve already existing symlink '/dev/char/189:3' to '../bus/usb/001/004'
systemd-udevd[2607]: 1-1: sd-device: Created db file '/run/udev/data/c189:3' for '/devices/pci0000:00/0000:00:11.0/0000:02:02.0/usb1/1-1'
systemd-udevd[2607]: Starting '/bin/setfacl -m g:scanner:rw /dev/bus/usb/001/004'
systemd-udevd[2607]: Successfully forked off '(spawn)' as PID 2611.
systemd-udevd[2607]: Process '/bin/setfacl -m g:scanner:rw /dev/bus/usb/001/004' succeeded.
systemd-udevd[2607]: 1-1: Device (SEQNUM=6875, ACTION=bind) processed
systemd-udevd[2607]: 1-1: sd-device-monitor: Passed 768 byte to netlink monitor
systemd-udevd[328]: Cleanup idle workers
systemd-udevd[2604]: Unload module index
systemd-udevd[2605]: Unload module index
systemd-udevd[2605]: Unloaded link configuration context.
systemd-udevd[2604]: Unloaded link configuration context.
systemd-udevd[328]: Worker [2604] exited
systemd-udevd[328]: Worker [2605] exited
systemd-udevd[2607]: Unload module index
systemd-udevd[2607]: Unloaded link configuration context.
<...>

Советы от Капитана

На этом возможности udevadm не ограничены. Подробную информацию можно получить в справке man udevadm.

Отсюда мы узнаём, что для определения наименования производителя и его модели при помощи правила /usr/lib/udev/rules.d/50-udev-default.rules считываются строки с базы данных hwdb.

/usr/lib/udev/rules.d/50-udev-default.rules:13 строка

systemd-udevd[2604]: 1-1: IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/50-udev-default.rules:13
systemd-udevd[2604]: 1-1: No entry found from hwdb.
systemd-udevd[2604]: 1-1: IMPORT builtin 'hwdb' fails: No data available

Затем назначаются права "664".

/usr/lib/udev/rules.d/50-udev-default.rules:45 строка

SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"
udev rules hint

Управлять правами на все устройства, подпадающими по атрибутам SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", можно через единственный файл правила 50-udev-default.rules. А если установить запрет на дальнейшее изменение атрибутов MODE:="0600", то фактически одним махом будут отключены все последующие правила их бэкендов.

Следом для устройства с bInterfaceClass=7bInterfaceSubClass=1 и любым bInterfaceProtocol предоставляется доступ для группы lp. Под эти условия попадают принтеры [10].

/usr/lib/udev/rules.d/50-udev-default.rules:57 строка

SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", GROUP="lp"

Отрабатывает правило драйвера 60-pantum_mfp.rules, которое устанавливает достаточно избыточные права «0666» на символьный файл устройства /dev/bus/usb/001/004.

systemd-udevd[2604]: 1-1: OWNER 0 /etc/udev/rules.d/60-pantum_mfp.rules:242
systemd-udevd[2604]: 1-1: GROUP 7 /etc/udev/rules.d/60-pantum_mfp.rules:242
systemd-udevd[2604]: 1-1: MODE 0666 /etc/udev/rules.d/60-pantum_mfp.rules:242

Для всех пользователей «0666» будет вполне достаточно. Управление доступом на запись осуществлять через членство в группе lp. Но ещё изящнее и легковесней будет оставить только выполнение ENV{libsane_matched}="yes". Следом отработает связка правил 73-seat-late.rules,

/usr/lib/udev/rules.d/73-seat-late.rules:17

TAG=="uaccess", ENV{MAJOR}!="", RUN{builtin}+="uaccess"

которая установит метку uaccess для работы с файлом устройства через ACL при входе в сеанс пользователя и 99-libsane1.rules

RUN '/bin/setfacl -m g:scanner:rw $env{DEVNAME}' /usr/lib/udev/rules.d/99-libsane1.rules:2

c настройками ACL для группы scanner (113), в которой по умолчанию (для ALSE) присутствуют все новые пользователи. Раз уж затронули особенности бэкенда pantum, то и сам файл с udev-правилом корректно было бы назвать не 60-pantum_mfp.rules, а 60-pantum6500.rules, по аналогии с названием бэкенда. Драйвер pantum содержит два конфигурационных файла (см. вывод содержимого deb-пакета pantum_1.1.108-1astra1_amd64.deb из главы "Бэкенд") pantum6500.conf и pantum_mfp.conf. Да даже закомментированная строка в 60-pantum_mfp.rules

#ACTION!="add", GOTO="mud_rules_end"

#SUBSYSTEM=="usb_device", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="232b", ATTR{idProduct}=="1e10", MODE="0666", OWNER="root", GROUP="lp", ENV{libsane_matched}="yes"
<...>

говорит о том, что это правило никакого отношения к бэкенду pantum_mfp не имеет. Это лучше видно на изображении.

Используемые бэкендом pantum файлы

Используемые бэкендом pantum файлы

Для сравнения: вот открытый бэкенд xerox_mfp. Впрочем, он тоже не является показательным примером идеального именования файлов, так как не имеет выделенного udev-правила с «личным» названием.

Используемые бэкендом xerox_mfp файлы (а также имена пакетов)

Используемые бэкендом xerox_mfp файлы (а также имена пакетов)

Далее udev опять прогоняет каждый интерфейс через правила и пытается подобрать к нему драйвер (модуль ядра), используя идентификатор MODALIAS [32]. У pantum интерфейса три:

  • usb:v232Bp2732d0100dc00dsc00dp00ic07isc01ip02in00 (4-1:1.0)

  • usb:v232Bp2732d0100dc00dsc00dp00icFFiscFFipFFin01 (4-1:1.1)

  • usb:v232Bp2732d0100dc00dsc00dp00icFFisc01ip01in02 (4-1:1.2)

Первому интерфейсу загружен модуль usblp, а на остальные два модулей не нашлось. Просмотреть все alias можно командой modprobe -c. Команда считывает содержимое файла /lib/modules/$(uname -r)/modules.alias, и там можно обнаружить строку с маской,

<...>
alias usb:v*p*d*dc*dsc*dp*ic07isc01ip02in* usblp
<...>

по которой был найден usb:v232Bp2732d0100dc00dsc00dp00ic07isc01ip02in00.

Все alias для модуля usblp удобно просмотреть командой modinfo.

sudo modinfo usblp

filename:       /lib/modules/5.4.0-110-generic/kernel/drivers/usb/class/usblp.ko
license:        GPL
description:    USB Printer Device Class driver
author:         Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal
srcversion:     EFA4AEE65DA637CC5975DD9
alias:          usb:v04B8p0202d*dc*dsc*dp*ic*isc*ip*in*
alias:          usb:v*p*d*dc*dsc*dp*ic07isc01ip03in*
alias:          usb:v*p*d*dc*dsc*dp*ic07isc01ip02in*
alias:          usb:v*p*d*dc*dsc*dp*ic07isc01ip01in*
alias:          usb:v*p*d*dc07dsc01dp03ic*isc*ip*in*
alias:          usb:v*p*d*dc07dsc01dp02ic*isc*ip*in*
alias:          usb:v*p*d*dc07dsc01dp01ic*isc*ip*in*
depends:
retpoline:      Y
intree:         Y
name:           usblp
vermagic:       5.4.0-110-generic SMP mod_unload modversions
parm:           proto_bias:Favourite protocol number (int)

В целях тестирования существует способ отключить автозагрузку модулей при подключении устройства.

disable autoprobe

echo 0 | sudo tee /sys/bus/usb/drivers_autoprobe

В Astra Linux Special Edition есть аналогичный механизм управления загрузки новых модулей ядра - astra-modban-lock. Подробнее — в Инструменты командной строки astra-safepolicy.

Однако отключение автозагрузки через drivers_autoprobe приведёт к тому, что конфигурация устройства не будет установлена.

usb-devices

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  7 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=232b ProdID=2732 Rev=01.00
S:  Manufacturer=Pantum
S:  Product=BM5100ADW series
S:  SerialNumber=CK1A046238
C:  #Ifs= 0 Cfg#= 0 Atr= MxPwr=
cat: '/sys/bus/usb/devices/usb1/1-1/1-*:?.*/bInterfaceNumber': Нет такого файла или каталога
cat: '/sys/bus/usb/devices/usb1/1-1/1-*:?.*/bAlternateSetting': Нет такого файла или каталога
cat: '/sys/bus/usb/devices/usb1/1-1/1-*:?.*/bNumEndpoints': Нет такого файла или каталога
cat: '/sys/bus/usb/devices/usb1/1-1/1-*:?.*/bInterfaceClass': Нет такого файла или каталога
cat: '/sys/bus/usb/devices/usb1/1-1/1-*:?.*/bInterfaceSubClass': Нет такого файла или каталога
cat: '/sys/bus/usb/devices/usb1/1-1/1-*:?.*/bInterfaceProtocol': Нет такого файла или каталога
/usr/bin/usb-devices: строка 76: printf: (none): недопустимое число
I:  If#=0x Alt= 0 #EPs= 0 Cls=() Sub= Prot= Driver=

Это необходимо выполнить вручную:

echo 1 | sudo tee /sys/bus/usb/devices/usb1/1-1/bConfigurationValue

Конкретно с pantum, модуль usblp, загруженный для интерфейса принтера, может мешать usbfs для конфигурирования интерфейса сканера. Попытки выполнить сканирование через любой фронтенд будут заканчиваться ошибками:

[  158.793334] usblp 1-1:1.0: usblp0: USB Bidirectional printer dev 2 if 0 alt 0 proto 2 vid 0x232B pid 0x2732
[  158.793575] usbcore: registered new interface driver usblp
<...>
[  185.864861] usb 1-1: usbfs: interface 0 claimed by usblp while 'KSaneIface::Fin' sets config #1
[  198.897101] usb 1-1: usbfs: interface 0 claimed by usblp while 'fly-scan' sets config #1
[  200.462243] usb 1-1: usbfs: interface 0 claimed by usblp while 'KSaneIface::KSa' sets config #1
[  224.768681] usb 1-1: usbfs: interface 0 claimed by usblp while 'KSaneIface::KSa' sets config #1

Или «Ошибка 25» на дисплее устройства (актуально для Pantum).

В этом случае поможет временная выгрузка модуля

sudo rmmod usplp

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

echo blacklist usblp | sudo tee -a /etc/modprobe.d/blacklist.conf
sudo update-initramfs -u -k all
sudo reboot

Выполнение rmmod usblp не остановит повторную загрузку модуля при переподключении устройства.

Зачем тогда вообще usblp?

Ситуация с модулем usblp довольно противоречивая. С одной стороны, его автоматическая загрузка в некоторых случаях может мешать функции сканирования. С другой, ещё ходят по земле староверы, которым нужен /dev/usb/lp0 для печати.

Некоторые устройства Samsung могут отказывать в сканировании, если до этого на МФУ была выполнена печать задания с CUPS (libusb). В этом случае usblp поможет в печати с устройства /dev/usb/lp0, минуя обращение к libusb. Для включения возможности добавить устройство произвольного вида file:///dev/usb/lp0 требуется раскомментировать строку FileDevice в конфигурационном файле /etc/cups/cups-files.conf.

# Do we allow file: device URIs other than to /dev/null?
FileDevice Yes

Знание устройства работы подсистемы udev позволяет понять, каким образом той или иной функции устройства (интерфейсу) назначается модуль. Это может сильно сэкономить время на этапе тестирования, решая, скажем, проблему [33] подгружаемых модулей устройства.

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

scanimage (sane-utils)

Scanimage — это консольная версия фронтенда для сканирования из терминала. Фронтенд в данном случае — любое пользовательское приложение, использующее инструментарий SANE. Scanimage обладает всем необходимым функционалом для автоматизации сканирования через скрипты. Всё, что работает в scanimage, должно работать в других приложениях фронтенда SANE (к примеру simple-scan, fly-scan, naps2). Если этого не происходит, это баг конкретного приложения. И, конечно, наоборот, scanimage не всегда сможет выполнить «особое» сканирование, которое исправно выполняет фирменное приложение вендора.

Первое, с чего начинается работа со scanimage, — поиск всех доступных устройств, обнаруженных перечисленными в /etc/sane.d/dll.conf (и не забываем про /etc/sane.d/dll.d) бэкендами командой scanimage -L (--list-devices).

scanimage -L

device `escl:https://10.0.0.20:443' is a ESCL Pantum BM5100ADW Series 4B94CA platen,adf scanner
device `pantum6500:libusb:004:002' is a  Pantum BM5100ADW series (libusb:004:002)

Вывод довольно легко расшифровать: имя устройства (URI) включает в себя название бэкенда (backend name), а также адрес шины и порты подключения libusb (libusb device path), разделенные ":". Для мало-мальской идентификации имя может быть дополнено описанием (device description from backend), содержащим наименование производителя, модель и тип подключения.

Расшифровка device URI бэкенда pantum6500

Расшифровка device URI бэкенда pantum6500

Формат имени устройства (URI) не регламентирован SANE. Устройство получает имя на усмотрение разработчика бэкенда. Яркий пример — Unified Linux Driver для Xerox (smfp).

Расшифровка device URI бэкенда smfp

Расшифровка device URI бэкенда smfp

В этом случае вместо динамически получаемого от libusb имени бэкенд установит уникальное имя, которое не будет меняться при переподключении устройства. Как видим, тип подключения (usb), idVendor (0924), idProduct (42e9) и серийный номер (5290488780) гарантируют неповторимость URI. При добавлении его в «Избранное» или использовании в скриптах ошибки обнаружения исключены.

Да, при локальном подключении используется libusb (libusb-1.0-0, версия по-умолчанию в ALSE 1.7.x). Код некоторых бэкендов может использовать более старую версию libusb-0.1-4.

Обратите внимание: в выводе присутствует одно устройство, обнаруженное двумя бэкендами — сетевым escl и локальным pantum6500. Но что делать, если ожидаемое устройство отсутствует в списке?
Первый шаг: повторный запуск от root, чтобы не тратить время на поиск проблем с правами доступа к символьному файлу устройства. Далее нужно включить отображение диагностической информации об используемых при поиске бэкендов через переменную окружения SANE_DEBUG_DLL=<level>. Максимальный уровень <level> — 4 (но можно и 255, чтобы наверняка).

SANE_DEBUG_DLL=4 scanimage -L
<...>
[21:18:59.440837] [sanei_debug] Setting debug level of dll to 4.
[21:18:59.441770] [dll] sane_init: SANE dll backend version 1.0.13 from sane-backends 1.1.1-debian
[21:18:59.442488] [dll] sane_init/read_dlld: attempting to open directory `./dll.d'
[21:18:59.443250] [dll] sane_init/read_dlld: attempting to open directory `/etc/sane.d/dll.d'
[21:18:59.444148] [dll] sane_init/read_dlld: using config directory `/etc/sane.d/dll.d'
[21:18:59.444685] [dll] sane_init/read_dlld: considering /etc/sane.d/dll.d/pantum_mfp
[21:18:59.445289] [dll] sane_init/read_config: reading dll.d/pantum_mfp
[21:18:59.445826] [dll] add_backend: adding backend `pantum_mfp'
[21:18:59.446318] [dll] sane_init/read_dlld: considering /etc/sane.d/dll.d/pantum6500
[21:18:59.446878] [dll] sane_init/read_config: reading dll.d/pantum6500
[21:18:59.447363] [dll] add_backend: adding backend `pantum6500'
[21:18:59.447912] [dll] sane_init/read_dlld: considering /etc/sane.d/dll.d/airscan
[21:18:59.448503] [dll] sane_init/read_config: reading dll.d/airscan
[21:18:59.449022] [dll] add_backend: adding backend `airscan'
[21:18:59.449548] [dll] sane_init/read_dlld: considering /etc/sane.d/dll.d/hplip
[21:18:59.450138] [dll] sane_init/read_config: reading dll.d/hplip
[21:18:59.450640] [dll] add_backend: adding backend `hpaio'
[21:18:59.451128] [dll] sane_init/read_dlld: done.
[21:18:59.451679] [dll] sane_init/read_config: reading dll.conf
[21:18:59.452314] [dll] add_backend: adding backend `net'
[21:18:59.452794] [dll] add_backend: adding backend `abaton'
[21:18:59.453252] [dll] add_backend: adding backend `agfafocus'
[21:18:59.453707] [dll] add_backend: adding backend `apple'
[21:18:59.454157] [dll] add_backend: adding backend `artec'
<...>
[21:18:59.461212] [dll] add_backend: adding backend `xerox_mfp'
[21:18:59.461287] [dll] add_backend: adding backend `smfp'
[21:18:59.461442] [dll] sane_get_devices
[21:18:59.461536] [dll] load: searching backend `smfp' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:18:59.461669] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-smfp.so.1'
[21:18:59.461856] [dll] load: couldn't open `/usr/lib/x86_64-linux-gnu/sane/libsane-smfp.so.1' (No such file or directory)
[21:18:59.462004] [dll] load: trying to load `/usr/lib/sane/libsane-smfp.so.1'
[21:18:59.462294] [dll] load: dlopen()ing `/usr/lib/sane/libsane-smfp.so.1'
[21:18:59.464916] [dll] load: dlopen() failed (libusb-0.1.so.4: cannot open shared object file: No such file or directory)
[21:18:59.465105] [dll] load: searching backend `xerox_mfp' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:18:59.465246] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-xerox_mfp.so.1'
[21:18:59.465474] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-xerox_mfp.so.1'
[21:18:59.466347] [dll] init: initializing backend `xerox_mfp'
[21:18:59.498524] [dll] init: backend `xerox_mfp' is version 1.0.13
<...>
[21:19:09.324879] [dll] load: searching backend `pantum6500' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:19:09.325004] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-pantum6500.so.1'
[21:19:09.325271] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-pantum6500.so.1'
[21:19:09.327055] [dll] init: initializing backend `pantum6500'
[21:19:09.356191] [dll] init: backend `pantum6500' is version 1.0.13
dev_inquiry: Model name = Pantum BM5100ADW series (libusb:003:004)
[21:19:16.532357] [dll] load: searching backend `pantum_mfp' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:19:16.532563] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-pantum_mfp.so.1'
[21:19:16.532809] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-pantum_mfp.so.1'
[21:19:16.535115] [dll] init: initializing backend `pantum_mfp'
[21:19:16.563974] [dll] init: backend `pantum_mfp' is version 1.0.13
[21:19:16.564382] [dll] sane_get_devices: found 1 devices
device `pantum6500:libusb:003:004' is a  Pantum BM5100ADW series (libusb:003:004)
[21:19:16.564628] [dll] sane_exit: exiting
[21:19:16.564785] [dll] sane_exit: calling backend `xerox_mfp's exit function
<...>
[21:19:16.591441] [dll] sane_exit: calling backend `abaton's exit function
[21:19:16.591727] [dll] sane_exit: calling backend `net's exit function
[21:19:16.593534] [dll] sane_exit: calling backend `hpaio's exit function
[21:19:16.595281] [dll] sane_exit: calling backend `airscan's exit function
[21:19:16.601232] [dll] sane_exit: calling backend `pantum6500's exit function
[21:19:16.601792] [dll] sane_exit: calling backend `pantum_mfp's exit function
[21:19:16.605785] [dll] sane_exit: finished

Вывод достаточно огромный за счет количества подгружаемых по умолчанию бэкендов. В листинге можно увидеть, что приоритет использования бэкендов из директории /etc/sane.d/dll.d для сторонних (проприетарных) бэкендов выше,

[21:18:59.443250] [dll] sane_init/read_dlld: attempting to open directory `/etc/sane.d/dll.d'

чем у /etc/sane.d/dll.conf.

[21:18:59.451679] [dll] sane_init/read_config: reading dll.conf

Наиболее полезными могут оказаться ошибки о ненайденных (No such file or directory).so файлах. В выводе как раз отмечена такая libsane-smfp.so.1 в составе бэкенда smfp (Unified Linux Driver) [34].

Символьные ссылки на библиотеки

На самом деле sane не обращается к файлам библиотек libsane*.so.* напрямую, а делает это через символьные ссылки с именем .so или .so.1. Как известно, каждое имя файла связано с некоторым уникальным индексным дескриптором. С помощью символических ссылок (symbolic links) можно дать файлу другое имя, но не связывать файл с индексным дескриптором. Благодаря этому разработчику библиотеки не надо заботиться об имени файла, чтобы sane его нашел. Достаточно разместить символьную ссылку с фиксированным именем. Это даёт возможность хранить централизованно определенные тестированные версии .so файлов, скажем, на сетевом ресурсе.

Альтернативой символическим ссылкам может служить определение переменной окружения LD_LIBRARY_PATH=<path_1>:<path_2>, где <path_n> — абсолютный путь до каталогов с .so файлами, разделенный ":" (двоеточием).

[21:18:59.461536] [dll] load: searching backend `smfp' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:18:59.461669] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-smfp.so.1'
[21:18:59.461856] [dll] load: couldn't open `/usr/lib/x86_64-linux-gnu/sane/libsane-smfp.so.1' (No such file or directory)
[21:18:59.462004] [dll] load: trying to load `/usr/lib/sane/libsane-smfp.so.1'
[21:18:59.462294] [dll] load: dlopen()ing `/usr/lib/sane/libsane-smfp.so.1'
[21:18:59.464916] [dll] load: dlopen() failed (libusb-0.1.so.4: cannot open shared object file: No such file or directory)

SANE безуспешно пытается найти библиотеку (ссылку) бэкенда по пути /usr/lib/x86_64-linux-gnu/sane/libsane-smfp.so.1, а находит и успешно её открывает из /usr/lib/sane/libsane-smfp.so.1. Но дальше библиотека имеет в зависимостях libusb-0.1.so.4, которая отсутствует в системе (c ALSE 1.7.x по умолчанию установлен пакет libusb-1.0-0). В этом случае установка пакета libusb-0.1-4 решит проблему.

Не совсем

После решения проблемы с libusb sane не сможет обнаружить /usr/lib/x86_64-linux-gnu/sane/libsane-smfp.so.1.0.1, так как пакет копирует его в /opt/smfp-common/scanner/lib/libsane-smfp.so.1.0.1

Для решения проблемы необходимо создать верную символьную ссылку.

sudo ln -s /opt/smfp-common/scanner/lib/libsane-smfp.so.1.0.1 /usr/lib/x86_64-linux-gnu/sane/libsane-smfp.so.1

К слову, именно с этой ошибкой столкнулись многие пользователи сканирующих устройств после перехода с Astra Linux Common Edition 2.12 и Astra Linux Special Edition 1.6 на Astra Linx Special Edition (ALSE) 1.7 (Debian 9 и Debian 10). Подобная отладочная информация поможет выявить проблемы недостающих библиотек при использовании проприетарного бэкенда.

Отображение отладочной информации на уровне бэкенда поможет разобраться, почему устройство не обнаруживается или не сканирует. Использование имени переменной SANE_DEBUG_<BACKEND_NAME> стандартизировано, и каждый открытый бэкенд (в теории) должен её поддерживать. В зависимости от вендора вывод может содержать:

  • имена использованных конфигурационных файлов, процесс их построчного считывания;

  • вывод результата работы служебных вызовов бэкенда.

Пример максимально детализированной отладочной информации SANE_DEBUG_PANTUM6500=255 для pantum6500:

SANE_DEBUG_PANTUM6500=255 scanimage -L
[21:33:58.646100] [sanei_debug] Setting debug level of pantum6500 to 255.
[21:33:58.646308] [pantum6500] sane_init: pantum backend (build 13), version != null, authorize != null
[21:33:58.677003] [pantum6500] sane_pantum6500_init:FRONT_END_OTHERS
[21:33:58.677204] [pantum6500] sane_pantum6500_init:LANG = ru_RU.UTF-8
[21:33:58.677386] [pantum6500] sane_pantum6500_init:g_is_lang_zh = 0
[21:33:58.677643] [pantum6500] sane_pantum6500_get_devices: 0x7ffcae102c80, 0
[21:33:58.677984] [pantum6500] list_conf_devices: usb 0x232b 0x0e20 M6500
[21:33:58.678186] [pantum6500] list_conf_devices: usb 0x232b 0x1e20 M6500N
<...>
[21:33:58.767457] [pantum6500] list_one_device: libusb:003:004-BM5100ADW series
[21:33:58.767612] [pantum6500] usb_dev_open: open 0x1d5bc10
[21:33:58.768170] [pantum6500] device path = libusb:003:004, model_name = BM5100ADW series
dev_inquiry: Model name = Pantum BM5100ADW series (libusb:003:004)
[21:33:58.768368] [pantum6500] dev_inquiry: found /Pantum BM5100ADW series (libusb:003:004)
[21:33:58.768528] [pantum6500] fix_window: dev->val[OPT_SOURCE].s = Flatbed
[21:33:58.768690] [pantum6500] fix_window: dev->val[OPT_SOURCE].s = Flatbed[21:33:58.768817] [pantum6500] br-x=216.000000 br-y=297.000000
[21:33:58.768971] [pantum6500] *************************geo=稿台
[21:33:58.769130] [pantum6500] br-x=216.000000 br-y=297.000000
[21:33:58.769280] [pantum6500] dev->val[OPT_RESOLUTION].w=300
[21:33:58.769436] [pantum6500] fix_window: before scan_mode_to_code
[21:33:58.769580] [pantum6500] fix_window: after scan_mode_to_code:3
[21:33:58.769722] [pantum6500] win_width 850, win_len 1169
[21:33:58.769865] [pantum6500] usb_dev_close: closing dev 0x1d5bc10
[21:33:58.810572] [pantum6500] list_one_device: libusb:003:004-BM5100ADW series dev_open dev_close ok
[21:33:58.810768] [pantum6500] list_conf_devices: usb 0x232b 0x2740 BM5100FDN
<...>
[21:33:58.813136] [pantum6500] list_conf_devices: tcp M6500 9200
[21:33:58.813294] [pantum6500] search_net_mfp: start.
[21:33:58.813994] [pantum6500] search_net_mfp: interface num: 3
[21:33:58.814490] [pantum6500] probe_device: interface: eth0, ip addr: 10.0.0.20
[21:33:58.815297] [pantum6500] probe_device: interface: eth0, ip addr: fe80::1076:c551:a0d5:12da%eth0
[21:34:05.876299] [pantum6500] search_net_mfp: exit.
[21:34:05.876517] [pantum6500] list_conf_devices: usb 0x232b 0xa421 M6500-Series
<...>
[21:34:05.881405] [pantum6500] list_conf_devices: usb 0x232b 0x2715 BM5110ADW
device `pantum6500:libusb:003:004' is a  Pantum BM5100ADW series (libusb:003:004)

К большому разочарованию, не все производители оставляют возможность вывода отладочной информации через переменную окружения SANE_DEBUG. Чтобы выяснить, как организован вывод, приходится детально изучать файлы драйвера или использовать сторонние утилиты вроде lsof для поиска всех измененных во время вызова scanimage файлов. В надежде, что хоть какая-то отладка по умолчанию включена. Например, драйвер uld (Unified Linux Driver) [34], именуемый в системе как smfp, пишет отладочную информацию в

/opt/smfp-common/scanner/share/libsane-smfp.cfg

log4cplus.appender.file.File=/tmp/libsane-smfp-${USER}-${UID}.log

Это не очень удобно, так как требует внесения изменений в /opt/smfp-common/scanner/share/libsane-smfp.cfg для временного увеличения уровня логирования до DEBUG. А потом еще нужно не забыть его вернуть. Сравните с очевидным удобством переменной окружения.

Kodak тоже пошёл по своему пути, в нем каждое использование бэкенда kds_s2000 [35] фиксируется в файлах в директории с временной меткой /var/kodak/kds_s2000/.

На фоне подхода именитых производителей приятно видеть, как разработчик открытого проекта sane-airscan [36] Alex Pevzner добавил в код бэкенда airscan поддержку переменной SANE_DEBUG_AIRSCAN. И это в дополнение к возможности включить режим отладки через конфигурационный файл /etc/sane.d/airscan.conf на постоянной основе. Вообще, надо отдать должное качеству инструментов в составе проекта, ориентированных на сбор диагностической информации. Разработчик заинтересован в поддержке проекта и анализу проблем. Лучи добра тебе, Alex!

Опыт развития sane-airscan

Категорически рекомендую прочитать статью "Как делается OpenSource: личный опыт" [47] за авторством Alex Pevzner. Он в одиночку создал и развил проект sane-airscan, который входит в состав всех популярных дистрибутивов.

После успешного обнаружения устройства хорошей практикой считается выполнить тестовое сканирование scanimage -T,

Output format is not set, using pnm as a default.
dev_inquiry: Model name = Pantum BM5100ADW series (libusb:003:004)
sane_pantum6500_start: dev->doc_source = 100, scanning = 0, reading = 0
bHave_enough_memory: sizeof(s_info)=112
, mem_unit=1, freeram=646750208, freeswap=0
current memory left: 616M, total image size = 25M
scanimage: scanning image of size 2550x3507 pixels at 24 bits/pixel
scanimage: acquiring RGB frame, 8 bits/sample
scanimage: reading one scanline, 7650 bytes...  PASS
scanimage: reading one byte...          PASS
scanimage: stepped read, 2 bytes...     PASS
scanimage: stepped read, 4 bytes...     PASS
scanimage: stepped read, 8 bytes...     PASS
scanimage: stepped read, 16 bytes...    PASS
scanimage: stepped read, 32 bytes...    PASS
scanimage: stepped read, 64 bytes...    PASS
scanimage: stepped read, 128 bytes...   PASS
scanimage: stepped read, 256 bytes...   PASS
scanimage: stepped read, 512 bytes...   PASS
scanimage: stepped read, 1024 bytes...  PASS
scanimage: stepped read, 2048 bytes...  PASS
scanimage: stepped read, 4096 bytes...  PASS
scanimage: stepped read, 8192 bytes...  PASS
scanimage: stepped read, 8191 bytes...  PASS
scanimage: stepped read, 4095 bytes...  PASS
scanimage: stepped read, 2047 bytes...  PASS
scanimage: stepped read, 1023 bytes...  PASS
scanimage: stepped read, 511 bytes...   PASS
scanimage: stepped read, 255 bytes...   PASS
scanimage: stepped read, 127 bytes...   PASS
scanimage: stepped read, 63 bytes...    PASS
scanimage: stepped read, 31 bytes...    PASS
scanimage: stepped read, 15 bytes...    PASS
scanimage: stepped read, 7 bytes...     PASS
scanimage: stepped read, 3 bytes...     PASS

чтобы убедиться, что взаимодействие бэкенда с устройством проходит без сбоев.

Есть нюансы

Практика проверки работоспособности по результатам тестирования scanimage -T может быть неточна для всех сканирующих устройств. Например, Kyocera проходит успешно (PASS) лишь малую часть. Между тем это никак не сказывается на функционале устройства при сканировании через scanimage.

А также выполнить запрос всех доступных функций драйвера scanimage -A.

Output format is not set, using pnm as a default.
dev_inquiry: Model name = Pantum BM5100ADW series (libusb:003:004)

All options specific to device `pantum6500:libusb:003:004':
  Standard:
    --preview[=(yes|no)] [no]
        Request a preview-quality scan.
    --resolution 75|150|300|600|1200dpi [300]
        Sets the resolution of the scanned image.
    --mode Lineart|Gray|Color [Color]
        Selects the scan mode (e.g., lineart, monochrome, or color).
    --threshold 1..255 [inactive]
        Select minimum-brightness to get a white point
    --source Flatbed|Automatic Document Feeder|Automatic Document Feeder (Duplex) [Flatbed]
        Selects the scan source (such as a document-feeder).
    --geometry 稿台|A4|A5|B5|Letter|Full size [A4]
        Scan area and media size options
    -l 0..216mm (in steps of 1) [0]
        Top-left x position of scan area.
    -t 0..297mm (in steps of 1) [0]
        Top-left y position of scan area.
    -x 0..216mm (in steps of 1) [216]
        Width of scan-area.
    -y 0..297mm (in steps of 1) [297]
        Height of scan-area.

Эта информация демонстрирует заявленные драйвером возможности (значения, установленные драйвером по умолчанию, указаны в квадратных скобках). Стоит отметить, что разные версии одного драйвера могут поддерживать разный функционал и даже разные значения по умолчанию, также как и разные драйверы для одного устройства. Порой в этот функционал могут входить даже такие существенные возможности, как поддержка сканирования через АПД всех страниц в лотке.

Если перед вами стоит задача провести полное тестирование функционала устройства с заданной версией драйвера, рекомендуется проверить безошибочную работу с каждым возможным значением доступных параметров сканирования: source, resolution, mode и т.д. Повторюсь, никто не мешает это автоматизировать. По сути, автоматизация — это "киллер-фича" scanimage.

Диагностика

Когда дело доходит до диагностики проблем, то как при обнаружении устройств, так и при сканировании следует придерживаться принципа «от общего к частному».

  • SANE_DEBUG_DLL=<level> — отображение информации о загрузке всех бэкендов. 255 — максимальная детализация.

  • SANE_DEBUG_<BACKEND_NAME>=<level> — детализация работы конкретного бэкенда.

Не такой как все

Уровень <level> отображения информации обычно задается числовым значением, где 1 — минимальный уровень, 255 — максимальный уровень. Бэкенд epkowa от Epson предлагает иную схему: hex, cmd, info.

  • если переменная SANE_DEBUG для бэкенда отсутствует, нужно ознакомиться с документацией к нему — проверить расположение диагностических файлов и порядок включения режима отладки.

  • SANE_DEBUG_SANEI_USB (SANE_DEBUG_SANEI_TCP для сетевого) — отладочная информация на уровне libusb.

Если есть предположение, что проблема находится вне libusb, полезно будет проанализировать информацию о USB-трафике между usb_bus>host>device, используя модуль usbmon [14], собранную tcpdump (tcpdump),

sudo apt install tcpdump
sudo modprobe usbmon
sudo tcpdump -i usbmon0 -s0 -w scan.pcap

или через отображение USB-трафика, используя usbdevfs (включая данные, передаваемые через libusb). Вызов команд, обращающихся к устройству, будет сопровождаться событиями в dmesg и /var/log/syslog.

echo Y | sudo tee /sys/module/usbcore/parameters/usbfs_snoop

Главное преимущество usbfs_snoop в сравнении с usbmon  вывод не ограничен 32 байтами.

Каждый фронтенд может иметь дополнительные переменные, заложенные разработчиком, которые позволяют отображать отладочную информацию. В ней могут содержаться данные о параметрах сканирования (источник, цвет, разрешение), а также выполняемые пользователем в программе действия. В ALSE используется программа fly-scan. Выполнение из консоли с отображением диагностической информации.

QT_LOGGING_RULES="ru.astralinux.fly-scan=true;org.kde.ksane=true" fly-scan

Полезной может оказаться настройка вывода сообщений ядра напрямую в консоль так, чтобы не нужно было регулярно заглядывать в dmesg. Управление выводом происходит через конфигурационный файл /etc/syslog-ng/syslog-ng.conf службы syslog-ng (в ALSE, syslog-ng служба журналирования по умолчанию). К примеру, для вывода событий в /dev/pts/0 следует добавить строки

/etc/syslog-ng/syslog-ng.conf

destination d_console_tty { file("/dev/pts/0"); };
log { source(s_src); filter(f_kern); destination(d_console_tty); };

и перезапустить службу.

sudo systemctl restart syslog-ng

TOП-8 распространенных ошибок

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

  1. Нет прав доступа на чтение и запись на символьном файле устройства при выполнении сканирования или обнаружения устройства под обычным пользователем.

  2. Отсутствуют или находятся в другом месте общие библиотеки драйвера.

  3. Отсутствуют пакеты с библиотеками, необходимыми для работы бэкенда.

  4. Файл устройства занят другим модулем или службой.

  5. Сканирование выполняется не через целевой бэкенд. Как следствие, ограничен функционал универсального бэкенда.

  6. Использование USB 2.0 устройств на компьютере с портами USB 3.0 с xhci драйвером.

  7. Бэкенды мешают друг другу (применительно для сетевых бэкендов).

  8. Отсутствие у текущего пользователя прав на проприетарные приложения вендора.

Отсутствие драйвера

Но что остается делать, когда драйвер установлен корректно, а устройство так и не обнаружено?

Расскажем на примере с Kyocera FS-1028MFP (idVendor=0482 idProduct=03C5). Устройство довольно старое, но по-прежнему надежное и недорогое в обслуживании. Драйвера на официальном сайте производителя, конечно же, нет.

dmesg корректно определяет устройство:

sudo dmesg

[  164.001368] usb 1-3: new high-speed USB device number 3 using ehci-pci
[  164.159162] usb 1-3: New USB device found, idVendor=0482, idProduct=03c5, bcdDevice= 0.00
[  164.159174] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  164.159181] usb 1-3: Product: Kyocera FS-1028MFP
[  164.159187] usb 1-3: Manufacturer: Kyocera
[  164.159193] usb 1-3: SerialNumber: QUV1539570
[  164.298131] usblp 1-3:1.0: usblp1: USB Bidirectional printer dev 3 if 0 alt 0 proto 2 vid 0x0482 pid 0x03C5
[  164.299188] usbcore: registered new interface driver usblp

Вывод sane-find-scanner показывает, что обнаруженное устройство является потенциальным сканером.

sudo sane-find-scanner

found USB scanner (vendor=0x0482 [Kyocera], product=0x03c5 [Kyocera FS-1028MFP]) at libusb:001:002

Права на файл устройства назначены группе lp. Сейчас это неважно, все дальнейшие команды будут выполняться от пользователя с повышенными привилегиями.

ls -lha /dev/bus/usb/001/003

crw-rw-r-- 1 root lp   189, 388 июл 25 21:33 /dev/bus/usb/001/003

Как упоминалось выше, драйверов для Linux на сайте производителя нет, но есть пакет kyocera-sane_2.0.0326. Он доступен для всех моделей МФУ производства Kyocera. Да, во всех конфигурационных файлах /etc/sane.d/*.conf отсутствует упоминание idVendor=0482, idProduct=03c5 этой модели. Несмотря на это, попробуем установить пакет и добавить в /etc/sane.d/kyocera.conf эти данные вручную.

/etc/sane.d/kyocera.conf

#FS-1028 MFP
usb 0x0482 0x03C5

Выполним запуск scanimage с отладкой SANE_DEBUG_DLL=4, чтобы убедиться, что драйвер установлен и отрабатывает при поиске успешно:

SANE_DEBUG_DLL=4 scanimage -L
[21:19:03.546126] [dll] add_backend: adding backend `kyocera'
[21:19:03.546367] [dll] add_backend: adding backend `kyocera_gdi_a3'
[21:19:03.546726] [dll] add_backend: adding backend `kyocera_wc3'
[21:19:03.547026] [dll] add_backend: adding backend `kyocera_wc3_usb'
[21:19:03.547454] [dll] sane_get_devices
[21:19:03.547881] [dll] load: searching backend `kyocera_wc3_usb' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:19:03.547966] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3_usb.so.1'
[21:19:03.548121] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3_usb.so.1'
[21:19:03.550448] [dll] init: initializing backend `kyocera_wc3_usb'
[21:19:03.575034] [dll] init: backend `kyocera_wc3_usb' is version 1.0.1
[21:19:03.575605] [dll] load: searching backend `kyocera_wc3' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:19:03.575711] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3.so.1'
[21:19:03.575881] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3.so.1'
[21:19:03.589895] [dll] init: initializing backend `kyocera_wc3'
[21:19:03.590028] [dll] init: backend `kyocera_wc3' is version 1.0.1
[21:19:18.612407] [dll] load: searching backend `kyocera_gdi_a3' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:19:18.613236] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_gdi_a3.so.1'
[21:19:18.613915] [dll] load: couldn't open `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_gdi_a3.so.1' (No such file or directory)
[21:19:18.614253] [dll] load: trying to load `/usr/lib/sane/libsane-kyocera_gdi_a3.so.1'
[21:19:18.614459] [dll] load: couldn't open `/usr/lib/sane/libsane-kyocera_gdi_a3.so.1' (No such file or directory)
[21:19:18.614820] [dll] load: trying to load `/usr/lib64/sane/libsane-kyocera_gdi_a3.so.1'
[21:19:18.615184] [dll] load: couldn't open `/usr/lib64/sane/libsane-kyocera_gdi_a3.so.1' (No such file or directory)
[21:19:18.615508] [dll] load: couldn't find backend `kyocera_gdi_a3' (No such file or directory)
[21:19:18.615646] [dll] load: searching backend `kyocera' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:19:18.616001] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera.so.1'
[21:19:18.616407] [dll] load: couldn't open `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera.so.1' (No such file or directory)
[21:19:18.616737] [dll] load: trying to load `/usr/lib/sane/libsane-kyocera.so.1'
[21:19:18.616930] [dll] load: couldn't open `/usr/lib/sane/libsane-kyocera.so.1' (No such file or directory)
[21:19:18.617314] [dll] load: trying to load `/usr/lib64/sane/libsane-kyocera.so.1'
[21:19:18.617598] [dll] load: couldn't open `/usr/lib64/sane/libsane-kyocera.so.1' (No such file or directory)
[21:19:18.617856] [dll] load: couldn't find backend `kyocera' (No such file or directory)

Ну хорошо, первое препятствие — библиотеки бэкендов kyocera и kyocera_gdi_a3 не обнаружены ни в одной из /usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane директорий. Довольно странно, так как эти файлы есть.

ls /usr/lib/sane/libsane-kyocera* -lah

lrwxrwxrwx 1 root root   32 мар 27  2020 /usr/lib/sane/libsane-kyocera_gdi_a3.so.1 -> libsane-kyocera_gdi_a3.so.1.0.24
lrwxrwxrwx 1 root root   25 мар 27  2020 /usr/lib/sane/libsane-kyocera.so.1 -> libsane-kyocera.so.1.0.24
-rw-r--r-- 1 root root 1,1K мар 27  2020 /usr/lib/sane/libsane-kyocera_wc3.la
lrwxrwxrwx 1 root root   29 мар 27  2020 /usr/lib/sane/libsane-kyocera_wc3.so.1 -> libsane-kyocera_wc3.so.1.0.24
-rw-r--r-- 1 root root 170K мар 27  2020 /usr/lib/sane/libsane-kyocera_wc3.so.1.0.24
-rw-r--r-- 1 root root 1,1K мар 27  2020 /usr/lib/sane/libsane-kyocera_wc3_usb.la
lrwxrwxrwx 1 root root   33 мар 27  2020 /usr/lib/sane/libsane-kyocera_wc3_usb.so.1 -> libsane-kyocera_wc3_usb.so.1.0.24
-rw-r--r-- 1 root root 552K мар 27  2020 /usr/lib/sane/libsane-kyocera_wc3_usb.so.1.0.24

Да, есть. Но только это лишь символьные ссылки на отсутствующие файлы. Похоже, производитель забыл приложить их в пакет. Бывает.

Попробуем заглянуть в другую, более раннюю версию — kyocera-sane_2.0.1923_amd64.deb.

dpkg -X kyocera-sane_2.0.1923_amd64.deb kyocera && tree kyocera -L 5 -h

<...>
    │   ├── [4.0K]  sane
    │   │   ├── [1.1K]  libsane-kyocera_gdi_a3.la
    │   │   ├── [  32]  libsane-kyocera_gdi_a3.so.1 -> libsane-kyocera_gdi_a3.so.1.0.24
    │   │   ├── [554K]  libsane-kyocera_gdi_a3.so.1.0.24
    │   │   ├── [1.0K]  libsane-kyocera.la
    │   │   ├── [  25]  libsane-kyocera.so.1 -> libsane-kyocera.so.1.0.24
    │   │   ├── [535K]  libsane-kyocera.so.1.0.24
    │   │   ├── [1.1K]  libsane-kyocera_wc3.la
    │   │   ├── [  29]  libsane-kyocera_wc3.so.1 -> libsane-kyocera_wc3.so.1.0.24
    │   │   ├── [182K]  libsane-kyocera_wc3.so.1.0.24
    │   │   ├── [1.0K]  libsane-kyocera_wc3_usb.la
    │   │   ├── [  33]  libsane-kyocera_wc3_usb.so.1 -> libsane-kyocera_wc3_usb.so.1.0.24
    │   │   └── [620K]  libsane-kyocera_wc3_usb.so.1.0.24
    │   └── [4.0K]  x86_64-linux-gnu
    │       └── [4.0K]  sane
    │           ├── [1.1K]  libsane-kyocera_gdi_a3.la
    │           ├── [  32]  libsane-kyocera_gdi_a3.so.1 -> libsane-kyocera_gdi_a3.so.1.0.24
    │           ├── [554K]  libsane-kyocera_gdi_a3.so.1.0.24
    │           ├── [1.0K]  libsane-kyocera.la
    │           ├── [  25]  libsane-kyocera.so.1 -> libsane-kyocera.so.1.0.24
    │           ├── [535K]  libsane-kyocera.so.1.0.24
    │           ├── [1.1K]  libsane-kyocera_wc3.la
    │           ├── [  29]  libsane-kyocera_wc3.so.1 -> libsane-kyocera_wc3.so.1.0.24
    │           ├── [182K]  libsane-kyocera_wc3.so.1.0.24
    │           ├── [1.0K]  libsane-kyocera_wc3_usb.la
    │           ├── [  33]  libsane-kyocera_wc3_usb.so.1 -> libsane-kyocera_wc3_usb.so.1.0.24
    │           └── [620K]  libsane-kyocera_wc3_usb.so.1.0.24
<...>

Отлично, в этом пакете с файлами порядок. Устанавливаем и проверяем:

SANE_DEBUG_DLL=4 scanimage -L

<...>
[21:48:15.283818] [dll] add_backend: adding backend `kyocera'
[21:48:15.284099] [dll] add_backend: adding backend `kyocera_gdi_a3'
[21:48:15.284232] [dll] add_backend: adding backend `kyocera_wc3'
[21:48:15.284375] [dll] add_backend: adding backend `kyocera_wc3_usb'
[21:48:15.284571] [dll] sane_get_devices
[21:48:15.284650] [dll] load: searching backend `kyocera_wc3_usb' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:48:15.284747] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3_usb.so.1'
[21:48:15.284956] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3_usb.so.1'
[21:48:15.289141] [dll] init: initializing backend `kyocera_wc3_usb'
[21:48:15.315257] [dll] init: backend `kyocera_wc3_usb' is version 1.0.1
[21:48:15.315786] [dll] load: searching backend `kyocera_wc3' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:48:15.316111] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3.so.1'
[21:48:15.316344] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3.so.1'
[21:48:15.333840] [dll] init: initializing backend `kyocera_wc3'
[21:48:15.334047] [dll] init: backend `kyocera_wc3' is version 1.0.1
[21:48:15.341101] [dll] load: searching backend `kyocera_gdi_a3' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:48:15.341290] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_gdi_a3.so.1'
[21:48:15.341501] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_gdi_a3.so.1'
[21:48:15.351770] [dll] init: initializing backend `kyocera_gdi_a3'
[21:48:15.375142] [dll] init: backend `kyocera_gdi_a3' is version 1.0.1
[21:48:15.375506] [dll] load: searching backend `kyocera' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/sane'
[21:48:15.375694] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera.so.1'
[21:48:15.376024] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera.so.1'
[21:48:15.376814] [dll] init: initializing backend `kyocera'
[21:48:15.394530] [dll] init: backend `kyocera' is version 1.0.1
...
[kyocera] softconnect_scanner() : INFO : connecting usb scanner device libusb:001:002
[kyocera] attach_one() : vendor 0x482, product 0x3c5
Ошибка сегментирования

Идеально, все четыре бэкенда загрузились (initializing backend) без проблем. Но на бэкенде kyocera программа завершила выполнение с ошибкой сегментирования.

Познакомившись с бэкендами kyocera ближе, рассмотрев содержимое всех конфигурационных файлов, удалось выяснить:

  • бэкенд kyocera предназначен для устройств, подключенных по USB. В списке содержатся уж очень старые модели. Сравним эти конфигурационные файлы между первой версией kyocera-sane_1.1.0228 и текущей kyocera-sane_2.1.4406.

kyocera-sane_2.1.4406_kyocera.conf
#Kyocera MFP supported device

# FS-1020 MFP
usb 0x0482 0x0495
# FS-1120 MFP
usb 0x0482 0x0496
# FS-1025 MFP
usb 0x0482 0x0497
# FS-1125 MFP
usb 0x0482 0x0498
# FS-1220 MFP
usb 0x0482 0x04FD
# FS-1320 MFP
usb 0x0482 0x04FE
# FS-1325 MFP
usb 0x0482 0x04FF
# ECOSYS M1025d/PN
usb 0x0482 0x06CE
# ECOSYS M1520h
usb 0x0482 0x06CF
usb 0x0482 0x0d50
usb 0x0482 0x0d51
usb 0x0482 0x0d81
usb 0x0482 0x0d82

kyocera-sane_1.1.0228_kyocera.conf
#Kyocera MFP supported device

# FS-1020 MFP
usb 0x0482 0x0495
# FS-1120 MFP
usb 0x0482 0x0496
# FS-1025 MFP
usb 0x0482 0x0497
# FS-1125 MFP
usb 0x0482 0x0498
# FS-1220 MFP
usb 0x0482 0x04FD
# FS-1320 MFP
usb 0x0482 0x04FE
# FS-1325 MFP
usb 0x0482 0x04FF

Список поддерживаемых моделей пополнился ECOSYS M1025d/PN, ECOSYS M1520h и ещё четырьмя безымянными. Идентификаторы, возможно, принадлежат ещё не анонсированным моделям.

  • kyocera_gdi_a3  бэкенд для линейки TASKAlfa.

  • kyocera_wc3_usb —бэкенд для всех остальных моделей, работающих по USB-интерфейсу. Попробуем добавить запись о нашем устройстве в секцию МФУ-родственников

/etc/sane.d/kyocera_wc3_usb.conf

<...>
# --- Discovery30/35
### KDC
# FS-1030MFP
usb 0x0482 0x0483
# FS-1130MFP
usb 0x0482 0x0484
# FS-1035MFP
usb 0x0482 0x0485
# FS-1135MFP
usb 0x0482 0x0486
# LS-1035MFP
usb 0x0482 0x0499
# LS-1135MFP
usb 0x0482 0x049a
#FS-1028 MFP
usb 0x0482 0x03C5
<...>

и повторить поиск.

scanimage -L

[14:01:26.757918] [dll] sane_get_devices
[14:01:26.758164] [dll] load: searching backend `kyocera_wc3_usb' in `/usr/lib/x86_64-linux-gnu/sane:/usr/lib/sane:/usr/lib64/
[14:01:26.758623] [dll] load: trying to load `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3_usb.so.1'
[14:01:26.759013] [dll] load: dlopen()ing `/usr/lib/x86_64-linux-gnu/sane/libsane-kyocera_wc3_usb.so.1'
[14:01:26.763067] [dll] init: initializing backend `kyocera_wc3_usb'
[14:01:26.792390] [dll] init: backend `kyocera_wc3_usb' is version 1.0.1
Ошибка сегментирования

Увы. Результат отрицательный.

Вы будете абсолютно правы, посчитав, что подобные попытки сродни попаданию пальцем в небо. Если в коде отсутствуют строки, идентифицирующие каким-либо образом устройство (обычно это idVendor и idProduct), то и ожидать поддержки устройства со стороны такого кода не следует. Но кто знает, какую логику заложил в код драйвера разработчик! Драйвер закрытый, так просто посмотреть в исходники на GitHab не удастся.

Не опускаем руки

На самом деле, довольно сложно придумать способ идентификации, кроме как idVendor и idProduct. Для сканирующих устройств отсутствует класс (bDeviceClass) в спецификации USB. Но разработчики sane-find-scanner готовы с этим поспорить.

Но иногда добавляют уверенности комментарии самих разработчиков бэкенда, например, в epkowa.conf (epson).

# For any USB scanner not known to the backend (yet), you may, at your
# own peril(!!), force the backend to recognise and use it via libusb.
# You can do so by the following configuration command:

... но посмотреть одним глазком можно

Результаты gdb
Thread 1 "scanimage" received signal SIGSEGV, Segmentation fault.
__strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
120     ../sysdeps/x86_64/multiarch/../strlen.S: Нет такого файла или каталога.
(gdb) bt
#0  __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
#1  0x00007ffff7da0eee in __GI___strdup (s=0x0) at strdup.c:41
#2  0x00007ffff1865d0d in attach_one (connection_type=CONNECTION_TYPE_USB, device_name=0x492b00 "libusb:001:002") at kyocera.c:136
#3  attach_one_usb (device_name=0x492b00 "libusb:001:002") at kyocera.c:74
#4  0x00007ffff186c072 in kyocera_usb_find_devices (vendor=vendor@entry=1154, product=product@entry=965,
    attach=attach@entry=0x7ffff1865ba0 <attach_one_usb>) at kyocera_libusb.c:675
#5  0x00007ffff186c123 in kyocera_usb_attach_matching_devices (name=<optimized out>, attach=0x7ffff1865ba0 <attach_one_usb>)
    at kyocera_libusb.c:574
#6  0x00007ffff1866044 in sane_kyocera_get_devices (device_list_param=0x7fffffffc0a0, local=<optimized out>) at kyocera.c:1532
#7  0x00007ffff7f84d20 in sane_dll_get_devices () from /lib/x86_64-linux-gnu/libsane.so.1
#8  0x0000000000402867 in ?? ()
#9  0x00007ffff7d3d09b in __libc_start_main (main=0x402570, argc=4, argv=0x7fffffffe5e8, init=<optimized out>, fini=<optimized out>,
    rtld_fini=<optimized out>, stack_end=0x7fffffffe5d8) at ../csu/libc-start.c:308
#10 0x000000000040543a in ?? ()
(gdb) bt full
#0  __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:120
No locals.
#1  0x00007ffff7da0eee in __GI___strdup (s=0x0) at strdup.c:41
        len = <optimized out>
        new = <optimized out>
#2  0x00007ffff1865d0d in attach_one (connection_type=CONNECTION_TYPE_USB, device_name=0x492b00 "libusb:001:002") at kyocera.c:136
        status = SANE_STATUS_GOOD
        vendor = 1154
        product = 965
        model = <optimized out>
        i = <optimized out>
        scanner = 0x49e640
        status = <optimized out>
        scanner = <optimized out>
        vendor = <optimized out>
        product = <optimized out>
        model = <optimized out>
        i = <optimized out>
#3  attach_one_usb (device_name=0x492b00 "libusb:001:002") at kyocera.c:74
No locals.
#4  0x00007ffff186c072 in kyocera_usb_find_devices (vendor=vendor@entry=1154, product=product@entry=965,
    attach=attach@entry=0x7ffff1865ba0 <attach_one_usb>) at kyocera_libusb.c:675
        dn = 0
#5  0x00007ffff186c123 in kyocera_usb_attach_matching_devices (name=<optimized out>, attach=0x7ffff1865ba0 <attach_one_usb>)
    at kyocera_libusb.c:574
        vendorID = 1154
        productID = 965
        vendor = 0x49d390 "Kyocera"
        product = 0x49d390 "Kyocera"
#6  0x00007ffff1866044 in sane_kyocera_get_devices (device_list_param=0x7fffffffc0a0, local=<optimized out>) at kyocera.c:1532
        scanner = 0x0
        fp = 0x4a7cf0
        line = "usb 0x0482 0x03c5000000ed device000000b00000000000000b", '00' <repeats 15 times>, "`3673543673771770000hr000000000000365(23036737717700000000000000000000365(2303673771770000202663773773771770000370(2303673771770000P2673773773771770000W(2303673771770000`033553673771770000Hi33136737717700000000000000000000`26637737737717700000003000000000000p2663773773771770000`2663773773771770000-000000000000003602673773773771770000"...
        lp = 0x7fffffffb010 "usb 0x0482 0x03c5"
        i = 0
        vendor = 1154
        product = 965
        scanner_count = 0
#7  0x00007ffff7f84d20 in sane_dll_get_devices () from /lib/x86_64-linux-gnu/libsane.so.1
No symbol table info available.
#8  0x0000000000402867 in ?? ()
No symbol table info available.
#9  0x00007ffff7d3d09b in __libc_start_main (main=0x402570, argc=4, argv=0x7fffffffe5e8, init=<optimized out>, fini=<optimized out>,
    rtld_fini=<optimized out>, stack_end=0x7fffffffe5d8) at ../csu/libc-start.c:308
        self = <optimized out>
        result = <optimized out>
        unwind_buf = {cancel_jmp_buf = {{jmp_buf = {0, 92955761157321657, 4215824, 140737488348640, 0, 0, -92955207220350023,
                -92937443612970055}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x7fffffffe610, 0x7ffff7ffe190}, data = {prev = 0x0,
              cleanup = 0x0, canceltype = -6640}}}
        not_first_call = <optimized out>
#10 0x000000000040543a in ?? ()

  • kyocera_wc3  сетевой бэкенд для всех моделей, а kyocera_devices.conf является его вспомогательным файлом, из которого считываются данные об устройствах. Это можно увидеть в выводе отладочной информации SANE_DEBUG_KYOCERA_WC3=255.

SANE_DEBUG_KYOCERA_WC3=255 scanimage -L

[kyocera_debug] Setting debug level of kyocera_wc3 to 255.
[kyocera_wc3] >>sane_init
[kyocera_wc3] sane_init() : Kyocera backend (build 1), version != null, authorize != null
[kyocera_wc3] <<sane_init
[kyocera_wc3] >>sane_get_devices
[kyocera_wc3] discover_device()
[kyocera_wc3] get_ip_address()
[kyocera_wc3] INTERFACE NAME: eth0
[kyocera_wc3] IP ADDRESS: 10.0.0.20
[kyocera_wc3] req->myInterface: 10.0.0.20
[kyocera_wc3] KMCMNDV_DiscoverDevice = -1 Number of devices found = 0
[kyocera_wc3] sane_get_devices() : start reading config file kyocera_devices.conf
[kyocera_wc3] sane_get_devices() : finished reading config file kyocera_devices.conf
[kyocera_wc3] sane_get_devices() : Kyocera scanners found 0
[kyocera_wc3] <<sane_get_devices
<...>

А вот для сетевого бэкенда такой трюк сработает. Добавим информацию об устройстве в принятом в файле формате

/etc/sane.d/kyocera_wc3.conf

echo -e "A4 FS-1028MFP" | sudo tee -a /etc/sane.d/kyocera_wc3.conf

и попытаемся найти устройство...

sudo SANE_DEBUG_KYOCERA_WC3=255 scanimage -L

<...>
[kyocera_wc3] sane_get_devices() : start reading config file kyocera_devices.conf
[kyocera_wc3] sane_get_devices() : finished reading config file kyocera_devices.conf
[kyocera_wc3] sane_get_devices() : Kyocera scanners found 0
[kyocera_wc3] <<sane_get_devices

... не найдено. Обратите внимание на строку "finished reading config file kyocera_devices.conf". Бэкенд kyocera_wc3 считывает с него данные о сетевых устройствах, несмотря на то, что в самом kyocera_wc3.conf перечислены все сетевые модели устройств. Попробуем добавить в kyocera_devices.conf данные об IP-адресе и модели.

/etc/sane.d/kyocera_devices.conf

# ------------- Add devices here -------------
10.0.0.49 FS-1028MFP
 
# ------- List of supported devices ----------

Повторяем поиск.

<...>
[kyocera_debug] Setting debug level of kyocera_wc3 to 255.
[kyocera_wc3] >>sane_init
[kyocera_wc3] sane_init() : Kyocera backend (build 1), version != null, authorize != null
[kyocera_wc3] <<sane_init
[kyocera_wc3] >>sane_get_devices
[kyocera_wc3] discover_device()
[kyocera_wc3] get_ip_address()
[kyocera_wc3] INTERFACE NAME: eth0
[kyocera_wc3] IP ADDRESS: 10.0.12.22
[kyocera_wc3] req->myInterface: 10.0.12.22
[kyocera_wc3] KMCMNDV_DiscoverDevice = -1 Number of devices found = 0
[kyocera_wc3] sane_get_devices() : start reading config file kyocera_devices.conf
[kyocera_wc3] sane_get_devices() : string: 10.0.0.49 FS-1028MFP
[kyocera_wc3] sane_get_devices() : ip_add_or_hostname: 10.0.0.49
[kyocera_wc3] sane_get_devices() : device_name: FS-1028MFP
[kyocera_wc3] sane_get_devices() : start reading config file kyocera_wc3.conf
[kyocera_wc3] sane_get_devices() : string: A4 FS-1028MFP
[kyocera_wc3] sane_get_devices() : type: A4
[kyocera_wc3] sane_get_devices() : conf_name: FS-1028MFP
[kyocera_wc3] sane_get_devices() : FS-1028MFP == FS-1028MFP
[kyocera_wc3] attach_one()
[kyocera_wc3] sane_get_devices() : finished reading config file kyocera_devices.conf
[kyocera_wc3] sane_get_devices() : found Kyocera scanner in 10.0.0.49
[kyocera_wc3] sane_get_devices() : Kyocera scanners found 1
[kyocera_wc3] <<sane_get_devices
device `kyocera_wc3:10.0.0.49' is a Kyocera FS-1028MFP A4
[kyocera_wc3] >>sane_exit

Бинго! Устройство успешно обнаружено. Пробуем выполнить тест устройства.

scanimage -T

Output format is not set, using pnm as a default.
TIFFReadDirectory: Warning, Unknown field with tag 292 (0x124) encountered.
scanimage: scanning image of size 1653x2338 pixels at 1 bits/pixel
scanimage: acquiring gray frame, 1 bits/sample
scanimage: reading one scanline, 207 bytes...   PASS
scanimage: reading one byte...          Ошибка сегментирования (стек памяти сброшен на диск)

Любопытная реакция. Мало того что программа завершилась сбоем, так и дальнейшие попытки выполнить сканирование в файл приводили к ошибкам "Error during device I/O"

scanimage -d 'kyocera_wc3:10.0.0.49' --batch='scan.jpeg'
Output format is not set, using pnm as a default.
Scanning infinity pages, incrementing by 1, numbering from 1
Scanning page 1
scanimage: sane_start: Error during device I/O
Batch terminated, 0 pages scanned

Судя по сообщению на дисплее, устройство находилось в режиме «Дистанционная передача». Вероятно, режим тестирования -T функцией sane_read() завершился неудачно. Дальнейшая работа устройства была без сбоев.

Возможности драйвера kyocera_wc3:

scanimage -A
Options specific to device `kyocera_wc3:10.0.0.49':
    --source Auto|DP|Platen|2-sided (Binding Top)|2-sided (Binding Left/Right) [Auto]
        Selects the scan source (such as a document-feeder).
    --mode Mono|Gray|Color [Mono]
        Selects the scan mode (e.g., lineart, monochrome, or color).
    --resolution 200|300|400|600dpi [200]
        Sets the resolution of the scanned image.
  :
    --orientation Portrait(Top Edge Left)|Landscape(Top Edge Top) [Portrait(Top Edge Left)]
        Sets the Orientation for the image
    --originalSize A4|A5|A6|B5(JIS)|B6|Letter|Legal [A4]
        Determines the size of the original
    --sendingSize Auto|A4|A5|A6|B5(JIS)|B6|Letter|Legal [Auto]
        Determines the limit for the data size when the scanned image is
        transmitted
    --imageQuality Text+Photo|Text|Photo [Text+Photo]
        Determines scan quality according to the typical content of the
        original document
    --densityType Manual|Auto [Manual]
        Selects the density of scanned images
    --density -3..3 (in steps of 1) [0]
        Selects the density of scanned images
    --contrast -3..3 (in steps of 1) [0]
        Selects the contrast of scanned images

Функционал достаточно серьезный. Выполним серию тестов для проверки сканирования через различные источники подачи бумаги, а также цветность и разрешение.

Результаты тестирования с различными параметрами
scanimage -d 'kyocera_wc3:10.0.0.49' --batch='scan.jpeg'
Output format is not set, using pnm as a default.
Scanning infinity pages, incrementing by 1, numbering from 1
Scanning page 1
TIFFReadDirectory: Warning, Unknown field with tag 292 (0x124) encountered.
Scanned page 1. (scanner status = 5)
Scanning page 2
scanimage: sane_start: Document feeder out of documents
Batch terminated, 1 page scanned
scanimage -d 'kyocera_wc3:10.0.0.49' --batch='scan.jpeg' --resolution 600
Output format is not set, using pnm as a default.
Scanning infinity pages, incrementing by 1, numbering from 1
Scanning page 1
TIFFReadDirectory: Warning, Unknown field with tag 292 (0x124) encountered.
Scanned page 1. (scanner status = 5)
Scanning page 2
scanimage: sane_start: Document feeder out of documents
Batch terminated, 1 page scanned
scanimage -d 'kyocera_wc3:10.0.0.49' --batch='scan.jpeg' --resolution 600 --source DP
Output format is not set, using pnm as a default.
Scanning infinity pages, incrementing by 1, numbering from 1
Scanning page 1
TIFFReadDirectory: Warning, Unknown field with tag 292 (0x124) encountered.
Scanned page 1. (scanner status = 5)
Scanning page 2
TIFFReadDirectory: Warning, Unknown field with tag 292 (0x124) encountered.
Scanned page 2. (scanner status = 5)
Scanning page 3
TIFFReadDirectory: Warning, Unknown field with tag 292 (0x124) encountered.
Scanned page 3. (scanner status = 5)
Scanning page 4
scanimage: sane_start: Document feeder out of documents
Batch terminated, 3 pages scanned

Все операции сканирования завершились успехом.

Пример с сетевым бэкендом продемонстрировал универсальную поддержку сетевых устройств на уровне протокола WSD (kyocera_wc3). По каким-то причинам производитель не добавил модель в конфигурационный файл.

Дальнейшие поиски в коде sane привели к бэкенду avision [37]. В нем указана нетестированная модель Kyocera FS-1016MFP, чей idProduct 0x0482 0x0335 очень близок к целевому 0x0482 0x03C5. Конкретно в этом случае просто дописать в конфигурационный файл /etc/sane.d/avision.conf строку "usb 0x0482 0x03C5" действительно бессмысленно, так как в открытом исходном коде прописано каждое поддерживаемое устройство:

https://gitlab.com/sane-project/backends/-/blob/master/backend/avision.c#L1513

<...>
{ NULL, NULL,
      0x0482, 0x0335,
      "Kyocera", "FS-1016MFP",
      0,
      { 0, {0, 0}, {{0, 0}, {0, 0}} }
    },
<...>

В таком случае попробуем внести изменения в исходный код файла backend/avision.с с информацией о новом устройстве Kyocera FS-1028MFP и скомпилировать код.

avision.с

<...>
{ NULL, NULL,
      0x0482, 0x03c5,
      "Kyocera", "FS-1028MFP",
      0,
      { 0, {0, 0}, {{0, 0}, {0, 0}} }
    },
<...>

Попытка поиска устройства с модифицированным бэкендом:

SANE_DEBUG_SANEI_USB=4 SANE_DEBUG_AVISION=255 scanimage -L
[19:09:41.975746] [avision] sane_reload_devices: config file line 23: trying to attach USB:`usb 0x0482 0x03c5'
[19:09:41.975943] [sanei_usb] sanei_usb_find_devices: vendor=0x0482, product=0x03c5
[19:09:41.976174] [avision] attach:
[19:09:41.976324] [avision] attach: opening libusb:002:005
[19:09:41.976980] [sanei_usb] sanei_usb_open: opened usb device `libusb:002:005' (*dn=0)
[19:09:41.977151] [avision] inquiry: length: 96
[19:09:41.977316] [avision] inquiry: inquiring ...
[19:09:41.977497] [avision] avision_cmd: Inquiry
[19:09:41.977675] [avision] filling command to have a length of 10, was: 6
[19:09:41.977855] [avision] Timeouts: write: 30000, read: 1000, status: 1000
[19:09:41.978031] [avision] try to write cmd, count: 10.
[19:09:41.978533] [avision] wrote 10 bytes
[19:09:41.978702] [avision] try to read 96 bytes
[19:09:42.983972] [sanei_usb] sanei_usb_read_bulk: read failed (still got 0 bytes): Operation timed out
[19:09:42.985401] [avision] read 0 bytes
[19:09:42.985648] [avision] No data arrived.
[19:09:42.985837] [avision] try to write cmd, count: 10.
[19:09:42.986540] [avision] wrote 10 bytes
[19:09:42.986767] [avision] try to read 96 bytes
[19:09:43.991964] [sanei_usb] sanei_usb_read_bulk: read failed (still got 0 bytes): Operation timed out
[19:09:43.993377] [avision] read 0 bytes
[19:09:43.993624] [avision] No data arrived.
[19:09:43.993811] [avision] try to write cmd, count: 10.
[19:09:43.994654] [avision] wrote 10 bytes
[19:09:43.994906] [avision] try to read 96 bytes
[19:09:45.000207] [sanei_usb] sanei_usb_read_bulk: read failed (still got 0 bytes): Operation timed out
[19:09:45.001619] [avision] read 0 bytes
[19:09:45.001867] [avision] No data arrived.
[19:09:45.002064] [avision] Max retry count reached: I/O error
[19:09:45.002197] [avision] inquiry: inquiry failed (Error during device I/O)
[19:09:45.002404] [avision] inquiry: inquiring ...
[19:09:45.002550] [avision] avision_cmd: Inquiry
[19:09:45.002705] [avision] filling command to have a length of 10, was: 6
[19:09:45.002829] [avision] Timeouts: write: 30000, read: 1000, status: 1000
[19:09:45.002995] [avision] try to write cmd, count: 10.
[19:09:45.004422] [avision] wrote 10 bytes
[19:09:45.004664] [avision] try to read 96 bytes
[19:09:46.010071] [sanei_usb] sanei_usb_read_bulk: read failed (still got 0 bytes): Operation timed out
[19:09:46.011492] [avision] read 0 bytes
[19:09:46.011739] [avision] No data arrived.
[19:09:46.011899] [avision] try to write cmd, count: 10.
[19:09:46.012771] [avision] wrote 10 bytes
[19:09:46.013046] [avision] try to read 96 bytes
[19:09:47.018434] [sanei_usb] sanei_usb_read_bulk: read failed (still got 0 bytes): Operation timed out
[19:09:47.019651] [avision] read 0 bytes
[19:09:47.019902] [avision] No data arrived.
[19:09:47.020056] [avision] try to write cmd, count: 10.
[19:09:47.020937] [avision] wrote 10 bytes
[19:09:47.021200] [avision] try to read 96 bytes
[19:09:48.026498] [sanei_usb] sanei_usb_read_bulk: read failed (still got 0 bytes): Operation timed out
[19:09:48.027763] [avision] read 0 bytes
[19:09:48.028014] [avision] No data arrived.
[19:09:48.028174] [avision] Max retry count reached: I/O error
[19:09:48.028328] [avision] inquiry: inquiry failed (Error during device I/O)
[19:09:48.028456] [avision] attach: 1st inquiry failed (Error during device I/O)

Идентификаторы успешно считаны, но, увы, на запрос хоста sanei_usb_read_bulk устройство не отвечает. Так выглядит попытка обмена данными в дампе.

sudo cat /sys/kernel/debug/usb/usbmon/2u
ffff8923d0e31f00 2904340585 S Bo:2:002:4 -115 10 = 12000000 60000000 0000
ffff8923d0e31f00 2904340693 C Bo:2:002:4 0 10 >
ffff8923d0e31f00 2904341424 S Bi:2:002:5 -115 96 <
ffff8923d0e31f00 2905346448 C Bi:2:002:5 -2 0
ffff8923cba86540 2905347519 S Co:2:002:0 s 02 01 0000 0085 0000 0
ffff8923cba86540 2905347946 C Co:2:002:0 0 0
ffff8923cba86540 2905348698 S Bo:2:002:4 -115 10 = 12000000 60000000 0000
ffff8923cba86540 2905349201 C Bo:2:002:4 0 10 >
ffff8923cba86540 2905349721 S Bi:2:002:5 -115 96 <
ffff8923cba86540 2906355601 C Bi:2:002:5 -2 0
ffff8923cba86540 2906356160 S Co:2:002:0 s 02 01 0000 0085 0000 0
ffff8923cba86540 2906356949 C Co:2:002:0 0 0
ffff8923cba86540 2906358536 S Bo:2:002:4 -115 10 = 12000000 60000000 0000
ffff8923cba86540 2906358985 C Bo:2:002:4 0 10 >
ffff8923cba86540 2906359643 S Bi:2:002:5 -115 96 <
ffff8923cba86540 2907366077 C Bi:2:002:5 -2 0
ffff8923cba86540 2907366629 S Co:2:002:0 s 02 01 0000 0085 0000 0
ffff8923cba86540 2907367470 C Co:2:002:0 0 0
ffff8923cba86540 2907372159 S Bo:2:002:4 -115 10 = 12000000 60000000 0000
ffff8923cba86540 2907372424 C Bo:2:002:4 0 10 >
ffff8923d0e31e40 2907373630 S Bi:2:002:5 -115 96 <
ffff8923d0e31e40 2908378708 C Bi:2:002:5 -2 0
ffff8923d0e31e40 2908379164 S Co:2:002:0 s 02 01 0000 0085 0000 0
ffff8923d0e31e40 2908380045 C Co:2:002:0 0 0
ffff8923d0e31e40 2908380797 S Bo:2:002:4 -115 10 = 12000000 60000000 0000
ffff8923d0e31e40 2908381300 C Bo:2:002:4 0 10 >
ffff8923d0e31e40 2908382226 S Bi:2:002:5 -115 96 <
ffff8923d0e31e40 2909387324 C Bi:2:002:5 -2 0
ffff8923d0e31e40 2909387782 S Co:2:002:0 s 02 01 0000 0085 0000 0
ffff8923d0e31e40 2909388736 C Co:2:002:0 0 0
ffff8923cba86600 2909390036 S Bo:2:002:4 -115 10 = 12000000 60000000 0000
ffff8923cba86600 2909390660 C Bo:2:002:4 0 10 >
ffff8923cba86600 2909391611 S Bi:2:002:5 -115 96 <
ffff8923cba86600 2910397440 C Bi:2:002:5 -2 0
ffff8923d0e319c0 2910397954 S Co:2:002:0 s 02 01 0000 0085 0000 0
ffff8923d0e319c0 2910398834 C Co:2:002:0 0 0
ffff8923d0212240 2914678081 S Ci:2:002:0 s 80 06 0100 0000 0028 40 <
ffff8923d0212240 2914678747 C Ci:2:002:0 0 18 = 12010002 00000040 8204c503 00000102 0301
ffff8923d0212240 2914679123 S Ci:2:001:0 s 80 06 0100 0000 0028 40 <
ffff8923d0212240 2914679185 C Ci:2:001:0 0 18 = 12010002 09000040 6b1d0200 15050302 0101

Хост отправляет данные на EP 4 (OUT) и получает ответ [16] от EP 5 (IN) "-2 (No such file or directory -ENOENT)". Фрагмент дескрипторов с EP Kyocera FS-1028MFP.

Kyocera FS-1028MFP EP Descriptors
<...>
Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x04  EP 4 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x85  EP 5 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
<...>

Интересно было бы взглянуть на образцовый обмен данными от Kyocera FS-1016MFP, чтобы разобраться, что здесь не так. Устройство ждет своего часа для дальнейших изысканий.

На фоне этой неудачи успешные попытки "завести" новое устройство все же попадаются. Для Canon imageRUNNER 1133A отсутствует поддержка со стороны бэкенда pixma [38]. Но есть упоминание схожей модели — Canon imageRUNNER 1133 (отсутствует литера А, без АПД). На это обратил внимание пользователь Mikhail Remnev и создал issue [39]. Фактически, добавление одной строки в код backend/pixma/pixma_imageclass.c

https://gitlab.com/sane-project/backends/-/merge_requests/658/diffs#diff-content-ef420c6e0aefd96917d0ecb217b8a61d7efa1b8d

  DEV ("Canon i-SENSYS MF5880dn", "MF5880", MF5880_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP),
  DEV ("Canon i-SENSYS MF6680dn", "MF6680", MF6680_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP),
  DEV ("Canon imageRUNNER 1133", "iR1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP),                  /* max. w = 216mm */
+  DEV ("Canon imageRUNNER 1133A", "imageRUNNER1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP),        /* max. w = 216mm */
  DEV ("Canon i-SENSYS MF5900 Series", "MF5900", MF5900_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
  DEV ("Canon i-SENSYS MF8500C Series", "MF8500C", MF8500_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP),
  DEV ("Canon i-SENSYS MF6100 Series", "MF6100", MF6100_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP),

решило проблему с поддержкой устройства. Вот она, сила сообщества в действии.

"Здорово, замечательно", — скажете вы. Всё это, конечно, очень интересно, но как быть, если нет сил и специалистов, кто проделает всю работу по определению степени совместимости устройства и его функционала с ОС Astra Linux? Обильное количество топиков на тематических формах различных дистрибутивов не всегда даст полное представление о поддержке модели. С самым огромным списком открытых бэкендов можно ознакомиться на официальной странице [49] проекта SANE. А что для проприетарных? "Группа Астра" на этот случай разработала программу Ready for Astra [50]. Да, она не только для сканирующих устройств.

Ready for Astra

Пару слов о Ready for Astra — это программа технологического партнерства с разработчиками программного обеспечения и производителями оборудования. Цель программы – предоставить конечному пользователю экосистему совместимых решений с продуктами «Группы Астра», помочь выбрать оптимальное решение, чтобы быть уверенным в безопасности и корректном функционировании партнерских продуктов в среде ОС Astra Linux. В разделе «Совместимое оборудование» на сайте «Группы Астра» размещена информация о 400+ сканирующих устройств [43].

В том же разделе сайта можно найти сертификат совместимости и протокол испытаний. Сертификат совместимости подтверждает работоспособность и корректность совместного функционирования продукта технологического партнера и операционной системы.

У разных устройств есть свои особенности функционирования. Поэтому, выбирая решение, важно помимо сертификата изучать и протокол испытаний – это неотъемлемая часть сертификата совместимости. В нем фиксируется информация о предмете и объекте испытаний, описывается ход испытаний, конфигурация объекта испытаний и тестового стенда, перечень проверок и их результат.

Итог испытаний: подтверждение полной совместимости устройства или совместимости с ограничениями. Вся описанная в статье работа уже проделана нашими инженерами. Риск приобрести современное устройство, не поддерживаемое со стороны ОС, сводится к минимуму.


В этой главе мы рассмотрели процесс работы подсистемы udev, узнали, как устройству назначается модуль (помним, для сканеров не модуль) ядра. Описанных приемов работы с udevadm будет достаточно для диагностики проблем с отработкой правил и конфигурирования устройств. Не только сканирующих, но и любых других, подключаемых по USB. Использование scanimage описано только со стороны поиска и тестирования устройств для первоначальной подготовки их к работе. Строго говоря, scanimage из состава пакета sane-utils заслуживает большего внимания с точки зрения примеров его использования для повседневных задач.

Предоставлены основные приемы включения отладочной информации как на открытых, так и на некоторых проприетарных бэкендах.

Камлание с добавлением idVendor и idProduct неподдерживаемого устройства описаны для наглядной демонстрации логики работы бэкенда. Как вы сами увидели, это не дает 100%-й результат.

В третьей части мы расскажем о приемах ускорения поиска устройств и поделимся лучшими практиками использования программ SANE.

Автор: ddtpv

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js