Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Jun 2019 13:36:12 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r348855 - stable/11/sys/dev/usb
Message-ID:  <201906101336.x5ADaC5W028776@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Mon Jun 10 13:36:12 2019
New Revision: 348855
URL: https://svnweb.freebsd.org/changeset/base/348855

Log:
  MFC r348631:
  In usb(4) fix a lost completion event issue towards libusb(3). It may happen
  if a USB transfer is cancelled that we need to fake a completion event.
  Implement missing support in ugen_fs_copy_out() to handle this.
  
  This fixes issues with webcamd(8) and firefox.
  
  Approved by:	re (gjb)
  Sponsored by:	Mellanox Technologies

Modified:
  stable/11/sys/dev/usb/usb_generic.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/dev/usb/usb_generic.c
==============================================================================
--- stable/11/sys/dev/usb/usb_generic.c	Mon Jun 10 13:34:18 2019	(r348854)
+++ stable/11/sys/dev/usb/usb_generic.c	Mon Jun 10 13:36:12 2019	(r348855)
@@ -1217,6 +1217,40 @@ complete:
 }
 
 static int
+ugen_fs_copy_out_cancelled(struct usb_fs_endpoint *fs_ep_uptr)
+{
+	struct usb_fs_endpoint fs_ep;
+	int error;
+
+	error = copyin(fs_ep_uptr, &fs_ep, sizeof(fs_ep));
+	if (error)
+		return (error);
+
+	fs_ep.status = USB_ERR_CANCELLED;
+	fs_ep.aFrames = 0;
+	fs_ep.isoc_time_complete = 0;
+
+	/* update "aFrames" */
+	error = copyout(&fs_ep.aFrames, &fs_ep_uptr->aFrames,
+	    sizeof(fs_ep.aFrames));
+	if (error)
+		goto done;
+
+	/* update "isoc_time_complete" */
+	error = copyout(&fs_ep.isoc_time_complete,
+	    &fs_ep_uptr->isoc_time_complete,
+	    sizeof(fs_ep.isoc_time_complete));
+	if (error)
+		goto done;
+
+	/* update "status" */
+	error = copyout(&fs_ep.status, &fs_ep_uptr->status,
+	    sizeof(fs_ep.status));
+done:
+	return (error);
+}
+
+static int
 ugen_fs_copy_out(struct usb_fifo *f, uint8_t ep_index)
 {
 	struct usb_device_request *req;
@@ -1241,8 +1275,13 @@ ugen_fs_copy_out(struct usb_fifo *f, uint8_t ep_index)
 		return (EINVAL);
 
 	mtx_lock(f->priv_mtx);
-	if (usbd_transfer_pending(xfer)) {
+	if (!xfer->flags_int.transferring &&
+	    !xfer->flags_int.started) {
 		mtx_unlock(f->priv_mtx);
+		DPRINTF("Returning fake cancel event\n");
+		return (ugen_fs_copy_out_cancelled(f->fs_ep_ptr + ep_index));
+	} else if (usbd_transfer_pending(xfer)) {
+		mtx_unlock(f->priv_mtx);
 		return (EBUSY);		/* should not happen */
 	}
 	mtx_unlock(f->priv_mtx);
@@ -1362,6 +1401,7 @@ complete:
 	    sizeof(fs_ep.isoc_time_complete));
 	if (error)
 		goto done;
+
 	/* update "status" */
 	error = copyout(&fs_ep.status, &fs_ep_uptr->status,
 	    sizeof(fs_ep.status));
@@ -1450,12 +1490,15 @@ ugen_ioctl(struct usb_fifo *f, u_long cmd, void *addr,
 		xfer = f->fs_xfer[u.pstart->ep_index];
 		if (usbd_transfer_pending(xfer)) {
 			usbd_transfer_stop(xfer);
+
 			/*
 			 * Check if the USB transfer was stopped
-			 * before it was even started. Else a cancel
-			 * callback will be pending.
+			 * before it was even started and fake a
+			 * cancel event.
 			 */
-			if (!xfer->flags_int.transferring) {
+			if (!xfer->flags_int.transferring &&
+			    !xfer->flags_int.started) {
+				DPRINTF("Issuing fake completion event\n");
 				ugen_fs_set_complete(xfer->priv_sc,
 				    USB_P2U(xfer->priv_fifo));
 			}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201906101336.x5ADaC5W028776>