V4L/DVB (6045): ivtv: fix handling of INITIALIZE_INPUT fw call
authorHans Verkuil <hverkuil@xs4all.nl>
Sat, 18 Aug 2007 14:46:05 +0000 (11:46 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 10 Oct 2007 01:05:31 +0000 (22:05 -0300)
The CX2341X_ENC_INITIALIZE_INPUT firmware call requires careful handling,
otherwise the computer can freeze or the top-third of the screen can start
flickering. This patch ensures that CX2341X_ENC_INITIALIZE_INPUT is called
at the right time and in the right way.

In addition the stop capture handling was improved so that the last pending
DMA transfer is also processed. Otherwise this would be the first data that
arrived when a new capture was started which is not what you want.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-streams.c

index 9e867b5229d19b583fa945020347ce5f2f72689e..908e640c274dc9f00318a761e78de6eb804dd363 100644 (file)
@@ -892,12 +892,20 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
                        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)
@@ -931,13 +939,8 @@ void ivtv_mute(struct ivtv *itv)
 
 void ivtv_unmute(struct ivtv *itv)
 {
-       /* 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);
        }
index cee6c558c69c6f3bdc6f4075fbf1da1ecccb6fa4..734f2d2ffa62dafe330be3619ca80b9ab4e0435e 100644 (file)
@@ -906,6 +906,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
                        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 405e2e3fcb4901427e8caed2e4a41119e9ae9cd3..0582b9d57c5594080191c9a437e1b5a16284923a 100644 (file)
@@ -554,9 +554,10 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
                clear_bit(IVTV_F_I_EOS, &itv->i_flags);
 
                /* Initialize Digitizer for Capture */
+               itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
+               ivtv_msleep_timeout(300, 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 ivtv_stream *s, int gop_end)
        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 ivtv_stream *s, int gop_end)
                }
 
                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);
This page took 0.031376 seconds and 5 git commands to generate.