V4L/DVB (9721): cx18: Change to singlethreaded global work queue thread for deferable work

Change to singlethreaded global work queue thread for deferable work,
instead of the kernel default multithreaded work queue.  This ensures
execution of deferable work is always in the proper order, so caputred buffers
don't get reordered.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 434cc7f..752ca90 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -56,6 +56,9 @@
 /* Protects cx18_cards_active */
 DEFINE_SPINLOCK(cx18_cards_lock);
 
+/* Queue for deferrable IRQ handling work for all cx18 cards in system */
+struct workqueue_struct *cx18_work_queue;
+
 /* add your revision and whatnot here */
 static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
 	{PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
@@ -920,6 +923,13 @@
 	return 0;
 }
 
+static void cx18_cancel_epu_work_orders(struct cx18 *cx)
+{
+	int i;
+	for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++)
+		cancel_work_sync(&cx->epu_work_order[i].work);
+}
+
 static void cx18_remove(struct pci_dev *pci_dev)
 {
 	struct cx18 *cx = pci_get_drvdata(pci_dev);
@@ -937,7 +947,7 @@
 
 	cx18_halt_firmware(cx);
 
-	flush_scheduled_work();
+	cx18_cancel_epu_work_orders(cx);
 
 	cx18_streams_cleanup(cx, 1);
 
@@ -981,8 +991,17 @@
 		printk(KERN_INFO "cx18:   Debug value must be >= 0 and <= 511!\n");
 	}
 
+	cx18_work_queue = create_singlethread_workqueue("cx18");
+	if (cx18_work_queue == NULL) {
+		printk(KERN_ERR
+		       "cx18:   Unable to create work hander thread\n");
+		return -ENOMEM;
+	}
+
 	if (pci_register_driver(&cx18_pci_driver)) {
 		printk(KERN_ERR "cx18:   Error detecting PCI card\n");
+		destroy_workqueue(cx18_work_queue);
+		cx18_work_queue = NULL;
 		return -ENODEV;
 	}
 	printk(KERN_INFO "cx18:  End initialization\n");
@@ -995,11 +1014,15 @@
 
 	pci_unregister_driver(&cx18_pci_driver);
 
+	destroy_workqueue(cx18_work_queue);
+	cx18_work_queue = NULL;
+
 	for (i = 0; i < cx18_cards_active; i++) {
 		if (cx18_cards[i] == NULL)
 			continue;
 		kfree(cx18_cards[i]);
 	}
+
 }
 
 module_init(module_start);