diff options
Diffstat (limited to 'freebsd/sys/dev/usb/usb_generic.c')
-rw-r--r-- | freebsd/sys/dev/usb/usb_generic.c | 58 |
1 files changed, 52 insertions, 6 deletions
diff --git a/freebsd/sys/dev/usb/usb_generic.c b/freebsd/sys/dev/usb/usb_generic.c index 29a27d53..6d359226 100644 --- a/freebsd/sys/dev/usb/usb_generic.c +++ b/freebsd/sys/dev/usb/usb_generic.c @@ -185,7 +185,8 @@ ugen_open(struct usb_fifo *f, int fflags) struct usb_endpoint_descriptor *ed = ep->edesc; uint8_t type; - DPRINTFN(6, "flag=0x%x\n", fflags); + DPRINTFN(1, "flag=0x%x pid=%d name=%s\n", fflags, + curthread->td_proc->p_pid, curthread->td_proc->p_comm); mtx_lock(f->priv_mtx); switch (usbd_get_speed(f->udev)) { @@ -215,7 +216,9 @@ ugen_open(struct usb_fifo *f, int fflags) static void ugen_close(struct usb_fifo *f, int fflags) { - DPRINTFN(6, "flag=0x%x\n", fflags); + + DPRINTFN(1, "flag=0x%x pid=%d name=%s\n", fflags, + curthread->td_proc->p_pid, curthread->td_proc->p_comm); /* cleanup */ @@ -1218,6 +1221,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; @@ -1242,7 +1279,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 */ } @@ -1363,6 +1405,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)); @@ -1451,12 +1494,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)); } |