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:
- 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.
- 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.
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.
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.
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.