Skip to content

Commit 0a0a276

Browse files
Dan Vacuragregkh
authored andcommitted
usb: gadget: uvc: fix sg handling in error case
If there is a transmission error the buffer will be returned too early, causing a memory fault as subsequent requests for that buffer are still queued up to be sent. Refactor the error handling to wait for the final request to come in before reporting back the buffer to userspace for all transfer types (bulk/isoc/isoc_sg). This ensures userspace knows if the frame was successfully sent. Fixes: e81e7f9 ("usb: gadget: uvc: add scatter gather support") Cc: <[email protected]> Signed-off-by: Dan Vacura <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 8e8e923 commit 0a0a276

File tree

2 files changed

+19
-7
lines changed

2 files changed

+19
-7
lines changed

drivers/usb/gadget/function/uvc_queue.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable)
304304

305305
queue->sequence = 0;
306306
queue->buf_used = 0;
307+
queue->flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
307308
} else {
308309
ret = vb2_streamoff(&queue->queue, queue->queue.type);
309310
if (ret < 0)
@@ -329,10 +330,11 @@ int uvcg_queue_enable(struct uvc_video_queue *queue, int enable)
329330
void uvcg_complete_buffer(struct uvc_video_queue *queue,
330331
struct uvc_buffer *buf)
331332
{
332-
if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
333-
buf->length != buf->bytesused) {
334-
buf->state = UVC_BUF_STATE_QUEUED;
333+
if (queue->flags & UVC_QUEUE_DROP_INCOMPLETE) {
334+
queue->flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
335+
buf->state = UVC_BUF_STATE_ERROR;
335336
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, 0);
337+
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_ERROR);
336338
return;
337339
}
338340

drivers/usb/gadget/function/uvc_video.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
8888
struct uvc_buffer *buf)
8989
{
9090
void *mem = req->buf;
91+
struct uvc_request *ureq = req->context;
9192
int len = video->req_size;
9293
int ret;
9394

@@ -113,13 +114,14 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
113114
video->queue.buf_used = 0;
114115
buf->state = UVC_BUF_STATE_DONE;
115116
list_del(&buf->queue);
116-
uvcg_complete_buffer(&video->queue, buf);
117117
video->fid ^= UVC_STREAM_FID;
118+
ureq->last_buf = buf;
118119

119120
video->payload_size = 0;
120121
}
121122

122123
if (video->payload_size == video->max_payload_size ||
124+
video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE ||
123125
buf->bytesused == video->queue.buf_used)
124126
video->payload_size = 0;
125127
}
@@ -180,7 +182,8 @@ uvc_video_encode_isoc_sg(struct usb_request *req, struct uvc_video *video,
180182
req->length -= len;
181183
video->queue.buf_used += req->length - header_len;
182184

183-
if (buf->bytesused == video->queue.buf_used || !buf->sg) {
185+
if (buf->bytesused == video->queue.buf_used || !buf->sg ||
186+
video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE) {
184187
video->queue.buf_used = 0;
185188
buf->state = UVC_BUF_STATE_DONE;
186189
buf->offset = 0;
@@ -195,6 +198,7 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
195198
struct uvc_buffer *buf)
196199
{
197200
void *mem = req->buf;
201+
struct uvc_request *ureq = req->context;
198202
int len = video->req_size;
199203
int ret;
200204

@@ -209,12 +213,13 @@ uvc_video_encode_isoc(struct usb_request *req, struct uvc_video *video,
209213

210214
req->length = video->req_size - len;
211215

212-
if (buf->bytesused == video->queue.buf_used) {
216+
if (buf->bytesused == video->queue.buf_used ||
217+
video->queue.flags & UVC_QUEUE_DROP_INCOMPLETE) {
213218
video->queue.buf_used = 0;
214219
buf->state = UVC_BUF_STATE_DONE;
215220
list_del(&buf->queue);
216-
uvcg_complete_buffer(&video->queue, buf);
217221
video->fid ^= UVC_STREAM_FID;
222+
ureq->last_buf = buf;
218223
}
219224
}
220225

@@ -255,6 +260,11 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
255260
case 0:
256261
break;
257262

263+
case -EXDEV:
264+
uvcg_dbg(&video->uvc->func, "VS request missed xfer.\n");
265+
queue->flags |= UVC_QUEUE_DROP_INCOMPLETE;
266+
break;
267+
258268
case -ESHUTDOWN: /* disconnect from host. */
259269
uvcg_dbg(&video->uvc->func, "VS request cancelled.\n");
260270
uvcg_queue_cancel(queue, 1);

0 commit comments

Comments
 (0)