Skip to content

Commit

Permalink
V4L/DVB (5842): ivtv: Add locking to ensure stream setup is atomic.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed Jul 18, 2007
1 parent 0901973 commit f885969
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 11 deletions.
1 change: 1 addition & 0 deletions drivers/media/video/ivtv/ivtv-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->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->udma.lock);

Expand Down
1 change: 1 addition & 0 deletions drivers/media/video/ivtv/ivtv-driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ struct ivtv {
int search_pack_header;

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 */
struct ivtv_user_dma udma;
Expand Down
30 changes: 19 additions & 11 deletions drivers/media/video/ivtv/ivtv-streams.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
if (s->v4l2dev == NULL)
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);

switch (s->type) {
Expand Down Expand Up @@ -487,6 +490,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
0, sizeof(itv->vbi.sliced_mpeg_size));
break;
default:
mutex_unlock(&itv->serialize_lock);
return -EINVAL;
}
s->subtype = subtype;
Expand Down Expand Up @@ -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))
{
IVTV_DEBUG_WARN( "Error starting capture!\n");
mutex_unlock(&itv->serialize_lock);
return -EINVAL;
}

Expand All @@ -583,6 +588,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)

/* you're live! sit back and await interrupts :) */
atomic_inc(&itv->capturing);
mutex_unlock(&itv->serialize_lock);
return 0;
}

Expand Down Expand Up @@ -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 */
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;

if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
Expand Down Expand Up @@ -840,17 +835,30 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* Clear capture and no-read bits */
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)
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);

if (atomic_read(&itv->capturing) > 0) {
mutex_unlock(&itv->serialize_lock);
return 0;
}

/* Set the following Interrupt mask bits for 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);
mutex_unlock(&itv->serialize_lock);

return 0;
}
Expand Down

0 comments on commit f885969

Please sign in to comment.