summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2019-06-10 13:36:12 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2019-06-10 13:36:12 +0000
commit67176f8b96638e12f3ee56494d9159af26074cf0 (patch)
tree0806a485eb30adad266915b74bc50de87f8ba7a2 /sys/dev/usb
parent5468d1c7c5a0595390b1a8e11f8f5f060850e693 (diff)
Notes
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/usb_generic.c51
1 files changed, 47 insertions, 4 deletions
diff --git a/sys/dev/usb/usb_generic.c b/sys/dev/usb/usb_generic.c
index 41e699f33ff2..c5d29ad530d8 100644
--- a/sys/dev/usb/usb_generic.c
+++ b/sys/dev/usb/usb_generic.c
@@ -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,7 +1275,12 @@ 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 */
}
@@ -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, int fflags)
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));
}