Commit 7708065f authored by Michael Tretter's avatar Michael Tretter Committed by Mauro Carvalho Chehab

media: v4l2-mem2mem: reorder checks in v4l2_m2m_poll()

When reaching the end of stream, V4L2 m2m clients may expect the
V4L2_EOS_EVENT. Although the V4L2_EOS_EVENT is deprecated behavior,
drivers must signal that event before dequeuing the buffer that has the
V4L2_BUF_FLAG_LAST flag set.

If a driver queues the V4L2_EOS_EVENT event and returns the buffer after
the check for events but before the check for buffers, vb2_m2m_poll()
will signal that the buffer with V4L2_BUF_FLAG_LAST can be read but not
that the V4L2_EOS_EVENT is available.

Split the check for buffers into a separate function and check for
available buffers before checking for events. This ensures that if
vb2_m2m_poll() signals POLLIN | POLLRDNORM for the V4L2_BUF_FLAG_LAST
buffer, it signals POLLPRI for the V4L2_EOS_EVENT, too.
Signed-off-by: default avatarMichael Tretter <m.tretter@pengutronix.de>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
[hverkuil-cisco@xs4all.nl: fix checkpatch alignment warning]
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 8d86a156
...@@ -603,11 +603,10 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, ...@@ -603,11 +603,10 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
} }
EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff); EXPORT_SYMBOL_GPL(v4l2_m2m_streamoff);
__poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, static __poll_t v4l2_m2m_poll_for_data(struct file *file,
struct poll_table_struct *wait) struct v4l2_m2m_ctx *m2m_ctx,
struct poll_table_struct *wait)
{ {
struct video_device *vfd = video_devdata(file);
__poll_t req_events = poll_requested_events(wait);
struct vb2_queue *src_q, *dst_q; struct vb2_queue *src_q, *dst_q;
struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
__poll_t rc = 0; __poll_t rc = 0;
...@@ -619,16 +618,6 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, ...@@ -619,16 +618,6 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
poll_wait(file, &src_q->done_wq, wait); poll_wait(file, &src_q->done_wq, wait);
poll_wait(file, &dst_q->done_wq, wait); poll_wait(file, &dst_q->done_wq, wait);
if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
struct v4l2_fh *fh = file->private_data;
poll_wait(file, &fh->wait, wait);
if (v4l2_event_pending(fh))
rc = EPOLLPRI;
if (!(req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM)))
return rc;
}
/* /*
* There has to be at least one buffer queued on each queued_list, which * There has to be at least one buffer queued on each queued_list, which
* means either in driver already or waiting for driver to claim it * means either in driver already or waiting for driver to claim it
...@@ -637,10 +626,8 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, ...@@ -637,10 +626,8 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
if ((!src_q->streaming || src_q->error || if ((!src_q->streaming || src_q->error ||
list_empty(&src_q->queued_list)) && list_empty(&src_q->queued_list)) &&
(!dst_q->streaming || dst_q->error || (!dst_q->streaming || dst_q->error ||
list_empty(&dst_q->queued_list))) { list_empty(&dst_q->queued_list)))
rc |= EPOLLERR; return EPOLLERR;
goto end;
}
spin_lock_irqsave(&dst_q->done_lock, flags); spin_lock_irqsave(&dst_q->done_lock, flags);
if (list_empty(&dst_q->done_list)) { if (list_empty(&dst_q->done_list)) {
...@@ -650,7 +637,7 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, ...@@ -650,7 +637,7 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
*/ */
if (dst_q->last_buffer_dequeued) { if (dst_q->last_buffer_dequeued) {
spin_unlock_irqrestore(&dst_q->done_lock, flags); spin_unlock_irqrestore(&dst_q->done_lock, flags);
return rc | EPOLLIN | EPOLLRDNORM; return EPOLLIN | EPOLLRDNORM;
} }
} }
spin_unlock_irqrestore(&dst_q->done_lock, flags); spin_unlock_irqrestore(&dst_q->done_lock, flags);
...@@ -673,7 +660,27 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, ...@@ -673,7 +660,27 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
rc |= EPOLLIN | EPOLLRDNORM; rc |= EPOLLIN | EPOLLRDNORM;
spin_unlock_irqrestore(&dst_q->done_lock, flags); spin_unlock_irqrestore(&dst_q->done_lock, flags);
end: return rc;
}
__poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
struct poll_table_struct *wait)
{
struct video_device *vfd = video_devdata(file);
__poll_t req_events = poll_requested_events(wait);
__poll_t rc = 0;
if (req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM))
rc = v4l2_m2m_poll_for_data(file, m2m_ctx, wait);
if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
struct v4l2_fh *fh = file->private_data;
poll_wait(file, &fh->wait, wait);
if (v4l2_event_pending(fh))
rc |= EPOLLPRI;
}
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(v4l2_m2m_poll); EXPORT_SYMBOL_GPL(v4l2_m2m_poll);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment