aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx88/cx88-mpeg.c
diff options
context:
space:
mode:
authorSteven Toth <stoth@hauppauge.com>2006-12-02 18:15:51 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2006-12-10 05:50:47 -0500
commit6c5be74c86f102c2d4e123bc51d2fa93155fd794 (patch)
tree72bb1b00045f7c263721f113f92d286405ae96d7 /drivers/media/video/cx88/cx88-mpeg.c
parent91bb9be6ff4101652bb104f9f083f340e73ba6dd (diff)
V4L/DVB (4676): Dynamic cx88 mpeg port management for HVR1300 MPEG2/DVB-T support.
A series of patches to change the cx88 framework to allow the PCI mpeg port to be shared dynamically between different types of drivers or applications. This patch changes the cx88-dvb and cx88-blackbird drivers to become 'sub drivers' of a higher single cx88-mpeg driver. The cx88-mpeg driver is a superset of the previous cx88-mpeg/blackbird drivers and now owns the IRQ. cx88-dvb/blackbird now become mini drivers, registering themselves with cx88-mpeg through a standard interface with callbacks. Sub drivers request access to hardware via the cx88-mpeg driver. In turn the cx88-mpeg driver determines whether the hardware is busy and accepts or refuses the request, grant access using callbacks into the sub drivers. The net effect is that you are no longer able to tamper with the mpeg port from multiple different applications at the same time, potentially breaking a live mpeg2 hardware encoding or dvb stream. The mechanism extends to enable multiple dvb frontends to be registered and share the single resource. Signed-off-by: Steven Toth <stoth@hauppauge.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/cx88/cx88-mpeg.c')
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c344
1 files changed, 327 insertions, 17 deletions
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 6b23a4e6f66d..6f155713ee02 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -44,8 +44,12 @@ module_param(debug,int,0644);
44MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); 44MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
45 45
46#define dprintk(level,fmt, arg...) if (debug >= level) \ 46#define dprintk(level,fmt, arg...) if (debug >= level) \
47 printk(KERN_DEBUG "%s/2: " fmt, dev->core->name , ## arg) 47 printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg)
48 48
49#define mpeg_dbg(level,fmt, arg...) if (debug >= level) \
50 printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg)
51
52static LIST_HEAD(cx8802_devlist);
49/* ------------------------------------------------------------------ */ 53/* ------------------------------------------------------------------ */
50 54
51static int cx8802_start_dma(struct cx8802_dev *dev, 55static int cx8802_start_dma(struct cx8802_dev *dev,
@@ -65,17 +69,13 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
65 69
66 /* FIXME: this needs a review. 70 /* FIXME: this needs a review.
67 * also: move to cx88-blackbird + cx88-dvb source files? */ 71 * also: move to cx88-blackbird + cx88-dvb source files? */
68 if (cx88_boards[core->board].mpeg == (CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) ) {
69 /* Report a warning until the mini driver patch is applied,
70 * else the following conditions will set the dma registers incorrectly.
71 * This will be removed in the next major patch and changes to the conditions
72 * will be made.
73 */
74 printk(KERN_INFO "%s() board->(CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) is invalid\n", __FUNCTION__);
75 return -EINVAL;
76 }
77 72
78 if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) { 73 dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id);
74
75 if ( (core->active_type_id == CX88_MPEG_DVB) &&
76 (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) {
77
78 dprintk( 1, "cx8802_start_dma doing .dvb\n");
79 /* negedge driven & software reset */ 79 /* negedge driven & software reset */
80 cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); 80 cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
81 udelay(100); 81 udelay(100);
@@ -93,15 +93,17 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
93 cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ 93 cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */
94 udelay(100); 94 udelay(100);
95 break; 95 break;
96 case CX88_BOARD_HAUPPAUGE_HVR1300:
97 break;
96 default: 98 default:
97 cx_write(TS_SOP_STAT, 0x00); 99 cx_write(TS_SOP_STAT, 0x00);
98 break; 100 break;
99 } 101 }
100 cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); 102 cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
101 udelay(100); 103 udelay(100);
102 } 104 } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) &&
103 105 (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) {
104 if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) { 106 dprintk( 1, "cx8802_start_dma doing .blackbird\n");
105 cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ 107 cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
106 108
107 cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ 109 cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
@@ -112,6 +114,10 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
112 114
113 cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ 115 cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
114 udelay(100); 116 udelay(100);
117 } else {
118 printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
119 cx88_boards[core->board].mpeg );
120 return -EINVAL;
115 } 121 }
116 122
117 /* reset counter */ 123 /* reset counter */
@@ -542,8 +548,311 @@ int cx8802_resume_common(struct pci_dev *pci_dev)
542 return 0; 548 return 0;
543} 549}
544 550
551struct cx8802_dev * cx8802_get_device(struct inode *inode)
552{
553 int minor = iminor(inode);
554 struct cx8802_dev *h = NULL;
555 struct list_head *list;
556
557 list_for_each(list,&cx8802_devlist) {
558 h = list_entry(list, struct cx8802_dev, devlist);
559 if (h->mpeg_dev->minor == minor)
560 return h;
561 }
562
563 return NULL;
564}
565
566struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype)
567{
568 struct cx8802_dev *h = NULL;
569 struct cx8802_driver *d = NULL;
570 struct list_head *list;
571 struct list_head *list2;
572
573 list_for_each(list,&cx8802_devlist) {
574 h = list_entry(list, struct cx8802_dev, devlist);
575
576 list_for_each(list2, &h->drvlist.devlist) {
577 d = list_entry(list2, struct cx8802_driver, devlist);
578
579 /* only unregister the correct driver type */
580 if (d->type_id == btype) {
581 return d;
582 }
583 }
584 }
585
586 return NULL;
587}
588
589/* Driver asked for hardware access. */
590int cx8802_request_acquire(struct cx8802_driver *drv)
591{
592 struct cx88_core *core = drv->core;
593
594 /* Fail a request for hardware if the device is busy. */
595 if (core->active_type_id != CX88_BOARD_NONE)
596 return -EBUSY;
597
598 if (drv->advise_acquire)
599 {
600 core->active_type_id = drv->type_id;
601 drv->advise_acquire(drv);
602
603 mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
604 }
605
606 return 0;
607}
608
609/* Driver asked to release hardware. */
610int cx8802_request_release(struct cx8802_driver *drv)
611{
612 struct cx88_core *core = drv->core;
613
614 if (drv->advise_release)
615 {
616 drv->advise_release(drv);
617 core->active_type_id = CX88_BOARD_NONE;
618 mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
619 }
620
621 return 0;
622}
623
624static int cx8802_check_driver(struct cx8802_driver *drv)
625{
626 if (drv == NULL)
627 return -ENODEV;
628
629 if ((drv->type_id != CX88_MPEG_DVB) &&
630 (drv->type_id != CX88_MPEG_BLACKBIRD))
631 return -EINVAL;
632
633 if ((drv->hw_access != CX8802_DRVCTL_SHARED) &&
634 (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE))
635 return -EINVAL;
636
637 if ((drv->probe == NULL) ||
638 (drv->remove == NULL) ||
639 (drv->advise_acquire == NULL) ||
640 (drv->advise_release == NULL))
641 return -EINVAL;
642
643 return 0;
644}
645
646int cx8802_register_driver(struct cx8802_driver *drv)
647{
648 struct cx8802_dev *h;
649 struct cx8802_driver *driver;
650 struct list_head *list;
651 int err = 0, i = 0;
652
653 printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ ,
654 drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
655 drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
656
657 if ((err = cx8802_check_driver(drv)) != 0) {
658 printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ );
659 return err;
660 }
661
662 list_for_each(list,&cx8802_devlist) {
663 i++;
664 h = list_entry(list, struct cx8802_dev, devlist);
665
666 printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
667 h->core->name,h->pci->subsystem_vendor,
668 h->pci->subsystem_device,cx88_boards[h->core->board].name,
669 h->core->board);
670
671 /* Bring up a new struct for each driver instance */
672 driver = kzalloc(sizeof(*drv),GFP_KERNEL);
673 if (driver == NULL)
674 return -ENOMEM;
675
676 /* Snapshot of the driver registration data */
677 drv->core = h->core;
678 drv->suspend = cx8802_suspend_common;
679 drv->resume = cx8802_resume_common;
680 drv->request_acquire = cx8802_request_acquire;
681 drv->request_release = cx8802_request_release;
682 memcpy(driver, drv, sizeof(*driver));
683
684 err = drv->probe(driver);
685 if (err == 0) {
686 mutex_lock(&drv->core->lock);
687 list_add_tail(&driver->devlist,&h->drvlist.devlist);
688 mutex_unlock(&drv->core->lock);
689 } else {
690 printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err);
691 }
692
693 }
694 if (i == 0)
695 err = -ENODEV;
696
697 return err;
698}
699
700int cx8802_unregister_driver(struct cx8802_driver *drv)
701{
702 struct cx8802_dev *h;
703 struct cx8802_driver *d;
704 struct list_head *list;
705 struct list_head *list2, *q;
706 int err = 0, i = 0;
707
708 printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ ,
709 drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird");
710
711 list_for_each(list,&cx8802_devlist) {
712 i++;
713 h = list_entry(list, struct cx8802_dev, devlist);
714
715 printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
716 h->core->name,h->pci->subsystem_vendor,
717 h->pci->subsystem_device,cx88_boards[h->core->board].name,
718 h->core->board);
719
720 list_for_each_safe(list2, q, &h->drvlist.devlist) {
721 d = list_entry(list2, struct cx8802_driver, devlist);
722
723 /* only unregister the correct driver type */
724 if (d->type_id != drv->type_id)
725 continue;
726
727 err = d->remove(d);
728 if (err == 0) {
729 mutex_lock(&drv->core->lock);
730 list_del(list2);
731 mutex_unlock(&drv->core->lock);
732 } else
733 printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err);
734
735 }
736
737 }
738
739 return err;
740}
741
545/* ----------------------------------------------------------- */ 742/* ----------------------------------------------------------- */
743static int __devinit cx8802_probe(struct pci_dev *pci_dev,
744 const struct pci_device_id *pci_id)
745{
746 struct cx8802_dev *dev;
747 struct cx88_core *core;
748 int err;
749
750 /* general setup */
751 core = cx88_core_get(pci_dev);
752 if (NULL == core)
753 return -EINVAL;
754
755 printk("%s/2: cx2388x 8802 Driver Manager\n", core->name);
756
757 err = -ENODEV;
758 if (!cx88_boards[core->board].mpeg)
759 goto fail_core;
760
761 err = -ENOMEM;
762 dev = kzalloc(sizeof(*dev),GFP_KERNEL);
763 if (NULL == dev)
764 goto fail_core;
765 dev->pci = pci_dev;
766 dev->core = core;
767
768 err = cx8802_init_common(dev);
769 if (err != 0)
770 goto fail_free;
771
772 INIT_LIST_HEAD(&dev->drvlist.devlist);
773 list_add_tail(&dev->devlist,&cx8802_devlist);
546 774
775 /* Maintain a reference so cx88-video can query the 8802 device. */
776 core->dvbdev = dev;
777 return 0;
778
779 fail_free:
780 kfree(dev);
781 fail_core:
782 cx88_core_put(core,pci_dev);
783 return err;
784}
785
786static void __devexit cx8802_remove(struct pci_dev *pci_dev)
787{
788 struct cx8802_dev *dev;
789 struct cx8802_driver *h;
790 struct list_head *list;
791
792 dev = pci_get_drvdata(pci_dev);
793
794 dprintk( 1, "%s\n", __FUNCTION__);
795
796 list_for_each(list,&dev->drvlist.devlist) {
797 h = list_entry(list, struct cx8802_driver, devlist);
798 dprintk( 1, " ->driver\n");
799 if (h->remove == NULL) {
800 printk(KERN_ERR "%s .. skipping driver, no probe function\n", __FUNCTION__);
801 continue;
802 }
803 printk(KERN_INFO "%s .. Removing driver type %d\n", __FUNCTION__, h->type_id);
804 cx8802_unregister_driver(h);
805 list_del(&dev->drvlist.devlist);
806 }
807
808 /* Destroy any 8802 reference. */
809 dev->core->dvbdev = NULL;
810
811 /* common */
812 cx8802_fini_common(dev);
813 cx88_core_put(dev->core,dev->pci);
814 kfree(dev);
815}
816
817static struct pci_device_id cx8802_pci_tbl[] = {
818 {
819 .vendor = 0x14f1,
820 .device = 0x8802,
821 .subvendor = PCI_ANY_ID,
822 .subdevice = PCI_ANY_ID,
823 },{
824 /* --- end of list --- */
825 }
826};
827MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl);
828
829static struct pci_driver cx8802_pci_driver = {
830 .name = "cx88-mpeg driver manager",
831 .id_table = cx8802_pci_tbl,
832 .probe = cx8802_probe,
833 .remove = __devexit_p(cx8802_remove),
834};
835
836static int cx8802_init(void)
837{
838 printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n",
839 (CX88_VERSION_CODE >> 16) & 0xff,
840 (CX88_VERSION_CODE >> 8) & 0xff,
841 CX88_VERSION_CODE & 0xff);
842#ifdef SNAPSHOT
843 printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
844 SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
845#endif
846 return pci_register_driver(&cx8802_pci_driver);
847}
848
849static void cx8802_fini(void)
850{
851 pci_unregister_driver(&cx8802_pci_driver);
852}
853
854module_init(cx8802_init);
855module_exit(cx8802_fini);
547EXPORT_SYMBOL(cx8802_buf_prepare); 856EXPORT_SYMBOL(cx8802_buf_prepare);
548EXPORT_SYMBOL(cx8802_buf_queue); 857EXPORT_SYMBOL(cx8802_buf_queue);
549EXPORT_SYMBOL(cx8802_cancel_buffers); 858EXPORT_SYMBOL(cx8802_cancel_buffers);
@@ -551,9 +860,10 @@ EXPORT_SYMBOL(cx8802_cancel_buffers);
551EXPORT_SYMBOL(cx8802_init_common); 860EXPORT_SYMBOL(cx8802_init_common);
552EXPORT_SYMBOL(cx8802_fini_common); 861EXPORT_SYMBOL(cx8802_fini_common);
553 862
554EXPORT_SYMBOL(cx8802_suspend_common); 863EXPORT_SYMBOL(cx8802_register_driver);
555EXPORT_SYMBOL(cx8802_resume_common); 864EXPORT_SYMBOL(cx8802_unregister_driver);
556 865EXPORT_SYMBOL(cx8802_get_device);
866EXPORT_SYMBOL(cx8802_get_driver);
557/* ----------------------------------------------------------- */ 867/* ----------------------------------------------------------- */
558/* 868/*
559 * Local variables: 869 * Local variables: