The problem of scanning using USB multi-function printers in Linux (continued)

My previous post discussed the inability of the Linux installation on my main laptop to use the scanner of my Canon PIXMA MP560 MFP (multi-function peripheral) when they are connected via USB. Linux sees the MP560 as a single USB device with multiple interfaces: Interface 0 (scanner), Interface 1 (printer) and Interface 2 (USB mass storage). The basic problem seems to be that the usb-storage driver — whether built into the kernel or as an external module — claims the USB device and blocks access by userspace’s libusb, which is what the SANE backend (‘pixma‘, in the case of the MP560) uses to access the USB device. However, scanning works fine when using a network connection instead of the USB connection.

Attempts such as unbinding the usb-storage driver from the USB device — either manually or using a UDEV rule — in order to try and allow libusb/SANE to access the scanner, did not solve the problem. Although I can scan by connecting to the MP560 via my home network, the inability of the OS to scan via the USB interface piqued my interest, so I continued my investigations and below I discuss my latest findings.

Disabling kernel auto-binding

I learned from the interesting blog post Controlling USB device access on Linux how to stop the kernel automatically binding a driver to a USB device in the first place, as distinct from unbinding a driver after the kernel has bound it to a device. I thought this approach could be used to stop the usb-storage driver from binding to the MP560 and thus allow libusb/SANE to access Interface 0. The method using sysfs to stop the kernel binding the driver is to disable kernel USB auto-probing before launching a scanner application, by using the following command:

# echo 0 > /sys/bus/usb/drivers_autoprobe

This did indeed stop the kernel from automatically binding USB drivers to USB devices, but unfortunately libusb/SANE would still not access the MP560 scanner via USB. When drivers_autoprobe contains zero, applications such as XSane can use the network-connected MP560 as before, but still hang if the USB-connected MP560 is selected.

Unloading the usb-storage module

According to various blog and forum posts, some people have been able to use MFP scanners via USB after manually unloading the usb-storage module. I decided to try this. As I had built the kernel with the usb-storage driver internally rather than an external module, I first had to rebuild the kernel with CONFIG_USB_STORAGE=m instead of CONFIG_USB_STORAGE=y. Then I unloaded manually the usb_storage module using the command ‘rmmod usb_storage‘ and launched a scanner application, but the application still hung.

Disabling the usb-storage driver using a ‘quirk’

Then I had a thought: Perhaps there is a kernel ‘quirk’ to disable the usb-storage driver from binding to a specific USB device. Indeed there is (see Kernel Parameters or /usr/src/linux-<version>/Documentation/kernel-parameters.txt).

If the usb-storage driver is built into the kernel (CONFIG_USB_STORAGE=y), I would need to add the following kernel boot parameter to the kernel boot line:

usb-storage.quirks=04a9:173e:i

’04a9′ is the Vendor ID and ‘173e’ is the Product ID of the MP560. The ‘i‘ stands for ‘ignore’.

If the usb-storage driver is built as a kernel module (CONFIG_USB_STORAGE=m), I would need to create a file with a name such as /etc/modprobe.d/usb-storage.conf containing the following line:

options usb-storage quirks=04a9:173e:i

So I set up the quirk. Upon rebooting my laptop, the dmesg command reported the following:

usb 1-1.2.2: new high-speed USB device number 8 using ehci-pci
usb 1-1.2.2: New USB device found, idVendor=04a9, idProduct=173e
usb 1-1.2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1.2.2: Product: MP560 series
usb 1-1.2.2: Manufacturer: Canon
usb 1-1.2.2: SerialNumber: 1653C4
usb-storage 1-1.2.2:1.2: USB Mass Storage device detected
usb-storage 1-1.2.2:1.2: device ignored

Notice the final line. The quirk does indeed cause the usb-storage driver to ignore the MP560.

The lsusb command still shows the device, which is a good sign:

