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. MFC after: 3 days Sponsored by: Mellanox Technologies
This commit is contained in:
parent
cc202e518b
commit
8cf2829845
@ -1218,6 +1218,40 @@ complete:
|
||||
return (0);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -1243,7 +1277,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 */
|
||||
}
|
||||
@ -1364,6 +1403,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));
|
||||
@ -1452,12 +1492,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));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user