*** src/sys/dev/usb/ugen.c.lfc	Mon Dec 22 01:33:26 2003
--- src/sys/dev/usb/ugen.c	Fri Dec 26 13:16:06 2003
***************
*** 66,71 ****
--- 66,72 ----
  #include <dev/usb/usbdi.h>
  #include <dev/usb/usbdi_util.h>
  
+ #define USB_DEBUG
  #ifdef USB_DEBUG
  #define DPRINTF(x)	if (ugendebug) logprintf x
  #define DPRINTFN(n,x)	if (ugendebug>(n)) logprintf x
***************
*** 93,98 ****
--- 94,100 ----
  	int state;
  #define	UGEN_ASLP	0x02	/* waiting for data */
  #define UGEN_SHORT_OK	0x04	/* short xfers are OK */
+ #define UGEN_CLEAR_STALL 0x08   /* perform clear stall on next read */
  	usbd_pipe_handle pipeh;
  	struct clist q;
  	struct selinfo rsel;
***************
*** 506,511 ****
--- 508,537 ----
  }
  
  Static int
+ ugen_clear_halt(struct ugen_endpoint *sce)
+ {
+ 	usbd_status err;
+ 	int error = 0;
+ 
+ 	err = usbd_clear_endpoint_stall(sce->pipeh);
+ 	if (err) {
+ 		if (err == USBD_INTERRUPTED) {
+ 			DPRINTFN(10, ("ugen_clear_halt: interrupted\n"));
+ 			error = EINTR;
+ 		} else if (err == USBD_TIMEOUT) {
+ 			DPRINTFN(10, ("ugen_clear_halt: time out\n"));
+ 			error = ETIMEDOUT;
+ 		} else {
+ 			DPRINTFN(10, ("ugen_clear_halt: I/O Error(%d)\n",
+ 				      err));
+ 			error = EIO;
+ 		}
+ 	}
+ 
+ 	return(error);
+ }
+ 
+ Static int
  ugen_do_read(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
  {
  	struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][IN];
***************
*** 575,585 ****
  		}
  		break;
  	case UE_BULK:
  		xfer = usbd_alloc_xfer(sc->sc_udev);
  		if (xfer == 0)
  			return (ENOMEM);
  		while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
! 			DPRINTFN(1, ("ugenread: start transfer %d bytes\n",n));
  			tn = n;
  			err = usbd_bulk_transfer(
  				xfer, sce->pipeh,
--- 601,620 ----
  		}
  		break;
  	case UE_BULK:
+ 		if (sce->state & UGEN_CLEAR_STALL) {
+ 			DPRINTF(("ugenread: clearing endpoint halt on ioctl\n"));
+ 			sce->state &= (~UGEN_CLEAR_STALL);
+ 			if (ugen_clear_halt(sce)) {
+ 				printf("ugenread: endpoint clear failed\n");
+ 			}
+ 			return (0);
+ 		}
  		xfer = usbd_alloc_xfer(sc->sc_udev);
  		if (xfer == 0)
  			return (ENOMEM);
+ 		tn = 0;
  		while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
! 			DPRINTFN(1, ("ugenread: start transfer %d bytes%s timeout=%d\n",n,sce->state & UGEN_SHORT_OK ? " shortok" : "",sce->timeout));
  			tn = n;
  			err = usbd_bulk_transfer(
  				xfer, sce->pipeh,
***************
*** 595,605 ****
  					error = EIO;
  				break;
  			}
! 			DPRINTFN(1, ("ugenread: got %d bytes\n", tn));
  			error = uiomove(buf, tn, uio);
  			if (error || tn < n)
  				break;
  		}
  		usbd_free_xfer(xfer);
  		break;
  	case UE_ISOCHRONOUS:
--- 630,648 ----
  					error = EIO;
  				break;
  			}
! 			DPRINTFN(1, ("ugenread: got %d bytes start=0x%x\n", tn, (int) buf[0]));
  			error = uiomove(buf, tn, uio);
  			if (error || tn < n)
  				break;
  		}
+ #if 0
+ 		if (tn == 0 || tn == n) {
+ 			DPRINTF(("ugenread: clearing endpoint halt\n"));
+ 			if (ugen_clear_halt(sce)) {
+ 				printf("ugenread: endpoint clear failed\n");
+ 			}
+ 		}
+ #endif
  		usbd_free_xfer(xfer);
  		break;
  	case UE_ISOCHRONOUS:
***************
*** 1045,1050 ****
--- 1088,1108 ----
  	switch (cmd) {
  	case FIONBIO:
  		/* All handled in the upper FS layer. */
+ 		return (0);
+ 	case USB_CLEAR_ENDPOINT_STALL:
+ 		sce = &sc->sc_endpoints[endpt][IN];
+ 		if (sce == NULL)
+ 			return (EINVAL);
+ #ifdef DIAGNOSTIC
+ 		if (sce->pipeh == NULL) {
+ 			printf("ugenioctl: USB_CLEAR_ENDPOINT_STALL, no pipe\n");
+ 			return (EIO);
+ 		}
+ #endif
+ 		sce->state |= UGEN_CLEAR_STALL;
+ 		/* causes panic at present...
+ 		usbd_clear_endpoint_stall(sce->pipeh);
+ 		*/
  		return (0);
  	case USB_SET_SHORT_XFER:
  		/* This flag only affects read */
*** src/sys/dev/usb/usb.h.lfc	Mon Dec 22 01:34:44 2003
--- src/sys/dev/usb/usb.h	Mon Dec 22 01:45:39 2003
***************
*** 562,567 ****
--- 562,568 ----
  #define USB_GET_DEVICEINFO	_IOR ('U', 112, struct usb_device_info)
  #define USB_SET_SHORT_XFER	_IOW ('U', 113, int)
  #define USB_SET_TIMEOUT		_IOW ('U', 114, int)
+ #define USB_CLEAR_ENDPOINT_STALL _IOW ('U', 115, int)
  
  /* Modem device */
  #define USB_GET_CM_OVER_DATA	_IOR ('U', 130, int)
