Hi,

Since years now I have tried to find out what's wrong with Mustek USB
scanners like the ScanExpress 1200 CU. I would like to know if someone
else made similar experience or knows what may be going on here.

Short description:
------------------

I can open the USB device, bulk_read, bulk_write, whatever, do a
normal scan without problems. Then I close the device. Under special
circumstances after the next open, the first bulk_read (and every
bulk_read after that) runs into the timeout (no data transferred).
Writing does work, however.

Longer description:
-------------------

I'm talking about USB scanners like the Mustek ScanExpress 1200 CU,
1200 UB, 600 CU which use the Mustek MA1017 ASIC. This ASIC provides
one bulk-in, one bulk-out and an interrupt endpoint:

T:  Bus=01 Lev=02 Prnt=02 Port=00 Cnt=01 Dev#= 26 Spd=12  MxCh= 0
D:  Ver= 1.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=055f ProdID=0001 Rev= 1.00
C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 64mA
I:  If#= 0 Alt= 0 #EPs= 3 Cls=00(>ifc ) Sub=00 Prot=00 Driver=(none)
E:  Ad=01(O) Atr=02(Bulk) MxPS=   2 Ivl=0ms
E:  Ad=82(I) Atr=02(Bulk) MxPS=  64 Ivl=0ms
E:  Ad=83(I) Atr=03(Int.) MxPS=   1 Ivl=1ms

The ASIC communicates by setting registers. Writing to a register just
means sending two bytes (byte 1: value, byte 2: register number).
Reading is similar: write two bytes (byte 1: ignored, byte 2: register
number) and then read the value (one byte).

The problem first occured on FreeBSD with the FreeBSD scanner driver
(see http://www.freebsd.org/cgi/query-pr.cgi?pr=kern/41281). 

Basically, you can scan once without problems. The second time the
scanner device is opened, the first bulk_read doesn't get any data.

Further investigation showed that this happens with FreeBSD, OpenBSD,
and NetBSD with libusb or the uscanner (linux-like) kernel scanner
driver.

It didn't happen with Linux (neither libusb/usbfs nor kernel scanner
driver). So I thought it's a BSD USB core bug.

Now I found out that I can provoke the problem also with Linux. If I
use libusb in it's most basic way, there is no problem. But if I use
any of the functions usb_set_configuration(), usb_resetep(),
usb_clear_halt(), I get the same problem.

The first bulk access after plugging in the device always works. The
second always doesn't work. The third sometimes work, the forth may
work. And so on.

I'll append a test program /for libusb 0.1.6 or later) that just opens
the device and tries to read register 2. If I use it unchanged, it
works. If I change *any* of the #if 0 to #if 1, the second run of the
program runs into the timeout (5 s) of bulk_read. Example (resetep is
enabled):

:plugging in the scanner
: 1. run:
usb_init ... done
usb_find_busses ... done (result = 2)
usb_find_devices ... done (result = 4)
checking for devices ... done (device = 0x804f518)
usb_open ... done (handle = 0x8050548)
usb_claim_interface ... done (result = 0)
usb_bulk_write ... done (result = 2)
usb_bulk_read ... done (result = 1, read = 128)
usb_resetep ... done (result = 0)
usb_close ... done
:2. run
usb_init ... done
usb_find_busses ... done (result = 2)
usb_find_devices ... done (result = 4)
checking for devices ... done (device = 0x804f518)
usb_open ... done (handle = 0x8050548)
usb_claim_interface ... done (result = 0)
usb_bulk_write ... done (result = 2)
usb_bulk_read ... 
:hangs for 5 seconds here
                  done (result = -1, read = 0)
:3. run, 4. run both works, 5. run runs into timeout again.

This is on Linux 2.4.21-pre3, but I don't think it depend on the
kernel. No problems when using the kernel scanner driver.
This is with the ohci driver. Also tested on a completely different
system (2.4.20) with usb-uhci: similar behaviour. However, in this
case, once the error occurs, it will occur with every run after the
first one.

