V4L/DVB: ivtv: Avoid hard system lock on decoder output mode change
authorIan Armstrong <ian@iarmst.demon.co.uk>
Sat, 13 Mar 2010 23:22:34 +0000 (20:22 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 18 May 2010 03:47:15 +0000 (00:47 -0300)
Changing the decoder video standard just prior to, or during, the output of
the lower field may result in a hard system lock. To avoid this, try to ensure
the firmware call occurs only during the first 100 lines of the top field.

(Minor comment addition and a line break added Andy Walls <awalls@radix.net>.)

Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk>
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-ioctl.c

index 9a250548be4d2edec3f912a911289c92bd517320..1b79475ca134db7797c3ea95075a9fdfec61f983 100644 (file)
@@ -1293,7 +1293,6 @@ int ivtv_init_on_first_open(struct ivtv *itv)
                ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_stream, 1);
                ivtv_init_mpeg_decoder(itv);
        }
-       ivtv_s_std(NULL, &fh, &itv->tuner_std);
 
        /* On a cx23416 this seems to be able to enable DMA to the chip? */
        if (!itv->has_cx23415)
@@ -1310,6 +1309,10 @@ int ivtv_init_on_first_open(struct ivtv *itv)
        }
        else
                ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
+
+       /* For cards with video out, this call needs interrupts enabled */
+       ivtv_s_std(NULL, &fh, &itv->tuner_std);
+
        return 0;
 }
 
index 99f3c39a118b428ea04e4878f3c58a0ebc5da52d..2192bc42c6b6a543c5458e445c7f2b63b6e96984 100644 (file)
@@ -1087,8 +1087,10 @@ static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
 
 int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
 {
+       DEFINE_WAIT(wait);
        struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
        struct yuv_playback_info *yi = &itv->yuv_info;
+       int f;
 
        if ((*std & V4L2_STD_ALL) == 0)
                return -EINVAL;
@@ -1128,6 +1130,25 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
                itv->is_out_60hz = itv->is_60hz;
                itv->is_out_50hz = itv->is_50hz;
                ivtv_call_all(itv, video, s_std_output, itv->std_out);
+
+               /*
+                * The next firmware call is time sensitive. Time it to
+                * avoid risk of a hard lock, by trying to ensure the call
+                * happens within the first 100 lines of the top field.
+                * Make 4 attempts to sync to the decoder before giving up.
+                */
+               for (f = 0; f < 4; f++) {
+                       prepare_to_wait(&itv->vsync_waitq, &wait,
+                                       TASK_UNINTERRUPTIBLE);
+                       if ((read_reg(0x28c0) >> 16) < 100)
+                               break;
+                       schedule_timeout(msecs_to_jiffies(25));
+               }
+               finish_wait(&itv->vsync_waitq, &wait);
+
+               if (f == 4)
+                       IVTV_WARN("Mode change failed to sync to decoder\n");
+
                ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
                itv->main_rect.left = itv->main_rect.top = 0;
                itv->main_rect.width = 720;