Guide v1.6 / Updated 2020-02-08 / First published 2020-02-07 / echo (at) screaming (dot) computer

I experienced many problems trying to access my thermal printer from my Linux VM running in UnRAID. After many diagnostics and lots of troubleshooting, I identified a two-part solution:

  1. Install a USB expansion card into the UnRAID server and pass it through for the exclusive use of the VM. This addresses low-level USB errors in the virtual machine.
  2. Install a generic CUPS driver and use the lp command to send data to the printer. This addresses the issue where usblp won't mount the device.

Thermal receipt printer

POS58 thermal receipt printer

This particular thermal printer is listed as:

Manufacturer=GD32 Microelectronics
Product=POS58 USB Printer
USB device: Winbond Electronics Corp. Virtual Com Port
Vendor & Product ID: 0416:5011

It's sold under the name “58MM USB Thermal Receipt Printer, Symcode” on Amazon.ca.

USB diagnostics in Linux

Some miscellaneous Linux commands which are helpful for diagnosing USB-connected devices:

lsusb
lsusb -v
ls -l /dev/usb
usb-devices
lspci | grep USB
dmesg

Failure part 1: libusb errors in UnRAID VM

With the thermal printer plugged into the UnRAID system (prior to adding the USB expansion card) and passed through to the VM, the VM system log showed the following errors when booting:

libusb: error [op_set_interface] setintf failed error -1 errno 110
libusb: error [op_clear_halt] clear_halt failed error -1 errno 71

Under lsusb it appeared as a Winbond Electronics Corp. Virtual Com Port, and running usb-devices showed the device as a POS58 USB Printer.

The printer appeared to be mounted correctly by the usblp kernel module at /dev/usb/lp0.

Inital attempts to access the printer failed due to lack of user permissions. The lp0 device was part of the lp usergroup, so I added my current user to that group:

sudo usermod -a -G lp $USER
sudo reboot

Even with correct permissions, sending data to the printer always failed with I/O errors:

echo "test" >> /dev/usb/lp0

bash: echo: write error: Input/output error

...and the VM system log showed this error:

libusb: error [submit_bulk_transfer] submiturb failed error -1 errno=2

Solution part 1: Add a USB expansion card dedicated for VM use

Install your USB expansion card and boot your UnRAID server.

PCIe USB expansion card

UnRAID [Tools] tab → [System Devices]

Find the PCI ID of your newly-installed card and save it for later use; it is in the form XXXX:XXXX, where the X's are hexadecimal digits. My expansion card appeared as:

IOMMU group 13: [1106:3483] 03:00.0 USB controller: VIA Technologies, Inc. VL805 USB 3.0 Host Controller (rev 01)

so the ID number is 1106:3483

WARNING: Do not get this ID number wrong. Be sure you have the ID of the correct device. Using the wrong ID in the following steps can cause serious issues for UnRAID. Editing the following settings can cause your UnRAID server to become unbootable. Proceed at your own discretion.

UnRAID [Main] tab → [Flash] device → [Syslinux Configuration] → click in the [unRAID OS] textbox

On the append line, add a vfio-pci.ids parameter with the ID of your USB expansion card; this causes UnRAID to avoid “claiming” this device on startup, allowing it to be passed through for the exclusive use of a VM.

After editing, my append line in the unRAID OS section looked as follows:

append initrd=/bzroot vfio-pci.ids=1106:3483

[Apply], [Reboot] your UnRAID server

UnRAID [VMs] tab → (your VM) → [Edit]

USB Controller: 3.0 (qemu XHCI)
Other PCI Devices: [check the box for your expansion card]
[Update]

If you had previous USB devices passed-through to the VM which are no longer connected, you may receive this error: “internal error: unknown pci source type 'vendor'” — The easiest way to resolve this is to reconnect the USB devices, deselect them in the VM configuration, then remove the devices.

UnRAID [VMs] tab → (your VM) → [Start]
UnRAID [VMs] tab → (your VM) → [Logs]

Watch the log window for errors. Mine booted without issue.

Using VNC to access the VM, open a terminal. Run lsusb to observe your USB expansion card.

Successfully resolved: boot-time libusb errors. USB ports are now functioning correctly.

Failure part 2: usblp fails to mount the thermal printer device

Plug the thermal printer into the USB expansion card, run ls /dev/usb to see the mounted device (expecting lp0 or similar), then test the device while watching the log:

echo "test" >> /dev/usb/lp0

If your printer prints the word “test,” congratulations, it works!

Unfortunately this was unsuccessful for me. Running ls /dev/usb came up empty. Curiously, usblp was not mounting the printer now even though it did so prior to using the expansion card.

Running dmesg revealed the following error:

usblp: can't set desired altsetting 0 on interface 0

My expansion card appeared to be successfully configured, but this particular model of USB printer seems to behave in quirky or non-standards-compliant ways.

Others have observed similar issues with this model of printer:

It appears that usblp is failing to initialize and mount the printer.

(If, in your case, you see the device is mounted but it still generates I/O errors, look into blacklisting usblp and try the CUPS solution, below.)

Solution part 2: Install CUPS driver, use lp command to print

* Solution found in this AskUbuntu post: Print via terminal without usblp.

In the Linux Mint GUI, open [Start Menu] → [System] → [Printers] → [+Add]

In the list of [Devices] there was an entry for “Unknown (Printer),” described as “A printer connected to a USB port.” This was the thermal printer.

Devices: Unknown (Printer)
[Forward]

Select printer from database: yes
Makes: Generic
[Forward]

Models: Raw Queue
[Forward]

Printer Name: THERMALPRINTER
[Apply]

Open terminal, test the printer:

echo "test" | lp -d THERMALPRINTER

The printer successfully printed “test” for me.

Successful test of receipt printer

You can suppress the job ID messages on stdout using the -s option. See the lp man page for full lp command syntax.

Successfully resolved: Use a generic CUPS driver to access the USB printer, in situations where usblp fails to mount the device.