Attached are two new patches: it turned out that an extra wait was
necessary, otherwise flickering could still occur even though
INITIALIZE_INPUT would no longer freeze.
Regards,
Hans
On Saturday 28 July 2007 12:30, Hans Verkuil wrote:
> Hi all,
>
> There have been various bug reports lately regarding freezing of the
> PC when starting a capture or when changing channels.
>
> I've been stress testing this yesterday and today and I believe I
> have found and fixed the problem. And as an additional bonus I
> believe that this patch also fixes the bug that sometimes occurs
> where the top third of the captured screen is continuously
> flickering.
>
> I've attached two patches: ivtv-0.10.diff is against ivtv-0.10 and
> ivtv.diff is against the http://www.linuxtv.org/hg/~hverkuil/v4l-dvb
> repository (for kernels >= 2.6.22).
>
> These patches also make an important change in the behavior of the
> driver: if a capture is in progress, then it is no longer possible to
> change inputs or open the radio device. EBUSY is returned as an
> error.
>
> The underlying problem was the use of the
> CX2341X_ENC_INITIALIZE_INPUT firmware call. This call should be made
> whenever the digitizer (saa7115 or cx25840) has changed, either
> because the TV standard was changed, another input was chosen or the
> video format changes (e.g. capture size, VBI settings). But it turned
> out that the digitizer has to be turned off before calling this API
> and turned on afterwards. This is definitely the case for the
> saa7115, the cx25840 seems to be more forgiving.
>
> If the digitizer is NOT turned off, then this FW call can sometimes
> freeze your PC: it looks like the MPEG card crashes and freezes the
> PCI bus. Any PCI access simply freezes everything.
>
> The problem was that CX2341X_ENC_INITIALIZE_INPUT was called on every
> channel change, even though there was no need to call it at that
> time. So this call was removed.
>
> The CX2341X_ENC_INITIALIZE_INPUT was also called on the start of a
> capture and ensures that the MPEG encoder has the correct digitizer
> settings. If this is not called, then flickering may occur.
>
> Opening the radio device or changing input also requires a call to
> CX2341X_ENC_INITIALIZE_INPUT. However, testing showed that this call
> doesn't do anything when a capture is in progress, hence the new
> requirement that the radio device or changing inputs can only be done
> when no capture is running. Otherwise, changing inputs in midstream
> can cause flickering.
>
> While running a stress test app I also noticed that when recordings
> are stopped and started in quick succession the start of the capture
> can sometimes be garbled. It is actually a left-over from the
> previous capture. It turns out that stopping the capture needs to
> wait a bit (100 ms is enough) to make sure the last pending
> interrupts are handled. This actually makes for simpler code and
> works very well.
>
> Please test this patch, whether or not you have these problems. I'd
> like to get some feedback on this!
>
> Thanks,
>
> Hans
>
> The CX2341X_ENC_INITIALIZE_INPUT firmware call is very important
Index: ivtv-ioctl.c
===================================================================
--- ivtv-ioctl.c (revision 3935)
+++ ivtv-ioctl.c (working copy)
@@ -784,6 +784,9 @@
IVTV_DEBUG_INFO("Input unchanged\n");
break;
}
+ if (atomic_read(&itv->capturing) > 0) {
+ return -EBUSY;
+ }
IVTV_DEBUG_INFO("Changing input from %d to %d\n",
itv->active_input, inp);
Index: ivtv-streams.c
===================================================================
--- ivtv-streams.c (revision 3935)
+++ ivtv-streams.c (working copy)
@@ -557,9 +557,10 @@
clear_bit(IVTV_F_I_EOS, &itv->i_flags);
/* Initialize Digitizer for Capture */
+ itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
+ ivtv_sleep_timeout(HZ / 20, 1);
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- ivtv_sleep_timeout(HZ / 10, 0);
+ itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
}
/* begin_capture */
@@ -723,7 +724,6 @@
int cap_type;
unsigned long then;
int stopmode;
- u32 data[CX2341X_MBOX_MAX_DATA];
if (s->v4l2dev == NULL)
return -EINVAL;
@@ -802,29 +802,9 @@
}
then = jiffies;
- /* Make sure DMA is complete */
- add_wait_queue(&s->waitq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- do {
- /* check if DMA is pending */
- if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */
- (read_reg(IVTV_REG_DMASTATUS) & 0x02)) {
- /* Check for last DMA */
- ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0);
- if (data[0] == 1) {
- IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]);
- break;
- }
- } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
- break;
- }
-
- ivtv_sleep_timeout(HZ / 100, 1);
- } while (then + HZ * 2 > jiffies);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->waitq, &wait);
+ /* Handle any pending interrupts */
+ ivtv_sleep_timeout(HZ / 10, 1);
}
atomic_dec(&itv->capturing);
Index: ivtv-fileops.c
===================================================================
--- ivtv-fileops.c (revision 3935)
+++ ivtv-fileops.c (working copy)
@@ -816,12 +816,20 @@
return -EBUSY;
}
+ if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+ if (atomic_read(&itv->capturing) > 0) {
+ /* switching to radio while capture is
+ in progress is not polite */
+ kfree(item);
+ return -EBUSY;
+ }
+ }
+ /* Mark that the radio is being used. */
+ set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* We have the radio */
ivtv_mute(itv);
/* Switch tuner to radio */
ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
- /* Mark that the radio is being used. */
- set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* Select the correct audio input (i.e. radio tuner) */
ivtv_audio_set_io(itv);
if (itv->hw_flags & IVTV_HW_SAA711X)
@@ -863,13 +871,8 @@
{
struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 };
- /* initialize or refresh input */
- if (atomic_read(&itv->capturing) == 0)
- ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- ivtv_sleep_timeout(HZ / 10, 0);
-
if (atomic_read(&itv->capturing)) {
+ ivtv_sleep_timeout(HZ / 10, 0);
ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
}
diff -r c392ac29add0 linux/drivers/media/video/ivtv/ivtv-fileops.c
--- a/linux/drivers/media/video/ivtv/ivtv-fileops.c Wed Jul 25 23:02:03 2007 +0200
+++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c Sat Jul 28 13:18:59 2007 +0200
@@ -888,12 +888,20 @@ int ivtv_v4l2_open(struct inode *inode,
return -EBUSY;
}
+ if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+ if (atomic_read(&itv->capturing) > 0) {
+ /* switching to radio while capture is
+ in progress is not polite */
+ kfree(item);
+ return -EBUSY;
+ }
+ }
+ /* Mark that the radio is being used. */
+ set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* We have the radio */
ivtv_mute(itv);
/* Switch tuner to radio */
ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
- /* Mark that the radio is being used. */
- set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* Select the correct audio input (i.e. radio tuner) */
ivtv_audio_set_io(itv);
if (itv->hw_flags & IVTV_HW_SAA711X)
@@ -935,13 +943,8 @@ void ivtv_unmute(struct ivtv *itv)
{
struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 };
- /* initialize or refresh input */
- if (atomic_read(&itv->capturing) == 0)
- ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- ivtv_msleep_timeout(100, 0);
-
if (atomic_read(&itv->capturing)) {
+ ivtv_msleep_timeout(100, 0);
ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
}
diff -r c392ac29add0 linux/drivers/media/video/ivtv/ivtv-ioctl.c
--- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c Wed Jul 25 23:02:03 2007 +0200
+++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c Sat Jul 28 13:18:59 2007 +0200
@@ -903,6 +903,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, s
if (inp == itv->active_input) {
IVTV_DEBUG_INFO("Input unchanged\n");
break;
+ }
+ if (atomic_read(&itv->capturing) > 0) {
+ return -EBUSY;
}
IVTV_DEBUG_INFO("Changing input from %d to %d\n",
itv->active_input, inp);
diff -r c392ac29add0 linux/drivers/media/video/ivtv/ivtv-streams.c
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c Wed Jul 25 23:02:03 2007 +0200
+++ b/linux/drivers/media/video/ivtv/ivtv-streams.c Sat Jul 28 13:18:59 2007 +0200
@@ -554,9 +554,10 @@ int ivtv_start_v4l2_encode_stream(struct
clear_bit(IVTV_F_I_EOS, &itv->i_flags);
/* Initialize Digitizer for Capture */
+ itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
+ ivtv_msleep_timeout(50, 1);
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
- ivtv_msleep_timeout(100, 0);
+ itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
}
/* begin_capture */
@@ -713,7 +714,6 @@ int ivtv_stop_v4l2_encode_stream(struct
int cap_type;
unsigned long then;
int stopmode;
- u32 data[CX2341X_MBOX_MAX_DATA];
if (s->v4l2dev == NULL)
return -EINVAL;
@@ -793,27 +793,9 @@ int ivtv_stop_v4l2_encode_stream(struct
}
then = jiffies;
- /* Make sure DMA is complete */
- add_wait_queue(&s->waitq, &wait);
- do {
- /* check if DMA is pending */
- if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */
- (read_reg(IVTV_REG_DMASTATUS) & 0x02)) {
- /* Check for last DMA */
- ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0);
-
- if (data[0] == 1) {
- IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]);
- break;
- }
- } else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
- break;
- }
- } while (!ivtv_msleep_timeout(10, 1) &&
- then + msecs_to_jiffies(2000) > jiffies);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->waitq, &wait);
+
+ /* Handle any pending interrupts */
+ ivtv_msleep_timeout(100, 1);
}
atomic_dec(&itv->capturing);
_______________________________________________
ivtv-devel mailing list
[email protected]
http://ivtvdriver.org/mailman/listinfo/ivtv-devel