Subject: Re: Some experience about Epson GT-9700F usb scanner.
To: enami tsugutomo <enami@but-b.or.jp>
From: Lennart Augustsson <lennart@augustsson.net>
List: tech-kern
Date: 12/02/2001 12:05:25
Ah, I actually have a clue what might be going wrong.  It's probably the
data toggles that are not set right.

I'll cook up a fix later today.

    -- Lennart


enami tsugutomo wrote:

> Here is my brief experience about Epson GT-9700F usb scanner.
>
> - Unless ehcidebug is set to some value other than 0, attach phase
>   fails as follows:
>
>         usbd_transfer_cb: short transfer 0<4
>         uscanner0 at uhub2 port 1
>         uscanner0: EPSON EPSON Scanner, rev 2.00/1.01, addr 2
>         usbd_transfer_cb: short transfer 0<9
>         uscanner0: setting config no failed
>
>   The controller is NEC's.
>
> - If connected to uhci controller, it attaches successfully.  And it
>   works like many times of `scanimage -L' (from sane-backend pkg)
>   successfully returns the name of GT-9700F as available scanner
>   (i.e., reset and some other sequence like identify can be sent many
>   times and scanner response normally).  And I can scan once.  After
>   that, it waits ACK (of ESC/I protocol, Epson's scanner control
>   language) from scanner after sending 2 byte reset sequence.  When
>   this occurs, NAK bit is set in TD's status field (after read
>   operation is started).  E.g.,
>
>          5<T,VF> 398807ff<NAK,ACTIVE,IOC,SPD>,errcnt=3,actlen=0
>          pid=69,addr=2,endpt=1,D=0,maxlen=4
>
> - And I finanly found that if I defer actual device close operation
>   until detach time (see the diff attached below.  the diff includes
>   some garbage tho), the scanner works fine (with both uhci and ehci,
>   not tested with ohci controller yet).  But I'm not sure if this
>   should be integrated in main tree or not.  Especially if there is
>   another fix...
>
> enami.
>
> Index: uscanner.c
> ===================================================================
> RCS file: /cvsroot/syssrc/sys/dev/usb/uscanner.c,v
> retrieving revision 1.21
> diff -c -r1.21 uscanner.c
> *** uscanner.c  2001/12/01 09:42:39     1.21
> --- uscanner.c  2001/12/02 09:07:48
> ***************
> *** 72,78 ****
>   #ifdef USCANNER_DEBUG
>   #define DPRINTF(x)    if (uscannerdebug) logprintf x
>   #define DPRINTFN(n,x) if (uscannerdebug>(n)) logprintf x
> ! int   uscannerdebug = 0;
>   #else
>   #define DPRINTF(x)
>   #define DPRINTFN(n,x)
> --- 72,78 ----
>   #ifdef USCANNER_DEBUG
>   #define DPRINTF(x)    if (uscannerdebug) logprintf x
>   #define DPRINTFN(n,x) if (uscannerdebug>(n)) logprintf x
> ! int   uscannerdebug = 6;
>   #else
>   #define DPRINTF(x)
>   #define DPRINTFN(n,x)
> ***************
> *** 80,87 ****
>
>   /* Table of scanners that may work with this driver. */
>   static const struct scanner_id {
> !       uint16_t        vendor;
> !       uint16_t        product;
>   } scanner_ids [] = {
>         /* Acer Peripherals */
>         { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_320U },
> --- 80,89 ----
>
>   /* Table of scanners that may work with this driver. */
>   static const struct scanner_id {
> !       uint16_t        si_vendor;
> !       uint16_t        si_product;
> !       int             si_quirks;
> ! #define       USCANNERQ_DEFERCLOSE    0x0001
>   } scanner_ids [] = {
>         /* Acer Peripherals */
>         { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_ACERSCAN_320U },
> ***************
> *** 155,161 ****
>         { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1640 },
>         { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_640U },
>         { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1650 },
> !       { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_GT9700F },
>
>         /* UMAX */
>         { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1220U },
> --- 157,163 ----
>         { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1640 },
>         { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_640U },
>         { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_1650 },
> !       { USB_VENDOR_EPSON, USB_PRODUCT_EPSON_GT9700F, USCANNERQ_DEFERCLOSE },
>
>         /* UMAX */
>         { USB_VENDOR_UMAX, USB_PRODUCT_UMAX_ASTRA1220U },
> ***************
> *** 178,184 ****
>         { 0, 0 }
>   };
>
> ! #define       USCANNER_BUFFERSIZE     1024
>
>   struct uscanner_softc {
>         USBBASEDEVICE           sc_dev;         /* base device */
> --- 180,186 ----
>         { 0, 0 }
>   };
>
> ! #define       USCANNER_BUFFERSIZE     4096
>
>   struct uscanner_softc {
>         USBBASEDEVICE           sc_dev;         /* base device */
> ***************
> *** 201,207 ****
> --- 203,214 ----
>
>         u_char                  sc_state;
>   #define USCANNER_OPEN         0x01    /* opened */
> + #define USCANNER_SETUP                0x02    /* setup is done */
> + #define USCANNER_ATTACHED     0x04    /* attached */
>
> +       u_char                  sc_flags;
> + #define       USCANNERF_DEFERCLOSE    0x01
> +
>         int                     sc_refcnt;
>         u_char                  sc_dying;
>   };
> ***************
> *** 235,262 ****
>   };
>   #endif
>
>   Static int uscanner_do_read(struct uscanner_softc *, struct uio *, int);
>   Static int uscanner_do_write(struct uscanner_softc *, struct uio *, int);
>   Static void uscanner_do_close(struct uscanner_softc *);
>
>   #define USCANNERUNIT(n) (minor(n))
>
>   USB_DECLARE_DRIVER(uscanner);
>
>   USB_MATCH(uscanner)
>   {
>         USB_MATCH_START(uscanner, uaa);
> -       int i;
>
>         if (uaa->iface != NULL)
>                 return UMATCH_NONE;
>
> !       for (i = 0; scanner_ids[i].vendor != 0; i++) {
> !               if (scanner_ids[i].vendor == uaa->vendor &&
> !                   scanner_ids[i].product == uaa->product) {
> !                       return (UMATCH_VENDOR_PRODUCT);
> !               }
> !       }
>
>         return (UMATCH_NONE);
>   }
> --- 242,281 ----
>   };
>   #endif
>
> + Static const struct scanner_id *uscanner_lookup(struct usb_attach_arg *);
>   Static int uscanner_do_read(struct uscanner_softc *, struct uio *, int);
>   Static int uscanner_do_write(struct uscanner_softc *, struct uio *, int);
> + Static int uscanner_do_open(struct uscanner_softc *);
>   Static void uscanner_do_close(struct uscanner_softc *);
>
>   #define USCANNERUNIT(n) (minor(n))
>
>   USB_DECLARE_DRIVER(uscanner);
>
> + Static const struct scanner_id *
> + uscanner_lookup(struct usb_attach_arg *uaa)
> + {
> +       int i;
> +
> +       for (i = 0; scanner_ids[i].si_vendor != 0; i++) {
> +               if (scanner_ids[i].si_vendor == uaa->vendor &&
> +                   scanner_ids[i].si_product == uaa->product) {
> +                       return (&scanner_ids[i]);
> +               }
> +       }
> +
> +       return (NULL);
> + }
> +
>   USB_MATCH(uscanner)
>   {
>         USB_MATCH_START(uscanner, uaa);
>
>         if (uaa->iface != NULL)
>                 return UMATCH_NONE;
>
> !       if (uscanner_lookup(uaa) != NULL)
> !               return (UMATCH_VENDOR_PRODUCT);
>
>         return (UMATCH_NONE);
>   }
> ***************
> *** 266,271 ****
> --- 285,291 ----
>         USB_ATTACH_START(uscanner, sc, uaa);
>         usb_interface_descriptor_t *id = 0;
>         usb_endpoint_descriptor_t *ed, *ed_bulkin = NULL, *ed_bulkout = NULL;
> +       const struct scanner_id *si;
>         char devinfo[1024];
>         int i;
>         usbd_status err;
> ***************
> *** 274,279 ****
> --- 294,303 ----
>         USB_ATTACH_SETUP;
>         printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
>
> +       si = uscanner_lookup(uaa);
> +       if (si == NULL)
> +               panic("uscanner_attach: impossible");
> +
>         sc->sc_udev = uaa->device;
>
>         err = usbd_set_config_no(uaa->device, 1, 1); /* XXX */
> ***************
> *** 286,292 ****
>         /* XXX We only check the first interface */
>         err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface);
>         if (!err && sc->sc_iface)
> !           id = usbd_get_interface_descriptor(sc->sc_iface);
>         if (err || id == 0) {
>                 printf("%s: could not get interface descriptor, err=%d,id=%p\n",
>                        USBDEVNAME(sc->sc_dev), err, id);
> --- 310,316 ----
>         /* XXX We only check the first interface */
>         err = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface);
>         if (!err && sc->sc_iface)
> !               id = usbd_get_interface_descriptor(sc->sc_iface);
>         if (err || id == 0) {
>                 printf("%s: could not get interface descriptor, err=%d,id=%p\n",
>                        USBDEVNAME(sc->sc_dev), err, id);
> ***************
> *** 323,328 ****
> --- 347,355 ----
>
>         sc->sc_bulkin = ed_bulkin->bEndpointAddress;
>         sc->sc_bulkout = ed_bulkout->bEndpointAddress;
> +       if (si->si_quirks & USCANNERQ_DEFERCLOSE)
> +               sc->sc_flags |= USCANNERF_DEFERCLOSE;
> +       sc->sc_state |= USCANNER_ATTACHED;
>
>   #ifdef __FreeBSD__
>         /* the main device, ctrl endpoint */
> ***************
> *** 345,358 ****
>   {
>         struct uscanner_softc *sc;
>         int unit = USCANNERUNIT(dev);
> -       usbd_status err;
>
>         USB_GET_SC_OPEN(uscanner, unit, sc);
>
>         DPRINTFN(5, ("uscanneropen: flag=%d, mode=%d, unit=%d\n",
>                      flag, mode, unit));
>
> !       if (sc->sc_dying)
>                 return (ENXIO);
>
>         if (sc->sc_state & USCANNER_OPEN)
> --- 372,384 ----
>   {
>         struct uscanner_softc *sc;
>         int unit = USCANNERUNIT(dev);
>
>         USB_GET_SC_OPEN(uscanner, unit, sc);
>
>         DPRINTFN(5, ("uscanneropen: flag=%d, mode=%d, unit=%d\n",
>                      flag, mode, unit));
>
> !       if (sc->sc_dying || (sc->sc_state & USCANNER_ATTACHED) == 0)
>                 return (ENXIO);
>
>         if (sc->sc_state & USCANNER_OPEN)
> ***************
> *** 360,365 ****
> --- 386,402 ----
>
>         sc->sc_state |= USCANNER_OPEN;
>
> +       if ((sc->sc_state & USCANNER_SETUP) == 0)
> +               uscanner_do_open(sc);
> +
> +       return (0);     /* success */
> + }
> +
> + int
> + uscanner_do_open(struct uscanner_softc *sc)
> + {
> +       usbd_status err;
> +
>         sc->sc_bulkin_buffer = malloc(USCANNER_BUFFERSIZE, M_USBDEV, M_WAITOK);
>         sc->sc_bulkout_buffer = malloc(USCANNER_BUFFERSIZE, M_USBDEV, M_WAITOK);
>         /* No need to check buffers for NULL since we have WAITOK */
> ***************
> *** 396,401 ****
> --- 433,439 ----
>                 return (ENOMEM);
>         }
>
> +       sc->sc_state |= USCANNER_SETUP;
>         return (0);     /* success */
>   }
>
> ***************
> *** 420,427 ****
>         }
>   #endif
>
> !       uscanner_do_close(sc);
>
>         return (0);
>   }
>
> --- 458,468 ----
>         }
>   #endif
>
> !       if ((sc->sc_flags & USCANNERF_DEFERCLOSE) == 0)
> !               uscanner_do_close(sc);
>
> +       sc->sc_state &= ~USCANNER_OPEN;
> +
>         return (0);
>   }
>
> ***************
> *** 457,463 ****
>                 sc->sc_bulkout_buffer = NULL;
>         }
>
> !       sc->sc_state &= ~USCANNER_OPEN;
>   }
>
>   Static int
> --- 498,504 ----
>                 sc->sc_bulkout_buffer = NULL;
>         }
>
> !       sc->sc_state &= ~USCANNER_SETUP;
>   }
>
>   Static int
> ***************
> *** 468,476 ****
>   {
>         u_int32_t n, tn;
>         usbd_status err;
> !       int error = 0;
>
> !       DPRINTFN(5, ("%s: uscannerread\n", USBDEVNAME(sc->sc_dev)));
>
>         if (sc->sc_dying)
>                 return (EIO);
> --- 509,518 ----
>   {
>         u_int32_t n, tn;
>         usbd_status err;
> !       int error = 0, i;
>
> !       DPRINTFN(5, ("%s: uscannerread: resid %d\n", USBDEVNAME(sc->sc_dev),
> !           uio->uio_resid));
>
>         if (sc->sc_dying)
>                 return (EIO);
> ***************
> *** 492,499 ****
>                         else
>                                 error = EIO;
>                         break;
>                 }
> !               DPRINTFN(1, ("uscannerread: got %d bytes\n", tn));
>                 error = uiomove(sc->sc_bulkin_buffer, tn, uio);
>                 if (error || tn < n)
>                         break;
> --- 534,546 ----
>                         else
>                                 error = EIO;
>                         break;
> +               }
> +               DPRINTFN(1, ("uscannerread: got %d bytes", tn));
> +               for (i = 0; i < 16 && i < tn; i++) {
> +                       DPRINTFN(1, (" 0x%x",
> +                           ((u_char *)sc->sc_bulkin_buffer)[i]));
>                 }
> !               DPRINTFN(1, ("\n"));
>                 error = uiomove(sc->sc_bulkin_buffer, tn, uio);
>                 if (error || tn < n)
>                         break;
> ***************
> *** 528,534 ****
>         int flag;
>   {
>         u_int32_t n;
> !       int error = 0;
>         usbd_status err;
>
>         DPRINTFN(5, ("%s: uscanner_do_write\n", USBDEVNAME(sc->sc_dev)));
> --- 575,581 ----
>         int flag;
>   {
>         u_int32_t n;
> !       int error = 0, i;
>         usbd_status err;
>
>         DPRINTFN(5, ("%s: uscanner_do_write\n", USBDEVNAME(sc->sc_dev)));
> ***************
> *** 540,549 ****
>                 error = uiomove(sc->sc_bulkout_buffer, n, uio);
>                 if (error)
>                         break;
> !               DPRINTFN(1, ("uscanner_do_write: transfer %d bytes\n", n));
>                 err = usbd_bulk_transfer(
>                         sc->sc_bulkout_xfer, sc->sc_bulkout_pipe,
> !                       0, USBD_NO_TIMEOUT,
>                         sc->sc_bulkout_buffer, &n,
>                         "uscnwb");
>                 if (err) {
> --- 587,601 ----
>                 error = uiomove(sc->sc_bulkout_buffer, n, uio);
>                 if (error)
>                         break;
> !               DPRINTFN(1, ("uscanner_do_write: transfer %d bytes", n));
> !               for (i = 0; i < 16 && i < n; i++) {
> !                       DPRINTFN(1, (" 0x%x",
> !                           ((u_char *)sc->sc_bulkout_buffer)[i]));
> !               }
> !               DPRINTFN(1, ("\n"));
>                 err = usbd_bulk_transfer(
>                         sc->sc_bulkout_xfer, sc->sc_bulkout_pipe,
> !                       /* USBD_FORCE_SHORT_XFER */0, USBD_NO_TIMEOUT,
>                         sc->sc_bulkout_buffer, &n,
>                         "uscnwb");
>                 if (err) {
> ***************
> *** 615,620 ****
> --- 667,675 ----
>   #endif
>
>         sc->sc_dying = 1;
> +
> +       if ((sc->sc_state & USCANNER_SETUP) != 0)
> +               uscanner_do_close(sc);
>
>         /* Abort all pipes.  Causes processes waiting for transfer to wake. */
>         if (sc->sc_bulkin_pipe)