svn commit: r348858 - stable/9/sys/dev/usb

Hans Petter Selasky hselasky at FreeBSD.org
Mon Jun 10 13:38:58 UTC 2019


Author: hselasky
Date: Mon Jun 10 13:38:57 2019
New Revision: 348858
URL: https://svnweb.freebsd.org/changeset/base/348858

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.
  
  Sponsored by:	Mellanox Technologies

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

Modified: stable/9/sys/dev/usb/usb_generic.c
==============================================================================
--- stable/9/sys/dev/usb/usb_generic.c	Mon Jun 10 13:37:38 2019	(r348857)
+++ stable/9/sys/dev/usb/usb_generic.c	Mon Jun 10 13:38:57 2019	(r348858)
@@ -1206,6 +1206,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;
@@ -1230,8 +1264,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);
@@ -1351,6 +1390,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));
@@ -1438,12 +1478,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));
 			}


More information about the svn-src-stable-9 mailing list