V4L/DVB (5404): Merges VBI & YUV handling into a single work queue.

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@infradead.org>
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 162a1e8..ad0c162 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -628,21 +628,13 @@
 	itv->lock = SPIN_LOCK_UNLOCKED;
 	itv->dma_reg_lock = SPIN_LOCK_UNLOCKED;
 
-	itv->vbi.work_queues = create_workqueue("ivtv_vbi");
-	if (itv->vbi.work_queues == NULL) {
-		IVTV_ERR("Could not create VBI workqueue\n");
+	itv->irq_work_queues = create_workqueue(itv->name);
+	if (itv->irq_work_queues == NULL) {
+		IVTV_ERR("Could not create ivtv workqueue\n");
 		return -1;
 	}
 
-	itv->yuv_info.work_queues = create_workqueue("ivtv_yuv");
-	if (itv->yuv_info.work_queues == NULL) {
-		IVTV_ERR("Could not create YUV workqueue\n");
-		destroy_workqueue(itv->vbi.work_queues);
-		return -1;
-	}
-
-	INIT_WORK(&itv->vbi.work_queue, vbi_work_handler);
-	INIT_WORK(&itv->yuv_info.work_queue, ivtv_yuv_work_handler);
+	INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler);
 
 	/* start counting open_id at 1 */
 	itv->open_id = 1;
@@ -1241,8 +1233,7 @@
 	if (itv->has_cx23415)
 		release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
       free_workqueue:
-	destroy_workqueue(itv->vbi.work_queues);
-	destroy_workqueue(itv->yuv_info.work_queues);
+	destroy_workqueue(itv->irq_work_queues);
       err:
 	if (retval == 0)
 		retval = -ENODEV;
@@ -1284,10 +1275,8 @@
 
 	/* Stop all Work Queues */
 	IVTV_DEBUG_INFO(" Stop Work Queues.\n");
-	flush_workqueue(itv->vbi.work_queues);
-	flush_workqueue(itv->yuv_info.work_queues);
-	destroy_workqueue(itv->vbi.work_queues);
-	destroy_workqueue(itv->yuv_info.work_queues);
+	flush_workqueue(itv->irq_work_queues);
+	destroy_workqueue(itv->irq_work_queues);
 
 	IVTV_DEBUG_INFO(" Stopping Firmware.\n");
 	ivtv_halt_firmware(itv);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 236e353..1b2f7a6 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -383,28 +383,29 @@
 #define IVTV_F_S_APPL_IO        8	/* this stream is used read/written by an application */
 
 /* per-ivtv, i_flags */
-#define IVTV_F_I_DMA		0 	/* DMA in progress */
-#define IVTV_F_I_UDMA		1 	/* UDMA in progress */
-#define IVTV_F_I_UDMA_PENDING	2 	/* UDMA pending */
-
-#define IVTV_F_I_SPEED_CHANGE	3 	/* A speed change is in progress */
-#define IVTV_F_I_EOS		4 	/* End of encoder stream reached */
-#define IVTV_F_I_RADIO_USER	5 	/* The radio tuner is selected */
-#define IVTV_F_I_DIG_RST	6 	/* Reset digitizer */
-#define IVTV_F_I_DEC_YUV	7 	/* YUV instead of MPG is being decoded */
-#define IVTV_F_I_ENC_VBI	8 	/* VBI DMA */
-#define IVTV_F_I_UPDATE_CC	9  	/* CC should be updated */
-#define IVTV_F_I_UPDATE_WSS	10 	/* WSS should be updated */
-#define IVTV_F_I_UPDATE_VPS	11 	/* VPS should be updated */
-#define IVTV_F_I_DECODING_YUV	12 	/* this stream is YUV frame decoding */
-#define IVTV_F_I_ENC_PAUSED	13 	/* the encoder is paused */
+#define IVTV_F_I_DMA		   0 	/* DMA in progress */
+#define IVTV_F_I_UDMA		   1 	/* UDMA in progress */
+#define IVTV_F_I_UDMA_PENDING	   2 	/* UDMA pending */
+#define IVTV_F_I_SPEED_CHANGE	   3 	/* A speed change is in progress */
+#define IVTV_F_I_EOS		   4 	/* End of encoder stream reached */
+#define IVTV_F_I_RADIO_USER	   5 	/* The radio tuner is selected */
+#define IVTV_F_I_DIG_RST	   6 	/* Reset digitizer */
+#define IVTV_F_I_DEC_YUV	   7 	/* YUV instead of MPG is being decoded */
+#define IVTV_F_I_ENC_VBI	   8 	/* VBI DMA */
+#define IVTV_F_I_UPDATE_CC	   9  	/* CC should be updated */
+#define IVTV_F_I_UPDATE_WSS	   10 	/* WSS should be updated */
+#define IVTV_F_I_UPDATE_VPS	   11 	/* VPS should be updated */
+#define IVTV_F_I_DECODING_YUV	   12 	/* this stream is YUV frame decoding */
+#define IVTV_F_I_ENC_PAUSED	   13 	/* the encoder is paused */
 #define IVTV_F_I_VALID_DEC_TIMINGS 14 	/* last_dec_timing is valid */
+#define IVTV_F_I_WORK_HANDLER_VBI  15	/* there is work to be done for VBI */
+#define IVTV_F_I_WORK_HANDLER_YUV  16	/* there is work to be done for YUV */
 
 /* Event notifications */
-#define IVTV_F_I_EV_DEC_STOPPED	28	/* decoder stopped event */
-#define IVTV_F_I_EV_VSYNC	29 	/* VSYNC event */
-#define IVTV_F_I_EV_VSYNC_FIELD 30 	/* VSYNC event field (0 = first, 1 = second field) */
-#define IVTV_F_I_EV_VSYNC_ENABLED 31 	/* VSYNC event enabled */
+#define IVTV_F_I_EV_DEC_STOPPED	   28	/* decoder stopped event */
+#define IVTV_F_I_EV_VSYNC	   29 	/* VSYNC event */
+#define IVTV_F_I_EV_VSYNC_FIELD    30 	/* VSYNC event field (0 = first, 1 = second field) */
+#define IVTV_F_I_EV_VSYNC_ENABLED  31 	/* VSYNC event enabled */
 
 /* Scatter-Gather array element, used in DMA transfers */
 struct ivtv_SG_element {
@@ -612,8 +613,6 @@
 
 	u32 yuv_forced_update;
 	int update_frame;
-	struct workqueue_struct *work_queues;
-	struct work_struct work_queue;
 	struct yuv_frame_info new_frame_info[4];
 	struct yuv_frame_info old_frame_info;
 	struct yuv_frame_info old_frame_info_args;
@@ -676,8 +675,6 @@
 	struct ivtv_buffer sliced_mpeg_buf;
 	u32 inserted_frame;
 
-	struct workqueue_struct *work_queues;
-	struct work_struct work_queue;
 	u32 start[2], count;
 	u32 raw_size;
 	u32 sliced_size;
@@ -734,6 +731,9 @@
 
 	u32 base_addr;
 	u32 irqmask;
+
+	struct workqueue_struct *irq_work_queues;
+	struct work_struct irq_work_queue;
 	struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */
 
 	struct vbi_info vbi;
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 0656e18..c3a047b 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -27,6 +27,7 @@
 #include "ivtv-ioctl.h"
 #include "ivtv-mailbox.h"
 #include "ivtv-vbi.h"
+#include "ivtv-yuv.h"
 
 #define DMA_MAGIC_COOKIE 0x000001fe
 
@@ -49,6 +50,19 @@
 	    (SLICED_VBI_PIO && s->type == IVTV_ENC_STREAM_TYPE_VBI && itv->vbi.sliced_in->service_set);
 }
 
+void ivtv_irq_work_handler(struct work_struct *work)
+{
+	struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue);
+
+	DEFINE_WAIT(wait);
+
+	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags))
+		vbi_work_handler(itv);
+
+	if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags))
+		ivtv_yuv_work_handler(itv);
+}
+
 /* Determine the required DMA size, setup enough buffers in the predma queue and
    actually copy the data from the card to the buffers in case a PIO transfer is
    required for this stream.
@@ -643,6 +657,7 @@
 	}
 	if (frame != (itv->lastVsyncFrame & 1)) {
 		struct ivtv_stream *s = ivtv_get_output_stream(itv);
+		int work = 0;
 
 		itv->lastVsyncFrame += 1;
 		if (frame == 0) {
@@ -661,8 +676,10 @@
 			wake_up(&s->waitq);
 
 		/* Send VBI to saa7127 */
