Sometimes, the USB pipe could enter into a stalled state,
and may need a reset to rework.
Add such logic.
[mchehab@osg.samsung.com: ported from Android's source:
https://android.googlesource.com/kernel/x86_64/+/
3a322adc0084fd277b43070712c7dc0dc9245435%5E%21]
Signed-off-by: Terry Heo <terryheo@google.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
case -ESHUTDOWN:
return;
default: /* error */
case -ESHUTDOWN:
return;
default: /* error */
- cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+ cx231xx_isocdbg("urb completion error %d.\n", urb->status);
case -ENOENT:
case -ESHUTDOWN:
return;
case -ENOENT:
case -ESHUTDOWN:
return;
+ case -EPIPE: /* stall */
+ cx231xx_isocdbg("urb completion error - device is stalled.\n");
+ return;
- cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+ cx231xx_isocdbg("urb completion error %d.\n", urb->status);
struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
struct urb *urb;
int i;
struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
struct urb *urb;
int i;
+ bool broken_pipe = false;
cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n");
cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n");
transfer_buffer[i],
urb->transfer_dma);
}
transfer_buffer[i],
urb->transfer_dma);
}
+ if (urb->status == -EPIPE) {
+ broken_pipe = true;
+ }
usb_free_urb(urb);
dev->video_mode.isoc_ctl.urb[i] = NULL;
}
dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL;
}
usb_free_urb(urb);
dev->video_mode.isoc_ctl.urb[i] = NULL;
}
dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL;
}
+ if (broken_pipe) {
+ cx231xx_isocdbg("Reset endpoint to recover broken pipe.");
+ usb_reset_endpoint(dev->udev, dev->video_mode.end_point_addr);
+ }
kfree(dev->video_mode.isoc_ctl.urb);
kfree(dev->video_mode.isoc_ctl.transfer_buffer);
kfree(dma_q->p_left_data);
kfree(dev->video_mode.isoc_ctl.urb);
kfree(dev->video_mode.isoc_ctl.transfer_buffer);
kfree(dma_q->p_left_data);
struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
struct urb *urb;
int i;
struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
struct urb *urb;
int i;
+ bool broken_pipe = false;
cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n");
cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n");
transfer_buffer[i],
urb->transfer_dma);
}
transfer_buffer[i],
urb->transfer_dma);
}
+ if (urb->status == -EPIPE) {
+ broken_pipe = true;
+ }
usb_free_urb(urb);
dev->video_mode.bulk_ctl.urb[i] = NULL;
}
dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL;
}
usb_free_urb(urb);
dev->video_mode.bulk_ctl.urb[i] = NULL;
}
dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL;
}
+ if (broken_pipe) {
+ cx231xx_isocdbg("Reset endpoint to recover broken pipe.");
+ usb_reset_endpoint(dev->udev, dev->video_mode.end_point_addr);
+ }
kfree(dev->video_mode.bulk_ctl.urb);
kfree(dev->video_mode.bulk_ctl.transfer_buffer);
kfree(dma_q->p_left_data);
kfree(dev->video_mode.bulk_ctl.urb);
kfree(dev->video_mode.bulk_ctl.transfer_buffer);
kfree(dma_q->p_left_data);