CAPS Universe documentation  1.0.4
All you need to know to be successful
USB Printer Driver Start

Everything starts when the device occurs in the system. The Linux kernel creates a uevent, processed by the udev daemon. When a udev rule matches it will be processed. For all kind of USB based printers the CAPS Printing System Integration brings in a generic udev rule (99-caps.rules).

This rule triggers a generic systemd service template unit which finally launches the printer device's corresponding printer driver.

Troubleshooting

Linux Kernel

Attaching the printer looks like this:

$ dmesg -w
usb 1-2.5: new full-speed USB device number 19 using xhci_hcd
usb 1-2.5: New USB device found, idVendor=04e8, idProduct=3292, bcdDevice= 1.00
usb 1-2.5: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-2.5: Product: ML-1640 Series
usb 1-2.5: Manufacturer: Samsung Electronics Co., Ltd.
usb 1-2.5: SerialNumber: 144QBAHS302014M.
usblp 1-2.5:1.0: usblp0: USB Bidirectional printer dev 19 if 0 alt 0 proto 2 vid 0x04E8 pid 0x3292

Reasons why it could fail:

  • no Linux kernel USB support?
  • no Linux kernel USB printer support?
  • USB cable broken?
  • USB port disabled or protected?

uevent

Creating the uevent looks like this:

$ udevadm udevadm monitor -p
[…]
KERNEL[47827.830999] add      /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5 (usb)
[…]

KERNEL[47827.844576] add      /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0 (usb)
[…]

KERNEL[47827.858478] add      /class/usbmisc (class)
ACTION=add
DEVPATH=/class/usbmisc
SUBSYSTEM=class
SEQNUM=13644

KERNEL[47827.858570] add      /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0/usbmisc/lp0 (usbmisc)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0/usbmisc/lp0
SUBSYSTEM=usbmisc
DEVNAME=/dev/usb/lp0
SEQNUM=13645
MAJOR=180
MINOR=0

KERNEL[47827.858620] bind     /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0 (usb)
ACTION=bind
DEVPATH=/devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0
SUBSYSTEM=usb
DEVTYPE=usb_interface
DRIVER=usblp
PRODUCT=4e8/3292/100
TYPE=0/0/0
INTERFACE=7/1/2
MODALIAS=usb:v04E8p3292d0100dc00dsc00dp00ic07isc01ip02in00
SEQNUM=13646

KERNEL[47827.858673] bind     /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5 (usb)
[…]

UDEV  [47827.860270] add      /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5 (usb)
ACTION=add
DEVPATH=/devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5
SUBSYSTEM=usb
DEVNAME=/dev/bus/usb/001/018
DEVTYPE=usb_device
PRODUCT=4e8/3292/100
TYPE=0/0/0
BUSNUM=001
DEVNUM=018
SEQNUM=13642
USEC_INITIALIZED=47827860084
ID_VENDOR=Samsung_Electronics_Co.__Ltd.
ID_VENDOR_ENC=Samsung\x20Electronics\x20Co.\x2c\x20Ltd.
ID_VENDOR_ID=04e8
ID_MODEL=ML-1640_Series
ID_MODEL_ENC=ML-1640\x20Series
ID_MODEL_ID=3292
ID_REVISION=0100
ID_SERIAL=Samsung_Electronics_Co.__Ltd._ML-1640_Series_144QBAHS302014M.
ID_SERIAL_SHORT=144QBAHS302014M.
ID_BUS=usb
ID_USB_INTERFACES=:070102:
ID_VENDOR_FROM_DATABASE=Samsung Electronics Co., Ltd
ID_MODEL_FROM_DATABASE=ML-1640 Series Laser Printer
DRIVER=usb
ID_PATH=pci-0000:01:00.0-usb-0:2.5
ID_PATH_TAG=pci-0000_01_00_0-usb-0_2_5
SYSTEMD_WANTS=printer.target
SYSTEMD_USER_WANTS=printer.target
MAJOR=189
MINOR=17
TAGS=:systemd:

UDEV  [47827.860375] add      /class/usbmisc (class)
[…]

UDEV  [47827.865210] add      /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0 (usb)
[…]

UDEV  [47827.867705] add      /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0/usbmisc/lp0 (usbmisc)
[…]

UDEV  [47827.869857] bind     /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0 (usb)
[…]

UDEV  [47827.871738] bind     /devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5 (usb)
[…]
Note
This command produces a large amount of information. Thus, only the important information is shown here verbatim.

Reasons why it could fail:

  • never seen

udev daemon

The udev daemon must know our 99-caps.rules and must read it in. This can be checked with:

$ udevadm  test /sys/class/usbmisc/lp0
Reading rules file: /lib/udev/rules.d/39-usbmuxd.rules
Reading rules file: /lib/udev/rules.d/40-usb-media-players.rules
Reading rules file: /lib/udev/rules.d/40-vm-hotadd.rules
[…]
Reading rules file: /lib/udev/rules.d/99-caps.rules
Reading rules file: /lib/udev/rules.d/99-systemd.rules
[…]

If the 99-caps.rules is missing in the list, check if it is present in your system.

Reasons why it could fail:

  • 99-caps.rules wasn't installed to an expected location
  • after installation, the udev daemon wasn't restarted/reloaded
  • a different udev rule catches this uevent instead

To check if the 99-caps.rules is present, run:

$ pkg-config udev --variable=udevdir
/lib/udev

Thus, the 99-caps.rules file should be present in the /lib/udev/rules.d directory. Or in /etc/udev/rules.d. If it is present in one of these directories, we may need to reload the udev daemon to activate it.