# lsusb
Bus 002 Device 005: ID 0bc2:3300 Seagate RSS LLC
Bus 002 Device 004: ID 0411:01d9 BUFFALO INC. (formerly MelCo., Inc.)
Bus 002 Device 003: ID 05e3:0606 Genesys Logic, Inc. USB 2.0 Hub / D-Link DUB-H4 USB 2.0 Hub
Bus 002 Device 002: ID 8087:8000 Intel Corp.
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 006: ID 5986:055c Acer, Inc
Bus 001 Device 004: ID 8087:07dc Intel Corp.
Bus 001 Device 007: ID 0603:00f2 Novatek Microelectronics Corp. Keyboard (Labtec Ultra Flat Keyboard)
Bus 001 Device 008: ID 04a9:173e Canon, Inc. MP560
Bus 001 Device 005: ID 045e:00d1 Microsoft Corp. Optical Mouse with Tilt Wheel
Bus 001 Device 003: ID 05e3:0606 Genesys Logic, Inc. USB 2.0 Hub / D-Link DUB-H4 USB 2.0 Hub
Bus 001 Device 002: ID 8087:8008 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

# lsusb -t
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M
        |__ Port 2: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
            |__ Port 1: Dev 4, If 0, Class=Mass Storage, Driver=usb-storage, 480M
            |__ Port 3: Dev 5, If 0, Class=Mass Storage, Driver=usb-storage, 480M
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/6p, 480M
        |__ Port 2: Dev 3, If 0, Class=Hub, Driver=hub/4p, 480M
            |__ Port 1: Dev 5, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
            |__ Port 2: Dev 8, If 0, Class=Vendor Specific Class, Driver=usbfs, 480M
            |__ Port 2: Dev 8, If 1, Class=Printer, Driver=, 480M
            |__ Port 2: Dev 8, If 2, Class=Mass Storage, Driver=, 480M
            |__ Port 4: Dev 7, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M
            |__ Port 4: Dev 7, If 1, Class=Human Interface Device, Driver=usbhid, 1.5M
        |__ Port 3: Dev 4, If 0, Class=Wireless, Driver=btusb, 12M
        |__ Port 3: Dev 4, If 1, Class=Wireless, Driver=btusb, 12M
        |__ Port 4: Dev 6, If 0, Class=Video, Driver=uvcvideo, 480M
        |__ Port 4: Dev 6, If 1, Class=Video, Driver=uvcvideo, 480M

The output of the lsusb -v -d 04a9:173e command applicable to the MP560 is as follows:

Bus 001 Device 008: ID 04a9:173e Canon, Inc. MP560
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x04a9 Canon, Inc.
  idProduct          0x173e MP560
  bcdDevice            0.04
  iManufacturer           1 Canon
  iProduct                2 MP560 series
  iSerial                 3 1653C4
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           85
    bNumInterfaces          3
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xc0
      Self Powered
    MaxPower                2mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           3
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass      0 
      bInterfaceProtocol    255 
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x07  EP 7 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     0x88  EP 8 IN
        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     0x89  EP 9 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval              11
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         7 Printer
      bInterfaceSubClass      1 Printer
      bInterfaceProtocol      2 Bidirectional
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 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     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk-Only
      iInterface              0 
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x84  EP 4 IN
        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     0x05  EP 5 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0200  1x 512 bytes
        bInterval               0
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  bNumConfigurations      1
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0001
  Self Powered

The USB device created at boot was as follows:

# ls -la /dev/bus/usb/001/008
crw-rw-r--+ 1 root lp 189, 7 Jul 24 11:01 /dev/bus/usb/001/008

Whether run by the root user or under my user account, the SANE tools detected the MP560 scanner network and USB connections:

$ scanimage -L
device `pixma:MP560_192.168.1.78' is a CANON Canon PIXMA MP560 multi-function peripheral
device `pixma:04A9173E' is a CANON Canon PIXMA MP560 multi-function peripheral

