diff options
author | Kieran Bingham <kieran.bingham@ideasonboard.com> | 2017-03-23 08:25:14 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab+samsung@kernel.org> | 2018-12-05 03:10:06 -0500 |
commit | e829b262a6782ee36ee04e32a2fc7341385ac7fe (patch) | |
tree | 22240f51d2aafe89606bd23718732992a9eeda7f /drivers/media/usb/uvc | |
parent | c6d664fe8a7a47af1c63c037e20570d4abbda3c6 (diff) |
media: uvcvideo: Protect queue internals with helper
The URB completion operation obtains the current buffer by reading
directly into the queue internal interface.
Protect this queue abstraction by providing a helper
uvc_queue_get_current_buffer() which can be used by both the decode
task, and the uvc_queue_next_buffer() functions.
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'drivers/media/usb/uvc')
-rw-r--r-- | drivers/media/usb/uvc/uvc_queue.c | 33 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvc_video.c | 6 | ||||
-rw-r--r-- | drivers/media/usb/uvc/uvcvideo.h | 1 |
3 files changed, 30 insertions, 10 deletions
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 8964e16f2b22..74f9483911d0 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -430,6 +430,33 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) spin_unlock_irqrestore(&queue->irqlock, flags); } +/* + * uvc_queue_get_current_buffer: Obtain the current working output buffer + * + * Buffers may span multiple packets, and even URBs, therefore the active buffer + * remains on the queue until the EOF marker. + */ +static struct uvc_buffer * +__uvc_queue_get_current_buffer(struct uvc_video_queue *queue) +{ + if (list_empty(&queue->irqqueue)) + return NULL; + + return list_first_entry(&queue->irqqueue, struct uvc_buffer, queue); +} + +struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue) +{ + struct uvc_buffer *nextbuf; + unsigned long flags; + + spin_lock_irqsave(&queue->irqlock, flags); + nextbuf = __uvc_queue_get_current_buffer(queue); + spin_unlock_irqrestore(&queue->irqlock, flags); + + return nextbuf; +} + struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf) { @@ -446,11 +473,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, spin_lock_irqsave(&queue->irqlock, flags); list_del(&buf->queue); - if (!list_empty(&queue->irqqueue)) - nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - else - nextbuf = NULL; + nextbuf = __uvc_queue_get_current_buffer(queue); spin_unlock_irqrestore(&queue->irqlock, flags); buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 6d4384695964..7a7779e1b466 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1484,11 +1484,7 @@ static void uvc_video_complete(struct urb *urb) return; } - spin_lock_irqsave(&queue->irqlock, flags); - if (!list_empty(&queue->irqqueue)) - buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - spin_unlock_irqrestore(&queue->irqlock, flags); + buf = uvc_queue_get_current_buffer(queue); if (vb2_qmeta) { spin_lock_irqsave(&qmeta->irqlock, flags); diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 35ba48769244..f6109a4dde5b 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -728,6 +728,7 @@ int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); +struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue); int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma); __poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, |