$ sudo udevadm control --reload

After that, it should be read-in with the udevadm test command shown above.

CAPS printer template unit

The udev daemon should trigger the CAPS template unit, when a USB printer is attached to the system. Doing so should be look like that:

$ udevadm  test /sys/class/usbmisc/lp0
[…]
lp0: /lib/udev/rules.d/99-caps.rules:6 Running PROGRAM '/bin/systemd-escape -p --template=caps-printer@.service /dev/usb/lp0'
lp0: Starting '/bin/systemd-escape -p --template=caps-printer@.service /dev/usb/lp0'
Successfully forked off '(spawn)' as PID 210530.
lp0: '/bin/systemd-escape -p --template=caps-printer@.service /dev/usb/lp0'(out) 'caps-printer@dev-usb-lp0.service'
lp0: Process '/bin/systemd-escape -p --template=caps-printer@.service /dev/usb/lp0' succeeded.
lp0: Handling device node '/dev/usb/lp0', devnum=c180:0
lp0: Preserve permissions of /dev/usb/lp0, uid=0, gid=7, mode=0660
lp0: Preserve already existing symlink '/dev/char/180:0' to '../usb/lp0'
lp0: sd-device: Created db file '/run/udev/data/c180:0' for '/devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0/usbmisc/lp0'
DEVPATH=/devices/pci0000:00/0000:00:01.2/0000:01:00.0/usb1/1-2/1-2.5/1-2.5:1.0/usbmisc/lp0
DEVNAME=/dev/usb/lp0
MAJOR=180
MINOR=0
ACTION=add
SUBSYSTEM=usbmisc
TAGS=:systemd:
SYSTEMD_WANTS=caps-printer@dev-usb-lp0.service
USEC_INITIALIZED=101483726814

This only triggers the template unit. Further log you can found in the systemd journal:

$ journalctl -f
systemd[1]: Starting CAPS Printer Driver for /dev/usb/lp0...
[…]
systemd[1]: Started CAPS Printer Driver for /dev/usb/lp0.

Reasons why it could fail:

  • caps-printer@.service wasn't installed to an expected location
  • after installation, systemd hasn't reloaded the list of units

Check if the template unit file is known to systemd:

$ systemctl status caps-printer@/dev/usb/lp0.service
Invalid unit name "caps-printer@/dev/usb/lp0.service" escaped as "caps-printer@-dev-usb-lp0.service" (maybe you should use systemd-escap>
● caps-printer@-dev-usb-lp0.service - Printer Driver for //dev/usb/lp0
     Loaded: loaded (/lib/systemd/system/caps-printer@.service; static; vendor preset: enabled)
     Active: inactive (dead)
       Docs: https://flap.codeberg.page/caps-universe

If it isn't known, check if the template unit file is present:

$ pkg-config systemd --variable=systemdsystemunitdir
/lib/systemd/system

Thus, the caps-printer@.service file should be present in the /lib/systemd/system directory. Or in /etc/systemd/system. If it is present in one of these directories, we may need to reload the systemd daemon to activate it.

$ sudo systemctl daemon-reload

After that, it should be known with the systemctl status command shown above.

caps-printer-prep (CAPS printer driver preparation)

New printer device

$ journalctl -f
systemd[1]: Starting CAPS Printer Driver for /dev/usb/lp0...
caps-printer-prep[…]: Starting printer discovering process for device node '/dev/usb/lp0'...
caps-printer-prep[…]: Yet unknown USB printer device found at '/dev/usb/lp0'
caps-printer-prep[…]: New printer's run-time device parameter directory '/usr/local/var/lib/caps/printer_N4xoOY' created
caps-printer-prep[…]: Initial printer device's configuration 'printer_N4xoOY/service.ini' created
caps-printer-prep[…]: New printing device 'samsung-ml-1640-driver.ini' added as 'printer_N4xoOY' to the device database
systemd[1]: Started CAPS Printer Driver for /dev/usb/lp0.

Already known printer device

$ journalctl -f
systemd[1]: Starting CAPS Printer Driver for /dev/usb/lp0...
caps-printer-prep[…]: Starting printer discovering process for device node '/dev/usb/lp0'...
caps-printer-prep[…]: Printer device at '/dev/usb/lp0' is already known
systemd[1]: Started CAPS Printer Driver for /dev/usb/lp0.

caps-printer (CAPS printer driver launcher)

$ journalctl -f
[…]
caps-printer[…]: Launching printer driver '/usr/local/libexec/caps/caps-samsung-spl2'

CAPS Printer driver

$ journalctl -f
[…]
caps-samsung-spl2[…]: Detected printer model is: 'ML-1640'
caps-printing-coordinator[185914]: New printer 4290353918480799990 for provider d416393 created
caps-samsung-spl2[…]: Received Printer ID: 4290353918480799990
caps-samsung-spl2[…]: Driver is ready

In this case the capsprinter command line tool should now report:

$ capsprinter -v list
name: 'Samsung Electronics Co., Ltd._ML-1640 Series_144QBAHS302014M.'
 description: 'Samsung ML-1640 monochrome laser printer'
 location: 'Unknown location'
 state: Idle (ID 3)
 message: 'Idle'
Note
The name shown above is autogenerated, when this printer device was attached to the system the first time.
Refer User adaption how to adapt name and location to your needs.
Todo:
Give a hint, where to find the corresponding INI file to adapt these name and location settings.

After some time idling, the state of my printer device changes to:

$ capsprinter -v state
state: Idle (ID 3)
message: 'Power saving'