V4L/DVB (9166): ivtv - Fix potential race condition in yuv handler
authorIan Armstrong <ian@iarmst.demon.co.uk>
Thu, 9 Oct 2008 15:04:23 +0000 (12:04 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 13 Oct 2008 11:08:30 +0000 (09:08 -0200)
Modified yuv register update handling to remove a potential race condition
which could occur with the first video frame.

Also removed a forced yuv position update, since changing the source video
dimensions or interlace settings doesn't affect the frame already being
displayed.

Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/ivtv/ivtv-driver.h
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/ivtv/ivtv-irq.c
drivers/media/video/ivtv/ivtv-yuv.c

index be2d779dba124cc126b7f3eb555bbb51dc0ccb8d..bc29436e8a3cd4c3acc93a3c62df8b884d88d478 100644 (file)
@@ -506,6 +506,8 @@ struct yuv_playback_info
        struct v4l2_rect main_rect;
        u32 v4l2_src_w;
        u32 v4l2_src_h;
+
+       u8 running; /* Have any frames been displayed */
 };
 
 #define IVTV_VBI_FRAMES 32
index 3c2628a63015a9c6450af416add96d3c548f8607..8696527ab134bfb6daaee2e49eb7911a5c0cbf44 100644 (file)
@@ -644,8 +644,6 @@ static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f
                itv->dma_data_req_size =
                        1080 * ((yi->v4l2_src_h + 31) & ~31);
 
-       /* Force update of yuv registers */
-       yi->yuv_forced_update = 1;
        return 0;
 }
 
index 34f3ab82785853634bc3c47deb7587d7590508d3..f5d00ec5da73501cb2b99ad93404b9b5dc63a881 100644 (file)
@@ -753,7 +753,7 @@ static void ivtv_irq_vsync(struct ivtv *itv)
         */
        unsigned int frame = read_reg(0x28c0) & 1;
        struct yuv_playback_info *yi = &itv->yuv_info;
-       int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame);
+       int last_dma_frame = atomic_read(&yi->next_dma_frame);
        struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame];
 
        if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
@@ -772,6 +772,7 @@ static void ivtv_irq_vsync(struct ivtv *itv)
                                next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS;
                                atomic_set(&yi->next_dma_frame, next_dma_frame);
                                yi->fields_lapsed = -1;
+                               yi->running = 1;
                        }
                }
        }
@@ -804,9 +805,11 @@ static void ivtv_irq_vsync(struct ivtv *itv)
                }
 
                /* Check if we need to update the yuv registers */
-               if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) {
+               if (yi->running && (yi->yuv_forced_update || f->update)) {
                        if (!f->update) {
-                               last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS;
+                               last_dma_frame =
+                                       (u8)(atomic_read(&yi->next_dma_frame) -
+                                                1) % IVTV_YUV_BUFFERS;
                                f = &yi->new_frame_info[last_dma_frame];
                        }
 
index 3092ff1d00a066a24a4d04b3de06f1999159a299..ee91107376c75440ca56f6620924724a2267c5ab 100644 (file)
@@ -1147,6 +1147,7 @@ void ivtv_yuv_close(struct ivtv *itv)
        IVTV_DEBUG_YUV("ivtv_yuv_close\n");
        ivtv_waitq(&itv->vsync_waitq);
 
+       yi->running = 0;
        atomic_set(&yi->next_dma_frame, -1);
        atomic_set(&yi->next_fill_frame, 0);