diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2007-07-10 13:58:33 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-07-18 13:24:47 -0400 |
commit | f885969196da6ae905162c0d1c5f0553de12cb40 (patch) | |
tree | 3d23cbba88366834d05d8b6a63c6889caf789b37 /drivers/media | |
parent | 0901973f4bde9c1004795c9c2321bdc51f3996f1 (diff) |
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>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-driver.c | 1 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-driver.h | 1 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-streams.c | 30 |
3 files changed, 21 insertions, 11 deletions
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 28a53c42020d..ab7c3f6d3531 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c | |||
@@ -623,6 +623,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) | |||
623 | itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ | 623 | itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */ |
624 | itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ | 624 | itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */ |
625 | 625 | ||
626 | mutex_init(&itv->serialize_lock); | ||
626 | mutex_init(&itv->i2c_bus_lock); | 627 | mutex_init(&itv->i2c_bus_lock); |
627 | mutex_init(&itv->udma.lock); | 628 | mutex_init(&itv->udma.lock); |
628 | 629 | ||
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h index 48afd4270cbf..65ebddab3fe1 100644 --- a/drivers/media/video/ivtv/ivtv-driver.h +++ b/drivers/media/video/ivtv/ivtv-driver.h | |||
@@ -722,6 +722,7 @@ struct ivtv { | |||
722 | int search_pack_header; | 722 | int search_pack_header; |
723 | 723 | ||
724 | spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ | 724 | spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ |
725 | struct mutex serialize_lock; /* lock used to serialize starting streams */ | ||
725 | 726 | ||
726 | /* User based DMA for OSD */ | 727 | /* User based DMA for OSD */ |
727 | struct ivtv_user_dma udma; | 728 | struct ivtv_user_dma udma; |
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c index 6af88ae9295f..d538efaf61c9 100644 --- a/drivers/media/video/ivtv/ivtv-streams.c +++ b/drivers/media/video/ivtv/ivtv-streams.c | |||
@@ -446,6 +446,9 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) | |||
446 | if (s->v4l2dev == NULL) | 446 | if (s->v4l2dev == NULL) |
447 | return -EINVAL; | 447 | return -EINVAL; |
448 | 448 | ||
449 | /* Big serialization lock to ensure no two streams are started | ||
450 | simultaneously: that can give all sorts of weird results. */ | ||
451 | mutex_lock(&itv->serialize_lock); | ||
449 | IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); | 452 | IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name); |
450 | 453 | ||
451 | switch (s->type) { | 454 | switch (s->type) { |
@@ -487,6 +490,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) | |||
487 | 0, sizeof(itv->vbi.sliced_mpeg_size)); | 490 | 0, sizeof(itv->vbi.sliced_mpeg_size)); |
488 | break; | 491 | break; |
489 | default: | 492 | default: |
493 | mutex_unlock(&itv->serialize_lock); | ||
490 | return -EINVAL; | 494 | return -EINVAL; |
491 | } | 495 | } |
492 | s->subtype = subtype; | 496 | s->subtype = subtype; |
@@ -568,6 +572,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) | |||
568 | if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) | 572 | if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype)) |
569 | { | 573 | { |
570 | IVTV_DEBUG_WARN( "Error starting capture!\n"); | 574 | IVTV_DEBUG_WARN( "Error starting capture!\n"); |
575 | mutex_unlock(&itv->serialize_lock); | ||
571 | return -EINVAL; | 576 | return -EINVAL; |
572 | } | 577 | } |
573 | 578 | ||
@@ -583,6 +588,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s) | |||
583 | 588 | ||
584 | /* you're live! sit back and await interrupts :) */ | 589 | /* you're live! sit back and await interrupts :) */ |
585 | atomic_inc(&itv->capturing); | 590 | atomic_inc(&itv->capturing); |
591 | mutex_unlock(&itv->serialize_lock); | ||
586 | return 0; | 592 | return 0; |
587 | } | 593 | } |
588 | 594 | ||
@@ -762,17 +768,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end) | |||
762 | /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ | 768 | /* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */ |
763 | ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); | 769 | ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype); |
764 | 770 | ||
765 | /* only run these if we're shutting down the last cap */ | ||
766 | if (atomic_read(&itv->capturing) - 1 == 0) { | ||
767 | /* event notification (off) */ | ||
768 | if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { | ||
769 | /* type: 0 = refresh */ | ||
770 | /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ | ||
771 | ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); | ||
772 | ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); | ||
773 | } | ||
774 | } | ||
775 | |||
776 | then = jiffies; | 771 | then = jiffies; |
777 | 772 | ||
778 | if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) { | 773 | 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 | /* Clear capture and no-read bits */ | 835 | /* Clear capture and no-read bits */ |
841 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); | 836 | clear_bit(IVTV_F_S_STREAMING, &s->s_flags); |
842 | 837 | ||
838 | /* ensure these global cleanup actions are done only once */ | ||
839 | mutex_lock(&itv->serialize_lock); | ||
840 | |||
843 | if (s->type == IVTV_ENC_STREAM_TYPE_VBI) | 841 | if (s->type == IVTV_ENC_STREAM_TYPE_VBI) |
844 | ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); | 842 | ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP); |
845 | 843 | ||
846 | if (atomic_read(&itv->capturing) > 0) { | 844 | if (atomic_read(&itv->capturing) > 0) { |
845 | mutex_unlock(&itv->serialize_lock); | ||
847 | return 0; | 846 | return 0; |
848 | } | 847 | } |
849 | 848 | ||
850 | /* Set the following Interrupt mask bits for capture */ | 849 | /* Set the following Interrupt mask bits for capture */ |
851 | ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); | 850 | ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE); |
852 | 851 | ||
852 | /* event notification (off) */ | ||
853 | if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) { | ||
854 | /* type: 0 = refresh */ | ||
855 | /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */ | ||
856 | ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1); | ||
857 | ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST); | ||
858 | } | ||
859 | |||
853 | wake_up(&s->waitq); | 860 | wake_up(&s->waitq); |
861 | mutex_unlock(&itv->serialize_lock); | ||
854 | 862 | ||
855 | return 0; | 863 | return 0; |
856 | } | 864 | } |