diff options
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-streams.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-streams.c | 30 |
1 files changed, 19 insertions, 11 deletions
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 | } |