SANE Canon MP730 driver

In 2006, I spent a bit of time helping Martin Schewe and Wittawat Yamwong to develop some working drivers for the Canon PIXMA class scanners. I have one of the early models in that class, the Canon imageCLASS MP730, which was marketed to the USA market as a Canon MultiPASS MP730.

The drivers worked fine for a beta test and I have been using Wittawat's mp150-0.10.1 drivers for one-off scans ever since. However, something changed in mp150-0.12.0 that broke things and I never found time to work out what was going wrong, but lately I have decided to put some effort into getting a proper driver working.

After a bit of tinkering, I worked out that the line that broke it was only the PIXMA_CAP_EVENTS capability, and after removing that from the bit map, the driver in mp150-0.12.2 now scans correctly too. A better fix will come when I get it working properly, but this was enough to start with.

--- pixma_mp730.c.orig  2006-08-27 07:37:16.000000000 +1000
+++ pixma_mp730.c       2009-03-20 03:28:16.000000000 +1100
@@ -533,7 +533,7 @@
        &pixma_mp730_ops,  /* ops */            \
        dpi, dpi,          /* xdpi, ydpi */     \
        w, h,              /* width, height */  \
-        PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap                      \
+        PIXMA_CAP_GRAY|cap                      \
 }
 const pixma_config_t pixma_mp730_devices[] = {
 /* TODO: check area limits */

Wittawat's drivers have been superceded in the SANE project (though you wouldn't know by looking at it) and the current release is now "pixma version 0.15.0" found in the sane-backends module of CVS. This version now uses libusb for its USB functionality but unfortunately I cannot get it to work at all with the scanner, even though the changes to pixma_mp730.c are minimal. It always breaks on the first read/write URB.

I have prepared logs of my scan attempts and attached them to this post. Both are using basically the same parameters - the primary difference is the use of libusb-0.1.12

One thing that I notice from the logs is that they seem to attach to different bulk-in and bulk-out endpoints:

[pixma-0.12.2] Found endpoints: 3 (OUT), 84 (IN), 85 (INTR,64)

as compared to:

[sanei_usb] sanei_usb_open: we already have a bulk-out endpoint (address: 0x01), ignoring the new one
[sanei_usb] sanei_usb_open: we already have a bulk-in endpoint (address: 0x82), ignoring the new one
[sanei_usb] sanei_usb_open: we already have a int-in endpoint (address: 0x85), ignoring the new one

I don't know enough about USB devices from here, so I will leave it to the SANE experts.

Nicolas' page on MP610 also looks helpful.

UPDATE (18/4/09):

I saw on the sane-devel mailing list a helpful command to fully display the device info seen through libusb. This also points to SANE trying to open the wrong endpoints...

# sane-find-scanner -v -v
This is sane-find-scanner from sane-backends 1.0.19

