Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

V4L/DVB (9166): ivtv - Fix potential race condition in yuv handler

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>

authored by

Ian Armstrong and committed by
Mauro Carvalho Chehab
2bd7ac55 ec9faa1c

+9 -5
+2
drivers/media/video/ivtv/ivtv-driver.h
··· 506 506 struct v4l2_rect main_rect; 507 507 u32 v4l2_src_w; 508 508 u32 v4l2_src_h; 509 + 510 + u8 running; /* Have any frames been displayed */ 509 511 }; 510 512 511 513 #define IVTV_VBI_FRAMES 32
-2
drivers/media/video/ivtv/ivtv-ioctl.c
··· 644 644 itv->dma_data_req_size = 645 645 1080 * ((yi->v4l2_src_h + 31) & ~31); 646 646 647 - /* Force update of yuv registers */ 648 - yi->yuv_forced_update = 1; 649 647 return 0; 650 648 } 651 649
+6 -3
drivers/media/video/ivtv/ivtv-irq.c
··· 753 753 */ 754 754 unsigned int frame = read_reg(0x28c0) & 1; 755 755 struct yuv_playback_info *yi = &itv->yuv_info; 756 - int last_dma_frame = atomic_read(&itv->yuv_info.next_dma_frame); 756 + int last_dma_frame = atomic_read(&yi->next_dma_frame); 757 757 struct yuv_frame_info *f = &yi->new_frame_info[last_dma_frame]; 758 758 759 759 if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n"); ··· 772 772 next_dma_frame = (next_dma_frame + 1) % IVTV_YUV_BUFFERS; 773 773 atomic_set(&yi->next_dma_frame, next_dma_frame); 774 774 yi->fields_lapsed = -1; 775 + yi->running = 1; 775 776 } 776 777 } 777 778 } ··· 805 804 } 806 805 807 806 /* Check if we need to update the yuv registers */ 808 - if ((yi->yuv_forced_update || f->update) && last_dma_frame != -1) { 807 + if (yi->running && (yi->yuv_forced_update || f->update)) { 809 808 if (!f->update) { 810 - last_dma_frame = (u8)(last_dma_frame - 1) % IVTV_YUV_BUFFERS; 809 + last_dma_frame = 810 + (u8)(atomic_read(&yi->next_dma_frame) - 811 + 1) % IVTV_YUV_BUFFERS; 811 812 f = &yi->new_frame_info[last_dma_frame]; 812 813 } 813 814
+1
drivers/media/video/ivtv/ivtv-yuv.c
··· 1147 1147 IVTV_DEBUG_YUV("ivtv_yuv_close\n"); 1148 1148 ivtv_waitq(&itv->vsync_waitq); 1149 1149 1150 + yi->running = 0; 1150 1151 atomic_set(&yi->next_dma_frame, -1); 1151 1152 atomic_set(&yi->next_fill_frame, 0); 1152 1153