Commit e4d69788 authored by Hans Verkuil's avatar Hans Verkuil Committed by Greg Kroah-Hartman

V4L: ivtv: Add locking to ensure stream setup is atomic

Starting an MPEG and VBI capture simultaneously caused errors in
the VBI setup: this setup was done twice when it should be done
only for the first stream that is opened.
Added a mutex to prevent this from happening.

(cherry picked from commit f8859691)
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
Signed-off-by: default avatarMichael Krufky <mkrufky@linuxtv.org>
parent 53a8e6e3
...@@ -622,6 +622,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) ...@@ -622,6 +622,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
mutex_init(&itv->serialize_lock);
mutex_init(&itv->i2c_bus_lock); mutex_init(&itv->i2c_bus_lock);
mutex_init(&itv->udma.lock); mutex_init(&itv->udma.lock);
......
...@@ -722,6 +722,7 @@ struct ivtv { ...@@ -722,6 +722,7 @@ struct ivtv {
int search_pack_header; int search_pack_header;
spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
struct mutex serialize_lock; /* lock used to serialize starting streams */
/* User based DMA for OSD */ /* User based DMA for OSD */
struct ivtv_user_dma udma; struct ivtv_user_dma udma;
......
...@@ -446,6 +446,9 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) ...@@ -446,6 +446,9 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
if (s->v4l2dev == NULL) if (s->v4l2dev == NULL)
return -EINVAL; return -EINVAL;
/* Big serialization lock to ensure no two streams are started
simultaneously: that can give all sorts of weird results. */
mutex_lock(&itv->serialize_lock);
IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
switch (s->type) { switch (s->type) {
...@@ -487,6 +490,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) ...@@ -487,6 +490,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
0, sizeof(itv->vbi.sliced_mpeg_size)); 0, sizeof(itv->vbi.sliced_mpeg_size));
break; break;
default: default:
mutex_unlock(&itv->serialize_lock);
return -EINVAL; return -EINVAL;
} }
s->subtype = subtype; s->subtype = subtype;
...@@ -568,6 +572,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) ...@@ -568,6 +572,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
{ {
IVTV_DEBUG_WARN( "Error starting capture!\n"); IVTV_DEBUG_WARN( "Error starting capture!\n");
mutex_unlock(&itv->serialize_lock);
return -EINVAL; return -EINVAL;
} }
...@@ -583,6 +588,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) ...@@ -583,6 +588,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
/* you're live! sit back and await interrupts :) */ /* you're live! sit back and await interrupts :) */
atomic_inc(&itv->capturing); atomic_inc(&itv->capturing);
mutex_unlock(&itv->serialize_lock);
return 0; return 0;
} }
...@@ -762,17 +768,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) ...@@ -762,17 +768,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
/* only run these if we're shutting down the last cap */
if (atomic_read(&itv->capturing) - 1 == 0) {
/* event notification (off) */
if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
/* type: 0 = refresh */
/* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
}
}
then = jiffies; then = jiffies;
if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
...@@ -840,17 +835,30 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) ...@@ -840,17 +835,30 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* Clear capture and no-read bits */ /* Clear capture and no-read bits */
clear_bit(IVTV_F_S_STREAMING, &s->s_flags); clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
/* ensure these global cleanup actions are done only once */
mutex_lock(&itv->serialize_lock);
if (s->type == IVTV_ENC_STREAM_TYPE_VBI) if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
if (atomic_read(&itv->capturing) > 0) { if (atomic_read(&itv->capturing) > 0) {
mutex_unlock(&itv->serialize_lock);
return 0; return 0;
} }
/* Set the following Interrupt mask bits for capture */ /* Set the following Interrupt mask bits for capture */
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
/* event notification (off) */
if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
/* type: 0 = refresh */
/* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
}
wake_up(&s->waitq); wake_up(&s->waitq);
mutex_unlock(&itv->serialize_lock);
return 0; return 0;
} }
......
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