summaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/function
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/function')
-rw-r--r--drivers/usb/gadget/function/f_uvc.c4
-rw-r--r--drivers/usb/gadget/function/uvc.h3
-rw-r--r--drivers/usb/gadget/function/uvc_queue.c23
-rw-r--r--drivers/usb/gadget/function/uvc_video.c14
4 files changed, 32 insertions, 12 deletions
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index aa6ab666741a..a96476507d2f 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -362,6 +362,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
return ret;
usb_ep_enable(uvc->video.ep);
+ uvc->video.max_req_size = uvc->video.ep->maxpacket
+ * max_t(unsigned int, uvc->video.ep->maxburst, 1)
+ * (uvc->video.ep->mult);
+
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
v4l2_event_queue(&uvc->vdev, &v4l2_event);
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 9e79cbe50715..676419a04976 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -107,7 +107,7 @@ struct uvc_video {
unsigned int width;
unsigned int height;
unsigned int imagesize;
- unsigned int interval;
+ unsigned int interval; /* in 100ns units */
struct mutex mutex; /* protects frame parameters */
unsigned int uvc_num_requests;
@@ -117,6 +117,7 @@ struct uvc_video {
/* Requests */
bool is_enabled; /* tracks whether video stream is enabled */
unsigned int req_size;
+ unsigned int max_req_size;
struct list_head ureqs; /* all uvc_requests allocated by uvc_video */
/* USB requests that the video pump thread can encode into */
diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c
index 9a1bbd79ff5a..586e5524c171 100644
--- a/drivers/usb/gadget/function/uvc_queue.c
+++ b/drivers/usb/gadget/function/uvc_queue.c
@@ -86,10 +86,17 @@ static int uvc_buffer_prepare(struct vb2_buffer *vb)
buf->bytesused = 0;
} else {
buf->bytesused = vb2_get_plane_payload(vb, 0);
- buf->req_payload_size =
- DIV_ROUND_UP(buf->bytesused +
- (video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN),
- video->reqs_per_frame);
+
+ if (video->reqs_per_frame != 0) {
+ buf->req_payload_size =
+ DIV_ROUND_UP(buf->bytesused +
+ (video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN),
+ video->reqs_per_frame);
+ if (buf->req_payload_size > video->req_size)
+ buf->req_payload_size = video->req_size;
+ } else {
+ buf->req_payload_size = video->max_req_size;
+ }
}
return 0;
@@ -175,7 +182,15 @@ int uvcg_alloc_buffers(struct uvc_video_queue *queue,
{
int ret;
+retry:
ret = vb2_reqbufs(&queue->queue, rb);
+ if (ret < 0 && queue->use_sg) {
+ uvc_trace(UVC_TRACE_IOCTL,
+ "failed to alloc buffer with sg enabled, try non-sg mode\n");
+ queue->use_sg = 0;
+ queue->queue.mem_ops = &vb2_vmalloc_memops;
+ goto retry;
+ }
return ret ? ret : rb->count;
}
diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c
index fb77b0b21790..f568dee08b3b 100644
--- a/drivers/usb/gadget/function/uvc_video.c
+++ b/drivers/usb/gadget/function/uvc_video.c
@@ -499,13 +499,11 @@ uvc_video_prep_requests(struct uvc_video *video)
{
struct uvc_device *uvc = container_of(video, struct uvc_device, video);
struct usb_composite_dev *cdev = uvc->func.config->cdev;
- unsigned int interval_duration = video->ep->desc->bInterval * 1250;
+ unsigned int interval_duration;
unsigned int max_req_size, req_size, header_size;
unsigned int nreq;
- max_req_size = video->ep->maxpacket
- * max_t(unsigned int, video->ep->maxburst, 1)
- * (video->ep->mult);
+ max_req_size = video->max_req_size;
if (!usb_endpoint_xfer_isoc(video->ep->desc)) {
video->req_size = max_req_size;
@@ -515,8 +513,11 @@ uvc_video_prep_requests(struct uvc_video *video)
return;
}
+ interval_duration = 2 << (video->ep->desc->bInterval - 1);
if (cdev->gadget->speed < USB_SPEED_HIGH)
- interval_duration = video->ep->desc->bInterval * 10000;
+ interval_duration *= 10000;
+ else
+ interval_duration *= 1250;
nreq = DIV_ROUND_UP(video->interval, interval_duration);
@@ -837,7 +838,6 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
video->interval = 666666;
/* Initialize the video buffers queue. */
- uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent,
+ return uvcg_queue_init(&video->queue, uvc->v4l2_dev.dev->parent,
V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex);
- return 0;
}