Skip to content

Commit 2edc1ac

Browse files
Xu Yanggregkh
authored andcommitted
usb: gadget: uvc: fix req_payload_size calculation
Current req_payload_size calculation has 2 issue: (1) When the first time calculate req_payload_size for all the buffers, reqs_per_frame = 0 will be the divisor of DIV_ROUND_UP(). So the result is undefined. This happens because VIDIOC_STREAMON is always executed after VIDIOC_QBUF. So video->reqs_per_frame will be 0 until VIDIOC_STREAMON is run. (2) The buf->req_payload_size may be bigger than max_req_size. Take YUYV pixel format as example: If bInterval = 1, video->interval = 666666, high-speed: video->reqs_per_frame = 666666 / 1250 = 534 720p: buf->req_payload_size = 1843200 / 534 = 3452 1080p: buf->req_payload_size = 4147200 / 534 = 7766 Based on such req_payload_size, the controller can't run normally. To fix above issue, assign max_req_size to buf->req_payload_size when video->reqs_per_frame = 0. And limit buf->req_payload_size to video->req_size if it's large than video->req_size. Since max_req_size is used at many place, add it to struct uvc_video and set the value once endpoint is enabled. Fixes: 98ad032 ("usb: gadget: uvc: set req_length based on payload by nreqs instead of req_size") Cc: stable@vger.kernel.org Reviewed-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Xu Yang <xu.yang_2@nxp.com> Link: https://patch.msgid.link/20260113-uvc-gadget-fix-patch-v2-1-62950ef5bcb5@nxp.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 42c85d8 commit 2edc1ac

4 files changed

Lines changed: 17 additions & 7 deletions

File tree

drivers/usb/gadget/function/f_uvc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
362362
return ret;
363363
usb_ep_enable(uvc->video.ep);
364364

365+
uvc->video.max_req_size = uvc->video.ep->maxpacket
366+
* max_t(unsigned int, uvc->video.ep->maxburst, 1)
367+
* (uvc->video.ep->mult);
368+
365369
memset(&v4l2_event, 0, sizeof(v4l2_event));
366370
v4l2_event.type = UVC_EVENT_STREAMON;
367371
v4l2_event_queue(&uvc->vdev, &v4l2_event);

drivers/usb/gadget/function/uvc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ struct uvc_video {
117117
/* Requests */
118118
bool is_enabled; /* tracks whether video stream is enabled */
119119
unsigned int req_size;
120+
unsigned int max_req_size;
120121
struct list_head ureqs; /* all uvc_requests allocated by uvc_video */
121122

122123
/* USB requests that the video pump thread can encode into */

drivers/usb/gadget/function/uvc_queue.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,17 @@ static int uvc_buffer_prepare(struct vb2_buffer *vb)
8686
buf->bytesused = 0;
8787
} else {
8888
buf->bytesused = vb2_get_plane_payload(vb, 0);
89-
buf->req_payload_size =
90-
DIV_ROUND_UP(buf->bytesused +
91-
(video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN),
92-
video->reqs_per_frame);
89+
90+
if (video->reqs_per_frame != 0) {
91+
buf->req_payload_size =
92+
DIV_ROUND_UP(buf->bytesused +
93+
(video->reqs_per_frame * UVCG_REQUEST_HEADER_LEN),
94+
video->reqs_per_frame);
95+
if (buf->req_payload_size > video->req_size)
96+
buf->req_payload_size = video->req_size;
97+
} else {
98+
buf->req_payload_size = video->max_req_size;
99+
}
93100
}
94101

95102
return 0;

drivers/usb/gadget/function/uvc_video.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -503,9 +503,7 @@ uvc_video_prep_requests(struct uvc_video *video)
503503
unsigned int max_req_size, req_size, header_size;
504504
unsigned int nreq;
505505

506-
max_req_size = video->ep->maxpacket
507-
* max_t(unsigned int, video->ep->maxburst, 1)
508-
* (video->ep->mult);
506+
max_req_size = video->max_req_size;
509507

510508
if (!usb_endpoint_xfer_isoc(video->ep->desc)) {
511509
video->req_size = max_req_size;

0 commit comments

Comments
 (0)