diff options
Diffstat (limited to 'drivers/media/video/cx88/cx88-mpeg.c')
-rw-r--r-- | drivers/media/video/cx88/cx88-mpeg.c | 344 |
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); | |||
44 | MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); | 44 | MODULE_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 | |||
52 | static LIST_HEAD(cx8802_devlist); | ||
49 | /* ------------------------------------------------------------------ */ | 53 | /* ------------------------------------------------------------------ */ |
50 | 54 | ||
51 | static int cx8802_start_dma(struct cx8802_dev *dev, | 55 | static 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 | ||
551 | struct 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 | |||
566 | struct 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. */ | ||
590 | int 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. */ | ||
610 | int 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 | |||
624 | static 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 | |||
646 | int 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 | |||
700 | int 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 | /* ----------------------------------------------------------- */ |
743 | static 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 | |||
786 | static 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 | |||
817 | static 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 | }; | ||
827 | MODULE_DEVICE_TABLE(pci, cx8802_pci_tbl); | ||
828 | |||
829 | static 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 | |||
836 | static 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 | |||
849 | static void cx8802_fini(void) | ||
850 | { | ||
851 | pci_unregister_driver(&cx8802_pci_driver); | ||
852 | } | ||
853 | |||
854 | module_init(cx8802_init); | ||
855 | module_exit(cx8802_fini); | ||
547 | EXPORT_SYMBOL(cx8802_buf_prepare); | 856 | EXPORT_SYMBOL(cx8802_buf_prepare); |
548 | EXPORT_SYMBOL(cx8802_buf_queue); | 857 | EXPORT_SYMBOL(cx8802_buf_queue); |
549 | EXPORT_SYMBOL(cx8802_cancel_buffers); | 858 | EXPORT_SYMBOL(cx8802_cancel_buffers); |
@@ -551,9 +860,10 @@ EXPORT_SYMBOL(cx8802_cancel_buffers); | |||
551 | EXPORT_SYMBOL(cx8802_init_common); | 860 | EXPORT_SYMBOL(cx8802_init_common); |
552 | EXPORT_SYMBOL(cx8802_fini_common); | 861 | EXPORT_SYMBOL(cx8802_fini_common); |
553 | 862 | ||
554 | EXPORT_SYMBOL(cx8802_suspend_common); | 863 | EXPORT_SYMBOL(cx8802_register_driver); |
555 | EXPORT_SYMBOL(cx8802_resume_common); | 864 | EXPORT_SYMBOL(cx8802_unregister_driver); |
556 | 865 | EXPORT_SYMBOL(cx8802_get_device); | |
866 | EXPORT_SYMBOL(cx8802_get_driver); | ||
557 | /* ----------------------------------------------------------- */ | 867 | /* ----------------------------------------------------------- */ |
558 | /* | 868 | /* |
559 | * Local variables: | 869 | * Local variables: |