Subject: Some experience about Epson GT-9700F usb scanner.
To: None <tech-kern@netbsd.org>
From: enami tsugutomo <enami@but-b.or.jp>
List: tech-kern
Date: 12/02/2001 18:34:35
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)