mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 23:27:06 +00:00
V4L/DVB (5842): 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. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
parent
0901973f4b
commit
f885969196
3 changed files with 21 additions and 11 deletions
|
@ -623,6 +623,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 {
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
/* 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)
|
||||||
/* 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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue