diff options
Diffstat (limited to 'drivers/media/video/cx88/cx88-video.c')
-rw-r--r-- | drivers/media/video/cx88/cx88-video.c | 303 |
1 files changed, 13 insertions, 290 deletions
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index dc997549b634..c44a079d08c0 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * $Id: cx88-video.c,v 1.70 2005/06/20 03:36:00 mkrufky Exp $ | 2 | * $Id: cx88-video.c,v 1.79 2005/07/07 14:17:47 mchehab Exp $ |
3 | * | 3 | * |
4 | * device driver for Conexant 2388x based TV cards | 4 | * device driver for Conexant 2388x based TV cards |
5 | * video4linux video interface | 5 | * video4linux video interface |
@@ -86,13 +86,6 @@ static struct cx88_tvnorm tvnorms[] = { | |||
86 | .id = V4L2_STD_NTSC_M_JP, | 86 | .id = V4L2_STD_NTSC_M_JP, |
87 | .cxiformat = VideoFormatNTSCJapan, | 87 | .cxiformat = VideoFormatNTSCJapan, |
88 | .cxoformat = 0x181f0008, | 88 | .cxoformat = 0x181f0008, |
89 | #if 0 | ||
90 | },{ | ||
91 | .name = "NTSC-4.43", | ||
92 | .id = FIXME, | ||
93 | .cxiformat = VideoFormatNTSC443, | ||
94 | .cxoformat = 0x181f0008, | ||
95 | #endif | ||
96 | },{ | 89 | },{ |
97 | .name = "PAL-BG", | 90 | .name = "PAL-BG", |
98 | .id = V4L2_STD_PAL_BG, | 91 | .id = V4L2_STD_PAL_BG, |
@@ -248,6 +241,7 @@ static struct cx88_ctrl cx8800_ctls[] = { | |||
248 | .default_value = 0, | 241 | .default_value = 0, |
249 | .type = V4L2_CTRL_TYPE_INTEGER, | 242 | .type = V4L2_CTRL_TYPE_INTEGER, |
250 | }, | 243 | }, |
244 | .off = 0, | ||
251 | .reg = MO_CONTR_BRIGHT, | 245 | .reg = MO_CONTR_BRIGHT, |
252 | .mask = 0xff00, | 246 | .mask = 0xff00, |
253 | .shift = 8, | 247 | .shift = 8, |
@@ -674,231 +668,6 @@ static struct videobuf_queue_ops cx8800_video_qops = { | |||
674 | 668 | ||
675 | /* ------------------------------------------------------------------ */ | 669 | /* ------------------------------------------------------------------ */ |
676 | 670 | ||
677 | #if 0 /* overlay support not finished yet */ | ||
678 | static u32* ov_risc_field(struct cx8800_dev *dev, struct cx8800_fh *fh, | ||
679 | u32 *rp, struct btcx_skiplist *skips, | ||
680 | u32 sync_line, int skip_even, int skip_odd) | ||
681 | { | ||
682 | int line,maxy,start,end,skip,nskips; | ||
683 | u32 ri,ra; | ||
684 | u32 addr; | ||
685 | |||
686 | /* sync instruction */ | ||
687 | *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); | ||
688 | |||
689 | addr = (unsigned long)dev->fbuf.base; | ||
690 | addr += dev->fbuf.fmt.bytesperline * fh->win.w.top; | ||
691 | addr += (fh->fmt->depth >> 3) * fh->win.w.left; | ||
692 | |||
693 | /* scan lines */ | ||
694 | for (maxy = -1, line = 0; line < fh->win.w.height; | ||
695 | line++, addr += dev->fbuf.fmt.bytesperline) { | ||
696 | if ((line%2) == 0 && skip_even) | ||
697 | continue; | ||
698 | if ((line%2) == 1 && skip_odd) | ||
699 | continue; | ||
700 | |||
701 | /* calculate clipping */ | ||
702 | if (line > maxy) | ||
703 | btcx_calc_skips(line, fh->win.w.width, &maxy, | ||
704 | skips, &nskips, fh->clips, fh->nclips); | ||
705 | |||
706 | /* write out risc code */ | ||
707 | for (start = 0, skip = 0; start < fh->win.w.width; start = end) { | ||
708 | if (skip >= nskips) { | ||
709 | ri = RISC_WRITE; | ||
710 | end = fh->win.w.width; | ||
711 | } else if (start < skips[skip].start) { | ||
712 | ri = RISC_WRITE; | ||
713 | end = skips[skip].start; | ||
714 | } else { | ||
715 | ri = RISC_SKIP; | ||
716 | end = skips[skip].end; | ||
717 | skip++; | ||
718 | } | ||
719 | if (RISC_WRITE == ri) | ||
720 | ra = addr + (fh->fmt->depth>>3)*start; | ||
721 | else | ||
722 | ra = 0; | ||
723 | |||
724 | if (0 == start) | ||
725 | ri |= RISC_SOL; | ||
726 | if (fh->win.w.width == end) | ||
727 | ri |= RISC_EOL; | ||
728 | ri |= (fh->fmt->depth>>3) * (end-start); | ||
729 | |||
730 | *(rp++)=cpu_to_le32(ri); | ||
731 | if (0 != ra) | ||
732 | *(rp++)=cpu_to_le32(ra); | ||
733 | } | ||
734 | } | ||
735 | kfree(skips); | ||
736 | return rp; | ||
737 | } | ||
738 | |||
739 | static int ov_risc_frame(struct cx8800_dev *dev, struct cx8800_fh *fh, | ||
740 | struct cx88_buffer *buf) | ||
741 | { | ||
742 | struct btcx_skiplist *skips; | ||
743 | u32 instructions,fields; | ||
744 | u32 *rp; | ||
745 | int rc; | ||
746 | |||
747 | /* skip list for window clipping */ | ||
748 | if (NULL == (skips = kmalloc(sizeof(*skips) * fh->nclips,GFP_KERNEL))) | ||
749 | return -ENOMEM; | ||
750 | |||
751 | fields = 0; | ||
752 | if (V4L2_FIELD_HAS_TOP(fh->win.field)) | ||
753 | fields++; | ||
754 | if (V4L2_FIELD_HAS_BOTTOM(fh->win.field)) | ||
755 | fields++; | ||
756 | |||
757 | /* estimate risc mem: worst case is (clip+1) * lines instructions | ||
758 | + syncs + jump (all 2 dwords) */ | ||
759 | instructions = (fh->nclips+1) * fh->win.w.height; | ||
760 | instructions += 3 + 4; | ||
761 | if ((rc = btcx_riscmem_alloc(dev->pci,&buf->risc,instructions*8)) < 0) { | ||
762 | kfree(skips); | ||
763 | return rc; | ||
764 | } | ||
765 | |||
766 | /* write risc instructions */ | ||
767 | rp = buf->risc.cpu; | ||
768 | switch (fh->win.field) { | ||
769 | case V4L2_FIELD_TOP: | ||
770 | rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 0); | ||
771 | break; | ||
772 | case V4L2_FIELD_BOTTOM: | ||
773 | rp = ov_risc_field(dev, fh, rp, skips, 0x200, 0, 0); | ||
774 | break; | ||
775 | case V4L2_FIELD_INTERLACED: | ||
776 | rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 1); | ||
777 | rp = ov_risc_field(dev, fh, rp, skips, 0x200, 1, 0); | ||
778 | break; | ||
779 | default: | ||
780 | BUG(); | ||
781 | } | ||
782 | |||
783 | /* save pointer to jmp instruction address */ | ||
784 | buf->risc.jmp = rp; | ||
785 | kfree(skips); | ||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | static int verify_window(struct cx8800_dev *dev, struct v4l2_window *win) | ||
790 | { | ||
791 | enum v4l2_field field; | ||
792 | int maxw, maxh; | ||
793 | |||
794 | if (NULL == dev->fbuf.base) | ||
795 | return -EINVAL; | ||
796 | if (win->w.width < 48 || win->w.height < 32) | ||
797 | return -EINVAL; | ||
798 | if (win->clipcount > 2048) | ||
799 | return -EINVAL; | ||
800 | |||
801 | field = win->field; | ||
802 | maxw = norm_maxw(core->tvnorm); | ||
803 | maxh = norm_maxh(core->tvnorm); | ||
804 | |||
805 | if (V4L2_FIELD_ANY == field) { | ||
806 | field = (win->w.height > maxh/2) | ||
807 | ? V4L2_FIELD_INTERLACED | ||
808 | : V4L2_FIELD_TOP; | ||
809 | } | ||
810 | switch (field) { | ||
811 | case V4L2_FIELD_TOP: | ||
812 | case V4L2_FIELD_BOTTOM: | ||
813 | maxh = maxh / 2; | ||
814 | break; | ||
815 | case V4L2_FIELD_INTERLACED: | ||
816 | break; | ||
817 | default: | ||
818 | return -EINVAL; | ||
819 | } | ||
820 | |||
821 | win->field = field; | ||
822 | if (win->w.width > maxw) | ||
823 | win->w.width = maxw; | ||
824 | if (win->w.height > maxh) | ||
825 | win->w.height = maxh; | ||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | static int setup_window(struct cx8800_dev *dev, struct cx8800_fh *fh, | ||
830 | struct v4l2_window *win) | ||
831 | { | ||
832 | struct v4l2_clip *clips = NULL; | ||
833 | int n,size,retval = 0; | ||
834 | |||
835 | if (NULL == fh->fmt) | ||
836 | return -EINVAL; | ||
837 | retval = verify_window(dev,win); | ||
838 | if (0 != retval) | ||
839 | return retval; | ||
840 | |||
841 | /* copy clips -- luckily v4l1 + v4l2 are binary | ||
842 | compatible here ...*/ | ||
843 | n = win->clipcount; | ||
844 | size = sizeof(*clips)*(n+4); | ||
845 | clips = kmalloc(size,GFP_KERNEL); | ||
846 | if (NULL == clips) | ||
847 | return -ENOMEM; | ||
848 | if (n > 0) { | ||
849 | if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) { | ||
850 | kfree(clips); | ||
851 | return -EFAULT; | ||
852 | } | ||
853 | } | ||
854 | |||
855 | /* clip against screen */ | ||
856 | if (NULL != dev->fbuf.base) | ||
857 | n = btcx_screen_clips(dev->fbuf.fmt.width, dev->fbuf.fmt.height, | ||
858 | &win->w, clips, n); | ||
859 | btcx_sort_clips(clips,n); | ||
860 | |||
861 | /* 4-byte alignments */ | ||
862 | switch (fh->fmt->depth) { | ||
863 | case 8: | ||
864 | case 24: | ||
865 | btcx_align(&win->w, clips, n, 3); | ||
866 | break; | ||
867 | case 16: | ||
868 | btcx_align(&win->w, clips, n, 1); | ||
869 | break; | ||
870 | case 32: | ||
871 | /* no alignment fixups needed */ | ||
872 | break; | ||
873 | default: | ||
874 | BUG(); | ||
875 | } | ||
876 | |||
877 | down(&fh->vidq.lock); | ||
878 | if (fh->clips) | ||
879 | kfree(fh->clips); | ||
880 | fh->clips = clips; | ||
881 | fh->nclips = n; | ||
882 | fh->win = *win; | ||
883 | #if 0 | ||
884 | fh->ov.setup_ok = 1; | ||
885 | #endif | ||
886 | |||
887 | /* update overlay if needed */ | ||
888 | retval = 0; | ||
889 | #if 0 | ||
890 | if (check_btres(fh, RESOURCE_OVERLAY)) { | ||
891 | struct bttv_buffer *new; | ||
892 | |||
893 | new = videobuf_alloc(sizeof(*new)); | ||
894 | bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); | ||
895 | retval = bttv_switch_overlay(btv,fh,new); | ||
896 | } | ||
897 | #endif | ||
898 | up(&fh->vidq.lock); | ||
899 | return retval; | ||
900 | } | ||
901 | #endif | ||
902 | 671 | ||
903 | /* ------------------------------------------------------------------ */ | 672 | /* ------------------------------------------------------------------ */ |
904 | 673 | ||
@@ -1327,9 +1096,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, | |||
1327 | struct cx8800_fh *fh = file->private_data; | 1096 | struct cx8800_fh *fh = file->private_data; |
1328 | struct cx8800_dev *dev = fh->dev; | 1097 | struct cx8800_dev *dev = fh->dev; |
1329 | struct cx88_core *core = dev->core; | 1098 | struct cx88_core *core = dev->core; |
1330 | #if 0 | ||
1331 | unsigned long flags; | ||
1332 | #endif | ||
1333 | int err; | 1099 | int err; |
1334 | 1100 | ||
1335 | if (video_debug > 1) | 1101 | if (video_debug > 1) |
@@ -1350,9 +1116,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, | |||
1350 | V4L2_CAP_READWRITE | | 1116 | V4L2_CAP_READWRITE | |
1351 | V4L2_CAP_STREAMING | | 1117 | V4L2_CAP_STREAMING | |
1352 | V4L2_CAP_VBI_CAPTURE | | 1118 | V4L2_CAP_VBI_CAPTURE | |
1353 | #if 0 | ||
1354 | V4L2_CAP_VIDEO_OVERLAY | | ||
1355 | #endif | ||
1356 | 0; | 1119 | 0; |
1357 | if (UNSET != core->tuner_type) | 1120 | if (UNSET != core->tuner_type) |
1358 | cap->capabilities |= V4L2_CAP_TUNER; | 1121 | cap->capabilities |= V4L2_CAP_TUNER; |
@@ -1453,36 +1216,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file, | |||
1453 | } | 1216 | } |
1454 | 1217 | ||
1455 | 1218 | ||
1456 | #if 0 | ||
1457 | /* needs review */ | ||
1458 | case VIDIOC_G_AUDIO: | ||
1459 | { | ||
1460 | struct v4l2_audio *a = arg; | ||
1461 | unsigned int n = a->index; | ||
1462 | |||
1463 | memset(a,0,sizeof(*a)); | ||
1464 | a->index = n; | ||
1465 | switch (n) { | ||
1466 | case 0: | ||
1467 | if ((CX88_VMUX_TELEVISION == INPUT(n)->type) | ||
1468 | || (CX88_VMUX_CABLE == INPUT(n)->type)) { | ||
1469 | strcpy(a->name,"Television"); | ||
1470 | // FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO. | ||
1471 | return 0; | ||
1472 | } | ||
1473 | break; | ||
1474 | case 1: | ||
1475 | if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) { | ||
1476 | strcpy(a->name,"Line In"); | ||
1477 | a->capability = V4L2_AUDCAP_STEREO; | ||
1478 | return 0; | ||
1479 | } | ||
1480 | break; | ||
1481 | } | ||
1482 | // Audio input not available. | ||
1483 | return -EINVAL; | ||
1484 | } | ||
1485 | #endif | ||
1486 | 1219 | ||
1487 | /* --- capture ioctls ---------------------------------------- */ | 1220 | /* --- capture ioctls ---------------------------------------- */ |
1488 | case VIDIOC_ENUM_FMT: | 1221 | case VIDIOC_ENUM_FMT: |
@@ -1592,6 +1325,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file, | |||
1592 | 1325 | ||
1593 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | 1326 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; |
1594 | f->frequency = dev->freq; | 1327 | f->frequency = dev->freq; |
1328 | |||
1329 | cx88_call_i2c_clients(dev->core,VIDIOC_G_FREQUENCY,f); | ||
1330 | |||
1595 | return 0; | 1331 | return 0; |
1596 | } | 1332 | } |
1597 | case VIDIOC_S_FREQUENCY: | 1333 | case VIDIOC_S_FREQUENCY: |
@@ -1846,6 +1582,14 @@ static void cx8800_vid_timeout(unsigned long data) | |||
1846 | spin_unlock_irqrestore(&dev->slock,flags); | 1582 | spin_unlock_irqrestore(&dev->slock,flags); |
1847 | } | 1583 | } |
1848 | 1584 | ||
1585 | static char *cx88_vid_irqs[32] = { | ||
1586 | "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", | ||
1587 | "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", | ||
1588 | "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", | ||
1589 | "y_sync", "u_sync", "v_sync", "vbi_sync", | ||
1590 | "opc_err", "par_err", "rip_err", "pci_abort", | ||
1591 | }; | ||
1592 | |||
1849 | static void cx8800_vid_irq(struct cx8800_dev *dev) | 1593 | static void cx8800_vid_irq(struct cx8800_dev *dev) |
1850 | { | 1594 | { |
1851 | struct cx88_core *core = dev->core; | 1595 | struct cx88_core *core = dev->core; |
@@ -2013,7 +1757,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
2013 | { | 1757 | { |
2014 | struct cx8800_dev *dev; | 1758 | struct cx8800_dev *dev; |
2015 | struct cx88_core *core; | 1759 | struct cx88_core *core; |
2016 | struct tuner_addr tun_addr; | ||
2017 | int err; | 1760 | int err; |
2018 | 1761 | ||
2019 | dev = kmalloc(sizeof(*dev),GFP_KERNEL); | 1762 | dev = kmalloc(sizeof(*dev),GFP_KERNEL); |
@@ -2087,22 +1830,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
2087 | request_module("tuner"); | 1830 | request_module("tuner"); |
2088 | if (core->tda9887_conf) | 1831 | if (core->tda9887_conf) |
2089 | request_module("tda9887"); | 1832 | request_module("tda9887"); |
2090 | if (core->radio_type != UNSET) { | ||
2091 | tun_addr.v4l2_tuner = V4L2_TUNER_RADIO; | ||
2092 | tun_addr.type = core->radio_type; | ||
2093 | tun_addr.addr = core->radio_addr; | ||
2094 | cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE_ADDR, &tun_addr); | ||
2095 | } | ||
2096 | if (core->tuner_type != UNSET) { | ||
2097 | tun_addr.v4l2_tuner = V4L2_TUNER_ANALOG_TV; | ||
2098 | tun_addr.type = core->tuner_type; | ||
2099 | tun_addr.addr = core->tuner_addr; | ||
2100 | cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE_ADDR, &tun_addr); | ||
2101 | } | ||
2102 | |||
2103 | if (core->tda9887_conf) | ||
2104 | cx88_call_i2c_clients(dev->core,TDA9887_SET_CONFIG,&core->tda9887_conf); | ||
2105 | |||
2106 | /* register v4l devices */ | 1833 | /* register v4l devices */ |
2107 | dev->video_dev = cx88_vdev_init(core,dev->pci, | 1834 | dev->video_dev = cx88_vdev_init(core,dev->pci, |
2108 | &cx8800_video_template,"video"); | 1835 | &cx8800_video_template,"video"); |
@@ -2212,10 +1939,8 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) | |||
2212 | } | 1939 | } |
2213 | spin_unlock(&dev->slock); | 1940 | spin_unlock(&dev->slock); |
2214 | 1941 | ||
2215 | #if 1 | ||
2216 | /* FIXME -- shutdown device */ | 1942 | /* FIXME -- shutdown device */ |
2217 | cx88_shutdown(dev->core); | 1943 | cx88_shutdown(dev->core); |
2218 | #endif | ||
2219 | 1944 | ||
2220 | pci_save_state(pci_dev); | 1945 | pci_save_state(pci_dev); |
2221 | if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { | 1946 | if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { |
@@ -2237,10 +1962,8 @@ static int cx8800_resume(struct pci_dev *pci_dev) | |||
2237 | pci_set_power_state(pci_dev, PCI_D0); | 1962 | pci_set_power_state(pci_dev, PCI_D0); |
2238 | pci_restore_state(pci_dev); | 1963 | pci_restore_state(pci_dev); |
2239 | 1964 | ||
2240 | #if 1 | ||
2241 | /* FIXME: re-initialize hardware */ | 1965 | /* FIXME: re-initialize hardware */ |
2242 | cx88_reset(dev->core); | 1966 | cx88_reset(dev->core); |
2243 | #endif | ||
2244 | 1967 | ||
2245 | /* restart video+vbi capture */ | 1968 | /* restart video+vbi capture */ |
2246 | spin_lock(&dev->slock); | 1969 | spin_lock(&dev->slock); |