diff options
Diffstat (limited to 'freebsd/sys/dev/usb/usb_generic.c')
-rw-r--r-- | freebsd/sys/dev/usb/usb_generic.c | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/freebsd/sys/dev/usb/usb_generic.c b/freebsd/sys/dev/usb/usb_generic.c index 364b8cc5..d45a0bf6 100644 --- a/freebsd/sys/dev/usb/usb_generic.c +++ b/freebsd/sys/dev/usb/usb_generic.c @@ -1225,6 +1225,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; @@ -1249,7 +1283,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 */ } @@ -1370,6 +1409,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)); @@ -1458,12 +1498,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)); } |