$ sane-find-scanner

  # sane-find-scanner will now attempt to detect your scanner. If the
  # result is different from what you expected, first make sure your
  # scanner is powered up and properly connected to your computer.

  # No SCSI scanners found. If you expected something different, make sure that
  # you have loaded a kernel SCSI driver for your SCSI adapter.

found USB scanner (vendor=0x04a9 [Canon], product=0x173e [MP560 series]) at libusb:001:008
  # Your USB scanner was (probably) detected. It may or may not be supported by
  # SANE. Try scanimage -L and read the backend's manpage.

  # Not checking for parallel port scanners.

  # Most Scanners connected to the parallel port or other proprietary ports
  # can't be detected by this program.

But scanner applications still hung! This time the message displayed by the dmesg command was:

usb 1-1.2.2: usbfs: interface 0 claimed by usbfs while 'scanimage' sets config #1

I unplugged the USB cable and plugged it in again. The output of the dmesg command was:

usb 1-1.2.2: USB disconnect, device number 8
usb 1-1.2.2: new high-speed USB device number 9 using ehci-pci
usb 1-1.2.2: New USB device found, idVendor=04a9, idProduct=173e
usb 1-1.2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1.2.2: Product: MP560 series
usb 1-1.2.2: Manufacturer: Canon
usb 1-1.2.2: SerialNumber: 1653C4
usb-storage 1-1.2.2:1.2: USB Mass Storage device detected
usb-storage 1-1.2.2:1.2: device ignored

I then launched XSane several times and each time I was able to select either the MP560 via my home network (pixma:MP560_192.168.1.78) or via the USB cable (pixma:04A9173E_1653C4) and scan successfully.

By the way, it is possible to scan via the command line instead of using a GUI scanner application. For example, tjhe following command will scan an A4 page via the MP560’s USB connection (see man scanimage for details of the options):

$ scanimage -d pixma:04A9173E_1653C4 -l 0 -t 0 -x 215 -y 297 --resolution 150 --mode Color | convert - scanned-page.png

So the problem is solved, right? Wrong! For whatever reason, scanning via the USB interface is not guaranteed to work every time I boot the laptop. Sometimes scanner applications (and the scanimage command) hang if I select the USB interface; at other times they don’t hang and scanning works fine. If scanning using the USB device is not working, if I unplug and re-insert the USB cable a few times it becomes possible to scan using the USB interface. And once scanning via the USB interface does work, from then onwards it works consistently during that session.

I had been using Version 1.0.24-r5 of the sane-backends package in Gentoo Linux, which is the latest stable version according to the Gentoo package manager. To check if that particular version of the SANE pixma backend might be the cause of the problem I installed the latest version available in the Gentoo package manager (currently 1.0.5_pre20150625). However it made no discernable difference.

To sum up, in my case the most successful approach so far has been to use a kernel ‘quirk’ to force the usb-storage driver to ignore the device and not bind to it. However, this approach does not result in libusb/SANE being able to access the scanner during every boot session, but, if access is successful, it remains successful during the current session. Even if access via the USB interface does not work initially, sometimes I can get it to work by unplugging and re-inserting the USB cable.

UPDATE (July 30, 2015): I have now managed to get scanning to work with almost 100% reliability when connected to the MP560 via USB — see my latest post for details.

About Fitzcarraldo
A Linux user with an interest in all things technical.

2 Responses to The problem of scanning using USB multi-function printers in Linux (continued)

  1. Pingback: The problem of scanning using USB multi-function printers in Linux (success at last) | Fitzcarraldo's Blog

  2. Heinrich says:

    Thanks for providing these instructions. They did guide me to get the scanner part of my Canon Pixma MG3550 up and running under OpenSuse (it was not reliable working when installed via Yast).

    However, not all MFP are so difficult to setup: with my previous HP2575 all in one printer I had no problem to get printer and scanner to work, just selecting it out of a list and click OK.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: