aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18/cx18-driver.c')
-rw-r--r--drivers/media/video/cx18/cx18-driver.c100
1 files changed, 75 insertions, 25 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 49b1c3d7b1a8..92026e82e10e 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -30,6 +30,7 @@
30#include "cx18-irq.h" 30#include "cx18-irq.h"
31#include "cx18-gpio.h" 31#include "cx18-gpio.h"
32#include "cx18-firmware.h" 32#include "cx18-firmware.h"
33#include "cx18-queue.h"
33#include "cx18-streams.h" 34#include "cx18-streams.h"
34#include "cx18-av-core.h" 35#include "cx18-av-core.h"
35#include "cx18-scb.h" 36#include "cx18-scb.h"
@@ -151,7 +152,8 @@ MODULE_PARM_DESC(cardtype,
151 "\t\t\t 4 = Yuan MPC718\n" 152 "\t\t\t 4 = Yuan MPC718\n"
152 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" 153 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
153 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" 154 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
154 "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n" 155 "\t\t\t 7 = Leadtek WinFast PVR2100\n"
156 "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
155 "\t\t\t 0 = Autodetect (default)\n" 157 "\t\t\t 0 = Autodetect (default)\n"
156 "\t\t\t-1 = Ignore this card\n\t\t"); 158 "\t\t\t-1 = Ignore this card\n\t\t");
157MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); 159MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -312,7 +314,7 @@ static void cx18_process_eeprom(struct cx18 *cx)
312 CX18_INFO("Autodetected %s\n", cx->card_name); 314 CX18_INFO("Autodetected %s\n", cx->card_name);
313 315
314 if (tv.tuner_type == TUNER_ABSENT) 316 if (tv.tuner_type == TUNER_ABSENT)
315 CX18_ERR("tveeprom cannot autodetect tuner!"); 317 CX18_ERR("tveeprom cannot autodetect tuner!\n");
316 318
317 if (cx->options.tuner == -1) 319 if (cx->options.tuner == -1)
318 cx->options.tuner = tv.tuner_type; 320 cx->options.tuner = tv.tuner_type;
@@ -546,6 +548,40 @@ done:
546 cx->card_i2c = cx->card->i2c; 548 cx->card_i2c = cx->card->i2c;
547} 549}
548 550
551static int __devinit cx18_create_in_workq(struct cx18 *cx)
552{
553 snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
554 cx->v4l2_dev.name);
555 cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name);
556 if (cx->in_work_queue == NULL) {
557 CX18_ERR("Unable to create incoming mailbox handler thread\n");
558 return -ENOMEM;
559 }
560 return 0;
561}
562
563static int __devinit cx18_create_out_workq(struct cx18 *cx)
564{
565 snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out",
566 cx->v4l2_dev.name);
567 cx->out_work_queue = create_workqueue(cx->out_workq_name);
568 if (cx->out_work_queue == NULL) {
569 CX18_ERR("Unable to create outgoing mailbox handler threads\n");
570 return -ENOMEM;
571 }
572 return 0;
573}
574
575static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
576{
577 int i;
578 for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
579 cx->in_work_order[i].cx = cx;
580 cx->in_work_order[i].str = cx->epu_debug_str;
581 INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
582 }
583}
584
549/* Precondition: the cx18 structure has been memset to 0. Only 585/* Precondition: the cx18 structure has been memset to 0. Only
550 the dev and instance fields have been filled in. 586 the dev and instance fields have been filled in.
551 No assumptions on the card type may be made here (see cx18_init_struct2 587 No assumptions on the card type may be made here (see cx18_init_struct2
@@ -553,7 +589,7 @@ done:
553 */ 589 */
554static int __devinit cx18_init_struct1(struct cx18 *cx) 590static int __devinit cx18_init_struct1(struct cx18 *cx)
555{ 591{
556 int i; 592 int ret;
557 593
558 cx->base_addr = pci_resource_start(cx->pci_dev, 0); 594 cx->base_addr = pci_resource_start(cx->pci_dev, 0);
559 595
@@ -562,18 +598,18 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
562 mutex_init(&cx->epu2apu_mb_lock); 598 mutex_init(&cx->epu2apu_mb_lock);
563 mutex_init(&cx->epu2cpu_mb_lock); 599 mutex_init(&cx->epu2cpu_mb_lock);
564 600
565 cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name); 601 ret = cx18_create_out_workq(cx);
566 if (cx->work_queue == NULL) { 602 if (ret)
567 CX18_ERR("Unable to create work hander thread\n"); 603 return ret;
568 return -ENOMEM;
569 }
570 604
571 for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) { 605 ret = cx18_create_in_workq(cx);
572 cx->epu_work_order[i].cx = cx; 606 if (ret) {
573 cx->epu_work_order[i].str = cx->epu_debug_str; 607 destroy_workqueue(cx->out_work_queue);
574 INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler); 608 return ret;
575 } 609 }
576 610
611 cx18_init_in_work_orders(cx);
612
577 /* start counting open_id at 1 */ 613 /* start counting open_id at 1 */
578 cx->open_id = 1; 614 cx->open_id = 1;
579 615
@@ -759,17 +795,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
759 retval = -ENODEV; 795 retval = -ENODEV;
760 goto err; 796 goto err;
761 } 797 }
762 if (cx18_init_struct1(cx)) { 798
763 retval = -ENOMEM; 799 retval = cx18_init_struct1(cx);
800 if (retval)
764 goto err; 801 goto err;
765 }
766 802
767 CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); 803 CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
768 804
769 /* PCI Device Setup */ 805 /* PCI Device Setup */
770 retval = cx18_setup_pci(cx, pci_dev, pci_id); 806 retval = cx18_setup_pci(cx, pci_dev, pci_id);
771 if (retval != 0) 807 if (retval != 0)
772 goto free_workqueue; 808 goto free_workqueues;
773 809
774 /* map io memory */ 810 /* map io memory */
775 CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", 811 CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -943,8 +979,9 @@ free_map:
943 cx18_iounmap(cx); 979 cx18_iounmap(cx);
944free_mem: 980free_mem:
945 release_mem_region(cx->base_addr, CX18_MEM_SIZE); 981 release_mem_region(cx->base_addr, CX18_MEM_SIZE);
946free_workqueue: 982free_workqueues:
947 destroy_workqueue(cx->work_queue); 983 destroy_workqueue(cx->in_work_queue);
984 destroy_workqueue(cx->out_work_queue);
948err: 985err:
949 if (retval == 0) 986 if (retval == 0)
950 retval = -ENODEV; 987 retval = -ENODEV;
@@ -1053,11 +1090,19 @@ int cx18_init_on_first_open(struct cx18 *cx)
1053 return 0; 1090 return 0;
1054} 1091}
1055 1092
1056static void cx18_cancel_epu_work_orders(struct cx18 *cx) 1093static void cx18_cancel_in_work_orders(struct cx18 *cx)
1057{ 1094{
1058 int i; 1095 int i;
1059 for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) 1096 for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
1060 cancel_work_sync(&cx->epu_work_order[i].work); 1097 cancel_work_sync(&cx->in_work_order[i].work);
1098}
1099
1100static void cx18_cancel_out_work_orders(struct cx18 *cx)
1101{
1102 int i;
1103 for (i = 0; i < CX18_MAX_STREAMS; i++)
1104 if (&cx->streams[i].video_dev != NULL)
1105 cancel_work_sync(&cx->streams[i].out_work_order);
1061} 1106}
1062 1107
1063static void cx18_remove(struct pci_dev *pci_dev) 1108static void cx18_remove(struct pci_dev *pci_dev)
@@ -1073,15 +1118,20 @@ static void cx18_remove(struct pci_dev *pci_dev)
1073 if (atomic_read(&cx->tot_capturing) > 0) 1118 if (atomic_read(&cx->tot_capturing) > 0)
1074 cx18_stop_all_captures(cx); 1119 cx18_stop_all_captures(cx);
1075 1120
1076 /* Interrupts */ 1121 /* Stop interrupts that cause incoming work to be queued */
1077 cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); 1122 cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
1123
1124 /* Incoming work can cause outgoing work, so clean up incoming first */
1125 cx18_cancel_in_work_orders(cx);
1126 cx18_cancel_out_work_orders(cx);
1127
1128 /* Stop ack interrupts that may have been needed for work to finish */
1078 cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); 1129 cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
1079 1130
1080 cx18_halt_firmware(cx); 1131 cx18_halt_firmware(cx);
1081 1132
1082 cx18_cancel_epu_work_orders(cx); 1133 destroy_workqueue(cx->in_work_queue);
1083 1134 destroy_workqueue(cx->out_work_queue);
1084 destroy_workqueue(cx->work_queue);
1085 1135
1086 cx18_streams_cleanup(cx, 1); 1136 cx18_streams_cleanup(cx, 1);
1087 1137