mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 06:33:34 +00:00
[media] v4l2-pci-skeleton.c: fix alternate field handling
For interlaced HDTV timings the correct field setting is FIELD_ALTERNATE, not INTERLACED. Update this template driver accordingly: - add check for the invalid combination of read() and FIELD_ALTERNATE. - in the interrupt handler set v4l2_buffer field to alternating TOP and BOTTOM. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
parent
b050b29e07
commit
5f26f2501b
@ -77,7 +77,8 @@ struct skeleton {
|
|||||||
|
|
||||||
spinlock_t qlock;
|
spinlock_t qlock;
|
||||||
struct list_head buf_list;
|
struct list_head buf_list;
|
||||||
unsigned int sequence;
|
unsigned field;
|
||||||
|
unsigned sequence;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct skel_buffer {
|
struct skel_buffer {
|
||||||
@ -124,7 +125,7 @@ static const struct v4l2_dv_timings_cap skel_timings_cap = {
|
|||||||
* Interrupt handler: typically interrupts happen after a new frame has been
|
* Interrupt handler: typically interrupts happen after a new frame has been
|
||||||
* captured. It is the job of the handler to remove the new frame from the
|
* captured. It is the job of the handler to remove the new frame from the
|
||||||
* internal list and give it back to the vb2 framework, updating the sequence
|
* internal list and give it back to the vb2 framework, updating the sequence
|
||||||
* counter and timestamp at the same time.
|
* counter, field and timestamp at the same time.
|
||||||
*/
|
*/
|
||||||
static irqreturn_t skeleton_irq(int irq, void *dev_id)
|
static irqreturn_t skeleton_irq(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
@ -139,8 +140,15 @@ static irqreturn_t skeleton_irq(int irq, void *dev_id)
|
|||||||
spin_lock(&skel->qlock);
|
spin_lock(&skel->qlock);
|
||||||
list_del(&new_buf->list);
|
list_del(&new_buf->list);
|
||||||
spin_unlock(&skel->qlock);
|
spin_unlock(&skel->qlock);
|
||||||
new_buf->vb.v4l2_buf.sequence = skel->sequence++;
|
|
||||||
v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp);
|
v4l2_get_timestamp(&new_buf->vb.v4l2_buf.timestamp);
|
||||||
|
new_buf->vb.v4l2_buf.sequence = skel->sequence++;
|
||||||
|
new_buf->vb.v4l2_buf.field = skel->field;
|
||||||
|
if (skel->format.field == V4L2_FIELD_ALTERNATE) {
|
||||||
|
if (skel->field == V4L2_FIELD_BOTTOM)
|
||||||
|
skel->field = V4L2_FIELD_TOP;
|
||||||
|
else if (skel->field == V4L2_FIELD_TOP)
|
||||||
|
skel->field = V4L2_FIELD_BOTTOM;
|
||||||
|
}
|
||||||
vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE);
|
vb2_buffer_done(&new_buf->vb, VB2_BUF_STATE_DONE);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -160,6 +168,17 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
|
|||||||
{
|
{
|
||||||
struct skeleton *skel = vb2_get_drv_priv(vq);
|
struct skeleton *skel = vb2_get_drv_priv(vq);
|
||||||
|
|
||||||
|
skel->field = skel->format.field;
|
||||||
|
if (skel->field == V4L2_FIELD_ALTERNATE) {
|
||||||
|
/*
|
||||||
|
* You cannot use read() with FIELD_ALTERNATE since the field
|
||||||
|
* information (TOP/BOTTOM) cannot be passed back to the user.
|
||||||
|
*/
|
||||||
|
if (vb2_fileio_is_active(q))
|
||||||
|
return -EINVAL;
|
||||||
|
skel->field = V4L2_FIELD_TOP;
|
||||||
|
}
|
||||||
|
|
||||||
if (vq->num_buffers + *nbuffers < 3)
|
if (vq->num_buffers + *nbuffers < 3)
|
||||||
*nbuffers = 3 - vq->num_buffers;
|
*nbuffers = 3 - vq->num_buffers;
|
||||||
|
|
||||||
@ -173,10 +192,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare the buffer for queueing to the DMA engine: check and set the
|
* Prepare the buffer for queueing to the DMA engine: check and set the
|
||||||
* payload size and fill in the field. Note: if the format's field is
|
* payload size.
|
||||||
* V4L2_FIELD_ALTERNATE, then vb->v4l2_buf.field should be set in the
|
|
||||||
* interrupt handler since that's usually where you know if the TOP or
|
|
||||||
* BOTTOM field has been captured.
|
|
||||||
*/
|
*/
|
||||||
static int buffer_prepare(struct vb2_buffer *vb)
|
static int buffer_prepare(struct vb2_buffer *vb)
|
||||||
{
|
{
|
||||||
@ -190,7 +206,6 @@ static int buffer_prepare(struct vb2_buffer *vb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
vb2_set_plane_payload(vb, 0, size);
|
vb2_set_plane_payload(vb, 0, size);
|
||||||
vb->v4l2_buf.field = skel->format.field;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,10 +334,12 @@ static void skeleton_fill_pix_format(struct skeleton *skel,
|
|||||||
/* HDMI input */
|
/* HDMI input */
|
||||||
pix->width = skel->timings.bt.width;
|
pix->width = skel->timings.bt.width;
|
||||||
pix->height = skel->timings.bt.height;
|
pix->height = skel->timings.bt.height;
|
||||||
if (skel->timings.bt.interlaced)
|
if (skel->timings.bt.interlaced) {
|
||||||
pix->field = V4L2_FIELD_INTERLACED;
|
pix->field = V4L2_FIELD_ALTERNATE;
|
||||||
else
|
pix->height /= 2;
|
||||||
|
} else {
|
||||||
pix->field = V4L2_FIELD_NONE;
|
pix->field = V4L2_FIELD_NONE;
|
||||||
|
}
|
||||||
pix->colorspace = V4L2_COLORSPACE_REC709;
|
pix->colorspace = V4L2_COLORSPACE_REC709;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user