[---snip---]
<device descriptor of 0x04a9/0x262f at 002:009 (Canon Inc. MP730)>
bLength               18
bDescriptorType       1
bcdUSB                2.00
bDeviceClass          0
bDeviceSubClass       0
bDeviceProtocol       0
bMaxPacketSize0       64
idVendor              0x04A9
idProduct             0x262F
bcdDevice             17.02
iManufacturer         1 (Canon Inc.)
iProduct              2 (MP730)
iSerialNumber         3 (00000000F972)
bNumConfigurations    1
 <configuration 0>
 bLength              9
 bDescriptorType      2
 wTotalLength         115
 bNumInterfaces       4
 bConfigurationValue  1
 iConfiguration       0 ()
 bmAttributes         192 (Self-powered)
 MaxPower             2 mA
  <interface 0>
   <altsetting 0>
   bLength            9
   bDescriptorType    4
   bInterfaceNumber   0
   bAlternateSetting  0
   bNumEndpoints      2
   bInterfaceClass    7
   bInterfaceSubClass 1
   bInterfaceProtocol 2
   iInterface         0 ()
    <endpoint 0>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x01 (out 0x01)
    bmAttributes      2 (bulk)
    wMaxPacketSize    64
    bInterval         0 ms
    bRefresh          0
    bSynchAddress     0
    <endpoint 1>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x82 (in 0x02)
    bmAttributes      2 (bulk)
    wMaxPacketSize    64
    bInterval         0 ms
    bRefresh          0
    bSynchAddress     0
  <interface 1>
   <altsetting 0>
   bLength            9
   bDescriptorType    4
   bInterfaceNumber   1
   bAlternateSetting  0
   bNumEndpoints      3
   bInterfaceClass    255
   bInterfaceSubClass 0
   bInterfaceProtocol 255
   iInterface         0 ()
    <endpoint 0>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x03 (out 0x03)
    bmAttributes      2 (bulk)
    wMaxPacketSize    64
    bInterval         0 ms
    bRefresh          0
    bSynchAddress     0
    <endpoint 1>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x84 (in 0x04)
    bmAttributes      2 (bulk)
    wMaxPacketSize    64
    bInterval         0 ms
    bRefresh          0
    bSynchAddress     0
    <endpoint 2>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x85 (in 0x05)
    bmAttributes      3 (interrupt)
    wMaxPacketSize    64
    bInterval         200 ms
    bRefresh          0
    bSynchAddress     0
  <interface 2>
   <altsetting 0>
   bLength            9
   bDescriptorType    4
   bInterfaceNumber   2
   bAlternateSetting  0
   bNumEndpoints      2
   bInterfaceClass    8
   bInterfaceSubClass 6
   bInterfaceProtocol 80
   iInterface         0 ()
    <endpoint 0>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x86 (in 0x06)
    bmAttributes      2 (bulk)
    wMaxPacketSize    64
    bInterval         0 ms
    bRefresh          0
    bSynchAddress     0
    <endpoint 1>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x07 (out 0x07)
    bmAttributes      2 (bulk)
    wMaxPacketSize    64
    bInterval         0 ms
    bRefresh          0
    bSynchAddress     0
  <interface 3>
   <altsetting 0>
   bLength            9
   bDescriptorType    4
   bInterfaceNumber   3
   bAlternateSetting  0
   bNumEndpoints      3
   bInterfaceClass    255
   bInterfaceSubClass 0
   bInterfaceProtocol 255
   iInterface         0 ()
    <endpoint 0>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x08 (out 0x08)
    bmAttributes      2 (bulk)
    wMaxPacketSize    64
    bInterval         0 ms
    bRefresh          0
    bSynchAddress     0
    <endpoint 1>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x89 (in 0x09)
    bmAttributes      2 (bulk)
    wMaxPacketSize    64
    bInterval         0 ms
    bRefresh          0
    bSynchAddress     0
    <endpoint 2>
    bLength           7
    bDescriptorType   5
    bEndpointAddress  0x8A (in 0x0A)
    bmAttributes      3 (interrupt)
    wMaxPacketSize    64
    bInterval         200 ms
    bRefresh          0
    bSynchAddress     0

<trying to find out which USB chip is used>
    checking for GT-6801 ...
    this is not a GT-6801 (bDeviceClass = 0)
    checking for GT-6816 ...
    this is not a GT-6816 (bDeviceClass = 0, bInterfaceClass = 7)
    checking for GT-8911 ...
    this is not a GT-8911 (check 1, bDeviceClass = 0, bInterfaceClass = 7)
    checking for MA-1017 ...
    this is not a MA-1017 (bDeviceClass = 0, bInterfaceClass = 7)
    checking for MA-1015 ...
    this is not a MA-1015 (bDeviceClass = 0)
    checking for MA-1509 ...
    this is not a MA-1509 (bDeviceClass = 0)
    checking for LM983[1,2,3] ...
    this is not a LM983x (bDeviceClass = 0, bInterfaceClass = 7)
    checking for GL646 ...
    this is not a GL646 (bDeviceClass = 0, bInterfaceClass = 7)
    checking for GL646_HP ...
    this is not a GL646_HP (bDeviceClass = 0, bInterfaceClass = 7)
    checking for GL660+GL646 ...
    this is not a GL660+GL646 (bDeviceClass = 0, bInterfaceClass = 7)
    checking for GL84x ...
    this is not a GL841 (bDeviceClass = 0, bInterfaceClass = 7)
    checking for ICM532B ...
    this is not a ICM532B (check 1, bDeviceClass = 0, bInterfaceClass = 7)
    checking for PV8630/LM9830 ...
    this is not a PV8630/LM9830 (bcdUSB = 0x200)
    checking for M011 ...
    this is not a M011 (bDeviceClass = 0)
    checking for RTS8822 ...
    this is not a RTS8822 (bNumEndpoints = 2)
    checking for rts8858c ...
    this is not a rts8858c (bcdUSB = 0x200)
    checking for SQ113 ...
    this is not a SQ113 (bInterfaceClass = 7)
    checking for HP5550/5590/7650 chipset ...
    this is not a HP5550/5590/7650 chipset (bDeviceClass = 0)
    checking for rts8801/rts8891 ...
    this is not a rts8801/rts8891 (bcdUSB = 0x200)