The Windows 98 driver works without major problems, but I can't test
the details like with Linux.

Anyone any ideas? Just crappy hardware? But why is the error triggered
by a simple function like resetep?

Bye,
  Henning

----------------------- test program: link with -lusb -----------------------

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <usb.h>

int
main (int argc, char ** argv)
{
  int n;
  unsigned char data_field[2];
  int result = 0;
  struct usb_bus *bus;
  struct usb_device *dev, *device = 0;
  struct usb_interface_descriptor *interface;
  usb_dev_handle *handle;

  fprintf (stderr, "usb_init ... ");
  usb_init ();
  fprintf (stderr, "done\n");

  fprintf (stderr, "usb_find_busses ... ");
  result = usb_find_busses ();
  fprintf (stderr, "done (result = %d)\n", result);

  fprintf (stderr, "usb_find_devices ... ");
  result = usb_find_devices ();
  fprintf (stderr, "done (result = %d)\n", result);

  fprintf (stderr, "checking for devices ... ");
  for (bus = usb_busses; bus && !device; bus = bus->next)
    {
      for (dev = bus->devices; dev && !device; dev = dev->next)
        {
          if (dev->descriptor.idVendor == 0x055f &&
              dev->descriptor.idProduct == 0x0001)
            device = dev;
        }
    }
  fprintf (stderr, "done (device = %p)\n", device);
  if (!device)
    exit (1);

  fprintf (stderr, "usb_open ... ");
  handle = usb_open (device);
  fprintf (stderr, "done (handle = %p)\n", handle);
  if (!handle)
    exit (1);

#if 0
  /* first run works, all later runs don't */
  fprintf (stderr, "usb_set_configuration ... ");
  result = usb_set_configuration (handle, 1);
  fprintf (stderr, "done (result = %d)\n", result);
  if (result != 0)
    exit (1);
#endif

  interface = &device->config[0].interface[0].altsetting[0];
  fprintf (stderr, "usb_claim_interface ... ");
  result = usb_claim_interface (handle, interface->bInterfaceNumber);
  fprintf (stderr, "done (result = %d)\n", result);
  if (result != 0)
    exit (1);

  /* read register 0x02 */
  n = 2;
  data_field[0] = 0x00;
  data_field[1] = 0x2 | 0x20;
  
  fprintf (stderr, "usb_bulk_write ... ");
  result = usb_bulk_write (handle, interface->endpoint[0].bEndpointAddress,
                           data_field, n, 5000);
  fprintf (stderr, "done (result = %d)\n", result);
  if (result != n)
    exit (1);
  
  n = 1;
  fprintf (stderr, "usb_bulk_read ... ");
  result = usb_bulk_read (handle, interface->endpoint[1].bEndpointAddress,
                          data_field, n, 5000);
  fprintf (stderr, "done (result = %d, read = %d)\n",
           result, data_field[0]);
  if (result != n)
    exit (1);

#if 0
  /* first run works, second doesn't, third works, forth works, fifth doesn't
     ... */
  fprintf (stderr, "usb_resetep ... ");
  result = usb_resetep (handle, interface->endpoint[0].bEndpointAddress);
  fprintf (stderr, "done (result = %d)\n", result);
  if (result != 0)
    exit (1);
#endif

#if 0
  /* same as resetep */
  fprintf (stderr, "usb_clearhalt ... ");
  result = usb_clear_halt (handle, interface->endpoint[0].bEndpointAddress);
  fprintf (stderr, "done (result = %d)\n", result);
  if (result != 0)
    exit (1);
#endif


  fprintf (stderr, "usb_close ... ");
  usb_close (handle);
  fprintf (stderr, "done\n");

  exit (0);
}


-------------------------------------------------------
This SF.NET email is sponsored by:
SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See!
http://www.vasoftware.com
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to