-		if (frame)
-			vbi_schedule_work(itv);
+		if (frame) {
+			set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
+			work = 1;
+		}
 
 		/* Check if we need to update the yuv registers */
 		if ((itv->yuv_info.yuv_forced_update || itv->yuv_info.new_frame_info[last_dma_frame].update) && last_dma_frame != -1) {
@@ -673,9 +690,12 @@
 				itv->yuv_info.update_frame = last_dma_frame;
 				itv->yuv_info.new_frame_info[last_dma_frame].update = 0;
 				itv->yuv_info.yuv_forced_update = 0;
-				queue_work(itv->yuv_info.work_queues, &itv->yuv_info.work_queue);
+				set_bit(IVTV_F_I_WORK_HANDLER_YUV, &itv->i_flags);
+				work = 1;
 			}
 		}
+		if (work)
+			queue_work(itv->irq_work_queues, &itv->irq_work_queue);
 	}
 }
 
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h
index ed96205..a43348a 100644
--- a/drivers/media/video/ivtv/ivtv-irq.h
+++ b/drivers/media/video/ivtv/ivtv-irq.h
@@ -20,5 +20,7 @@
  */
 
 irqreturn_t ivtv_irq_handler(int irq, void *dev_id);
+
+void ivtv_irq_work_handler(struct work_struct *work);
 void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
 void ivtv_unfinished_dma(unsigned long arg);
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index b53ca50..5efa5a8 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -32,11 +32,6 @@
 	return c & 1;
 }
 
-void vbi_schedule_work(struct ivtv *itv)
-{
-	queue_work(itv->vbi.work_queues, &itv->vbi.work_queue);
-}
-
 static void passthrough_vbi_data(struct ivtv *itv, int cnt)
 {
 	int wss = 0;
@@ -454,12 +449,10 @@
 	itv->vbi.cc_pos = 0;
 }
 
-void vbi_work_handler(struct work_struct *work)
+
+void vbi_work_handler(struct ivtv *itv)
 {
-	struct vbi_info *info = container_of(work, struct vbi_info, work_queue);
-	struct ivtv *itv = container_of(info, struct ivtv, vbi);
 	struct v4l2_sliced_vbi_data data;
-	DEFINE_WAIT(wait);
 
 	/* Lock */
 	if (itv->output_mode == OUT_PASSTHROUGH) {
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h
index c897e9b..cdaea69 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.h
+++ b/drivers/media/video/ivtv/ivtv-vbi.h
@@ -23,5 +23,4 @@
 int ivtv_used_line(struct ivtv *itv, int line, int field);
 void ivtv_disable_vbi(struct ivtv *itv);
 void ivtv_set_vbi(unsigned long arg);
-void vbi_work_handler(struct work_struct *work);
-void vbi_schedule_work(struct ivtv *itv);
+void vbi_work_handler(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index e49ecef..c962303 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -804,12 +804,8 @@
 }
 
 /* Update the scaling register to the requested value */
-void ivtv_yuv_work_handler (struct work_struct *work)
+void ivtv_yuv_work_handler (struct ivtv *itv)
 {
-	struct yuv_playback_info *info = container_of(work, struct yuv_playback_info, work_queue);
-	struct ivtv *itv = container_of(info, struct ivtv, yuv_info);
-	DEFINE_WAIT(wait);
-
 	struct yuv_frame_info window;
 	u32 yuv_update;
 
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
index 3112873..88972d3 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/drivers/media/video/ivtv/ivtv-yuv.h
@@ -21,4 +21,4 @@
 int ivtv_yuv_filter_check(struct ivtv *itv);
 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
 void ivtv_yuv_close(struct ivtv *itv);
-void ivtv_yuv_work_handler (struct work_struct *work);
+void ivtv_yuv_work_handler (struct ivtv *itv);