<Couldn't determine the type of the USB chip (result from sane-backends 1.0.19)>

found USB scanner (vendor=0x04a9 [Canon Inc.], product=0x262f [MP730]) at libusb:002:009

 

UPDATE 2 (18/4/09)

Based on the documentation about "Device Classes" at http://www.linux-usb.org/USB-guide/x75.html and the official list of USB Class Codes from the USB Device Working Group, I modified the code in sanei/sanei_usb.c to skip Printer and Mass-Storage interface classes. Now I can attach to the correct endpoints and write data to the scanner, but it is expecting 14 bytes to be read, instead of the 2 bytes that is actually read. My work continues....

 

UPDATE 3 (19/4/09)

The 2 bytes that are being read are 0x1515 (PIXMA_STATUS_FAILED). This seems quite odd given that the data in the first URB to be written by the CVS version is the same as the data in the first URB written by pixma-0.12.2 (now working). Both CVS and pixma-0.12.2 use bulk transfers for reading and writing, but on different underlying USB infrastructures.

  • The old pixma-0.12.2 code uses usbdevfs with a call to usbSendBulkMsg() for both reading and writing.
  • The CVS code (pixma-0.15.0) uses libusb with calls to usb_write_bulk() and usb_read_bulk()

Both calls result in an ioctl() on the file handle for /dev/bus/usb/002/009

 

UPDATE 4 (19/4/09)

Partial Success!!!

The trouble, I have found, is that the second Vendor Specific interface (interface 3) was somehow getting mixed up with the first Vendor Specific interface (interface 1) so that the endpoints from interface 3 were being used to send the URBs. I changed sanei/sanei_usb.c again to skip interface 3 and now I get a partial success. It actually scans something.

I should also note this is with Gentoo Linux 2.6.18-ck1 kernel, libusb-0.1.12-r5 and sane-backends_cvs from 2009-03-20 14:34.

 

UPDATE 5 (21/4/09)

Finally!!!

After 2.5 years of not having a scanner working properly under Linux, and many many hours staring at gdb breakpoints, I finally squashed the bugs, and it comes down to some very small changes in only 1 file. My change at Update 4 was sufficient but I had made other bad changes that broke it in other ways.

helot sane-backends_cvs # cvs diff -u sanei/sanei_usb.c
Index: sanei/sanei_usb.c
===================================================================
RCS file: /cvsroot/sane/sane-backends/sanei/sanei_usb.c,v
retrieving revision 1.58
diff -u -r1.58 sanei_usb.c
--- sanei/sanei_usb.c   19 Feb 2009 13:57:45 -0000      1.58
+++ sanei/sanei_usb.c   21 Apr 2009 17:06:28 -0000
@@ -1243,6 +1243,20 @@

                  interface = &dev->config[c].interface[i].altsetting[a];

+                 /* don't try to read non-scanner device classes */
+                 if (interface->bInterfaceClass == 0x07) {
+                   DBG (3, "sanei_usb_open: skipping Printer interface\n");
+                   continue;
+                 }
+                 if (interface->bInterfaceClass == 0x08) {
+                   DBG (3, "sanei_usb_open: skipping Mass Storage interface\n");
+                   continue;
+                 }
+                 if (interface->bInterfaceClass == 0xff && i == 3) {
+                   DBG (3, "sanei_usb_open: skipping second Vendor Specific interface\n");
+                   continue;
+                 }
+
                  /* Now we look for usable endpoints */
                  for (num = 0; num < interface->bNumEndpoints; num++)
                    {

See the full patch with extra debugging info.

In summary:

Do not consider endpoints from Printer and Mass Storage interfaces. I have not fully debugged the problem of why the endpoints of the second Vendor Specific interface were overwriting the stored values of the first interface's endpoints.

Scanned on a Canon MP730 using S.A.N.E on Linux Scanned on a Canon MP730 using S.A.N.E 1.0.20cvs on Linux

UPDATE 6 (26/4/09):

I worked out a solution to the problem of failures using batch mode. The scanner doesn't like receiving a command to start_session and select_source when it already has a session open and is reading from the Automatic Document Feeder (ADF).

I also have a patch to pixma.c that prevents it from returning ECANCELED at the end of each scan. Don't ask me why it works, it just does.

There is still a problem when scanning at 1200dpi resolution in Grayscale mode. After returning some amount of image data, the scanner just keeps sending "OK" responses to requests for more data.

There seems to be a number of people who have had trouble with this driver. Some found the standalone version sufficient for their needs. I can't find anybody who reported problems to the SANE team but I hope this work will get some bug reports flowing.

comments powered by Disqus