aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx88/cx88-mpeg.c
diff options
context:
space:
mode:
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: