diff options
Diffstat (limited to 'drivers/media/video/cx88/cx88-blackbird.c')
-rw-r--r-- | drivers/media/video/cx88/cx88-blackbird.c | 778 |
1 files changed, 344 insertions, 434 deletions
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index 187e917f6659..8fcef790fc12 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c | |||
@@ -6,6 +6,9 @@ | |||
6 | * (c) 2004 Jelle Foks <jelle@foks.8m.com> | 6 | * (c) 2004 Jelle Foks <jelle@foks.8m.com> |
7 | * (c) 2004 Gerd Knorr <kraxel@bytesex.org> | 7 | * (c) 2004 Gerd Knorr <kraxel@bytesex.org> |
8 | * | 8 | * |
9 | * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> | ||
10 | * - video_ioctl2 conversion | ||
11 | * | ||
9 | * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), | 12 | * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), |
10 | * | 13 | * |
11 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
@@ -53,73 +56,6 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); | |||
53 | 56 | ||
54 | /* ------------------------------------------------------------------ */ | 57 | /* ------------------------------------------------------------------ */ |
55 | 58 | ||
56 | |||
57 | struct cx88_tvnorm { | ||
58 | char *name; | ||
59 | v4l2_std_id id; | ||
60 | u32 cxiformat; | ||
61 | u32 cxoformat; | ||
62 | }; | ||
63 | |||
64 | static struct cx88_tvnorm tvnorms[] = { | ||
65 | { | ||
66 | .name = "NTSC-M", | ||
67 | .id = V4L2_STD_NTSC_M, | ||
68 | .cxiformat = VideoFormatNTSC, | ||
69 | .cxoformat = 0x181f0008, | ||
70 | },{ | ||
71 | .name = "NTSC-JP", | ||
72 | .id = V4L2_STD_NTSC_M_JP, | ||
73 | .cxiformat = VideoFormatNTSCJapan, | ||
74 | .cxoformat = 0x181f0008, | ||
75 | },{ | ||
76 | .name = "PAL-BG", | ||
77 | .id = V4L2_STD_PAL_BG, | ||
78 | .cxiformat = VideoFormatPAL, | ||
79 | .cxoformat = 0x181f0008, | ||
80 | },{ | ||
81 | .name = "PAL-DK", | ||
82 | .id = V4L2_STD_PAL_DK, | ||
83 | .cxiformat = VideoFormatPAL, | ||
84 | .cxoformat = 0x181f0008, | ||
85 | },{ | ||
86 | .name = "PAL-I", | ||
87 | .id = V4L2_STD_PAL_I, | ||
88 | .cxiformat = VideoFormatPAL, | ||
89 | .cxoformat = 0x181f0008, | ||
90 | },{ | ||
91 | .name = "PAL-M", | ||
92 | .id = V4L2_STD_PAL_M, | ||
93 | .cxiformat = VideoFormatPALM, | ||
94 | .cxoformat = 0x1c1f0008, | ||
95 | },{ | ||
96 | .name = "PAL-N", | ||
97 | .id = V4L2_STD_PAL_N, | ||
98 | .cxiformat = VideoFormatPALN, | ||
99 | .cxoformat = 0x1c1f0008, | ||
100 | },{ | ||
101 | .name = "PAL-Nc", | ||
102 | .id = V4L2_STD_PAL_Nc, | ||
103 | .cxiformat = VideoFormatPALNC, | ||
104 | .cxoformat = 0x1c1f0008, | ||
105 | },{ | ||
106 | .name = "PAL-60", | ||
107 | .id = V4L2_STD_PAL_60, | ||
108 | .cxiformat = VideoFormatPAL60, | ||
109 | .cxoformat = 0x181f0008, | ||
110 | },{ | ||
111 | .name = "SECAM-L", | ||
112 | .id = V4L2_STD_SECAM_L, | ||
113 | .cxiformat = VideoFormatSECAM, | ||
114 | .cxoformat = 0x181f0008, | ||
115 | },{ | ||
116 | .name = "SECAM-DK", | ||
117 | .id = V4L2_STD_SECAM_DK, | ||
118 | .cxiformat = VideoFormatSECAM, | ||
119 | .cxoformat = 0x181f0008, | ||
120 | } | ||
121 | }; | ||
122 | |||
123 | #define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024 | 59 | #define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024 |
124 | 60 | ||
125 | /* defines below are from ivtv-driver.h */ | 61 | /* defines below are from ivtv-driver.h */ |
@@ -777,8 +713,13 @@ static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qc | |||
777 | return 0; | 713 | return 0; |
778 | } | 714 | } |
779 | 715 | ||
780 | static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qmenu) | 716 | /* ------------------------------------------------------------------ */ |
717 | /* IOCTL Handlers */ | ||
718 | |||
719 | static int vidioc_querymenu (struct file *file, void *priv, | ||
720 | struct v4l2_querymenu *qmenu) | ||
781 | { | 721 | { |
722 | struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; | ||
782 | struct v4l2_queryctrl qctrl; | 723 | struct v4l2_queryctrl qctrl; |
783 | 724 | ||
784 | qctrl.id = qmenu->id; | 725 | qctrl.id = qmenu->id; |
@@ -786,413 +727,347 @@ static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qm | |||
786 | return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); | 727 | return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); |
787 | } | 728 | } |
788 | 729 | ||
789 | /* ------------------------------------------------------------------ */ | 730 | static int vidioc_querycap (struct file *file, void *priv, |
790 | 731 | struct v4l2_capability *cap) | |
791 | static int mpeg_do_ioctl(struct inode *inode, struct file *file, | ||
792 | unsigned int cmd, void *arg) | ||
793 | { | 732 | { |
794 | struct cx8802_fh *fh = file->private_data; | 733 | struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; |
795 | struct cx8802_dev *dev = fh->dev; | ||
796 | struct cx88_core *core = dev->core; | 734 | struct cx88_core *core = dev->core; |
797 | 735 | ||
798 | if (debug > 1) | 736 | strcpy(cap->driver, "cx88_blackbird"); |
799 | v4l_print_ioctl(core->name,cmd); | 737 | strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card)); |
738 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); | ||
739 | cap->version = CX88_VERSION_CODE; | ||
740 | cap->capabilities = | ||
741 | V4L2_CAP_VIDEO_CAPTURE | | ||
742 | V4L2_CAP_READWRITE | | ||
743 | V4L2_CAP_STREAMING; | ||
744 | if (UNSET != core->tuner_type) | ||
745 | cap->capabilities |= V4L2_CAP_TUNER; | ||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | static int vidioc_enum_fmt_cap (struct file *file, void *priv, | ||
750 | struct v4l2_fmtdesc *f) | ||
751 | { | ||
752 | if (f->index != 0) | ||
753 | return -EINVAL; | ||
800 | 754 | ||
801 | switch (cmd) { | 755 | strlcpy(f->description, "MPEG", sizeof(f->description)); |
756 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
757 | f->pixelformat = V4L2_PIX_FMT_MPEG; | ||
758 | return 0; | ||
759 | } | ||
802 | 760 | ||
803 | /* --- capabilities ------------------------------------------ */ | 761 | static int vidioc_g_fmt_cap (struct file *file, void *priv, |
804 | case VIDIOC_QUERYCAP: | 762 | struct v4l2_format *f) |
805 | { | 763 | { |
806 | struct v4l2_capability *cap = arg; | 764 | struct cx8802_fh *fh = priv; |
765 | struct cx8802_dev *dev = fh->dev; | ||
766 | |||
767 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
768 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
769 | f->fmt.pix.bytesperline = 0; | ||
770 | f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */ | ||
771 | f->fmt.pix.colorspace = 0; | ||
772 | f->fmt.pix.width = dev->width; | ||
773 | f->fmt.pix.height = dev->height; | ||
774 | f->fmt.pix.field = fh->mpegq.field; | ||
775 | dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", | ||
776 | dev->width, dev->height, fh->mpegq.field ); | ||
777 | return 0; | ||
778 | } | ||
807 | 779 | ||
808 | memset(cap,0,sizeof(*cap)); | 780 | static int vidioc_try_fmt_cap (struct file *file, void *priv, |
809 | strcpy(cap->driver, "cx88_blackbird"); | 781 | struct v4l2_format *f) |
810 | strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card)); | 782 | { |
811 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); | 783 | struct cx8802_fh *fh = priv; |
812 | cap->version = CX88_VERSION_CODE; | 784 | struct cx8802_dev *dev = fh->dev; |
813 | cap->capabilities = | 785 | |
814 | V4L2_CAP_VIDEO_CAPTURE | | 786 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
815 | V4L2_CAP_READWRITE | | 787 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; |
816 | V4L2_CAP_STREAMING; | 788 | f->fmt.pix.bytesperline = 0; |
817 | if (UNSET != core->tuner_type) | 789 | f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; |
818 | cap->capabilities |= V4L2_CAP_TUNER; | 790 | f->fmt.pix.colorspace = 0; |
791 | dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", | ||
792 | dev->width, dev->height, fh->mpegq.field ); | ||
793 | return 0; | ||
794 | } | ||
819 | 795 | ||
820 | return 0; | 796 | static int vidioc_s_fmt_cap (struct file *file, void *priv, |
821 | } | 797 | struct v4l2_format *f) |
798 | { | ||
799 | struct cx8802_fh *fh = priv; | ||
800 | struct cx8802_dev *dev = fh->dev; | ||
801 | struct cx88_core *core = dev->core; | ||
822 | 802 | ||
823 | /* --- capture ioctls ---------------------------------------- */ | 803 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
824 | case VIDIOC_ENUM_FMT: | 804 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; |
825 | { | 805 | f->fmt.pix.bytesperline = 0; |
826 | struct v4l2_fmtdesc *f = arg; | 806 | f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; |
827 | int index; | 807 | f->fmt.pix.colorspace = 0; |
828 | 808 | dev->width = f->fmt.pix.width; | |
829 | index = f->index; | 809 | dev->height = f->fmt.pix.height; |
830 | if (index != 0) | 810 | fh->mpegq.field = f->fmt.pix.field; |
831 | return -EINVAL; | 811 | cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); |
832 | 812 | blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, | |
833 | memset(f,0,sizeof(*f)); | 813 | f->fmt.pix.height, f->fmt.pix.width); |
834 | f->index = index; | 814 | dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", |
835 | strlcpy(f->description, "MPEG", sizeof(f->description)); | 815 | f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field ); |
836 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 816 | return 0; |
837 | f->pixelformat = V4L2_PIX_FMT_MPEG; | 817 | } |
838 | return 0; | ||
839 | } | ||
840 | case VIDIOC_G_FMT: | ||
841 | { | ||
842 | struct v4l2_format *f = arg; | ||
843 | |||
844 | memset(f,0,sizeof(*f)); | ||
845 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
846 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
847 | f->fmt.pix.bytesperline = 0; | ||
848 | f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */ | ||
849 | f->fmt.pix.colorspace = 0; | ||
850 | f->fmt.pix.width = dev->width; | ||
851 | f->fmt.pix.height = dev->height; | ||
852 | f->fmt.pix.field = fh->mpegq.field; | ||
853 | dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", | ||
854 | dev->width, dev->height, fh->mpegq.field ); | ||
855 | return 0; | ||
856 | } | ||
857 | case VIDIOC_TRY_FMT: | ||
858 | { | ||
859 | struct v4l2_format *f = arg; | ||
860 | |||
861 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
862 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
863 | f->fmt.pix.bytesperline = 0; | ||
864 | f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; | ||
865 | f->fmt.pix.colorspace = 0; | ||
866 | dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", | ||
867 | dev->width, dev->height, fh->mpegq.field ); | ||
868 | return 0; | ||
869 | } | ||
870 | case VIDIOC_S_FMT: | ||
871 | { | ||
872 | struct v4l2_format *f = arg; | ||
873 | |||
874 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
875 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
876 | f->fmt.pix.bytesperline = 0; | ||
877 | f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; | ||
878 | f->fmt.pix.colorspace = 0; | ||
879 | dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", | ||
880 | f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field ); | ||
881 | return 0; | ||
882 | } | ||
883 | 818 | ||
884 | /* --- streaming capture ------------------------------------- */ | 819 | static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) |
885 | case VIDIOC_REQBUFS: | 820 | { |
886 | return videobuf_reqbufs(&fh->mpegq, arg); | 821 | struct cx8802_fh *fh = priv; |
822 | return (videobuf_reqbufs(&fh->mpegq, p)); | ||
823 | } | ||
887 | 824 | ||
888 | case VIDIOC_QUERYBUF: | 825 | static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) |
889 | return videobuf_querybuf(&fh->mpegq, arg); | 826 | { |
827 | struct cx8802_fh *fh = priv; | ||
828 | return (videobuf_querybuf(&fh->mpegq, p)); | ||
829 | } | ||
890 | 830 | ||
891 | case VIDIOC_QBUF: | 831 | static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) |
892 | return videobuf_qbuf(&fh->mpegq, arg); | 832 | { |
833 | struct cx8802_fh *fh = priv; | ||
834 | return (videobuf_qbuf(&fh->mpegq, p)); | ||
835 | } | ||
893 | 836 | ||
894 | case VIDIOC_DQBUF: | 837 | static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) |
895 | return videobuf_dqbuf(&fh->mpegq, arg, | 838 | { |
896 | file->f_flags & O_NONBLOCK); | 839 | struct cx8802_fh *fh = priv; |
840 | return (videobuf_dqbuf(&fh->mpegq, p, | ||
841 | file->f_flags & O_NONBLOCK)); | ||
842 | } | ||
897 | 843 | ||
898 | case VIDIOC_STREAMON: | 844 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) |
899 | return videobuf_streamon(&fh->mpegq); | 845 | { |
846 | struct cx8802_fh *fh = priv; | ||
847 | return videobuf_streamon(&fh->mpegq); | ||
848 | } | ||
900 | 849 | ||
901 | case VIDIOC_STREAMOFF: | 850 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) |
902 | return videobuf_streamoff(&fh->mpegq); | 851 | { |
852 | struct cx8802_fh *fh = priv; | ||
853 | return videobuf_streamoff(&fh->mpegq); | ||
854 | } | ||
903 | 855 | ||
904 | /* --- mpeg compression -------------------------------------- */ | 856 | static int vidioc_g_mpegcomp (struct file *file, void *fh, |
905 | case VIDIOC_G_MPEGCOMP: | 857 | struct v4l2_mpeg_compression *f) |
906 | { | 858 | { |
907 | struct v4l2_mpeg_compression *f = arg; | 859 | printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. " |
860 | "Replace with VIDIOC_G_EXT_CTRLS!"); | ||
861 | memcpy(f,&default_mpeg_params,sizeof(*f)); | ||
862 | return 0; | ||
863 | } | ||
908 | 864 | ||
909 | printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. " | 865 | static int vidioc_s_mpegcomp (struct file *file, void *fh, |
910 | "Replace with VIDIOC_G_EXT_CTRLS!"); | 866 | struct v4l2_mpeg_compression *f) |
911 | memcpy(f,&default_mpeg_params,sizeof(*f)); | 867 | { |
912 | return 0; | 868 | printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. " |
913 | } | 869 | "Replace with VIDIOC_S_EXT_CTRLS!"); |
914 | case VIDIOC_S_MPEGCOMP: | 870 | return 0; |
915 | printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. " | 871 | } |
916 | "Replace with VIDIOC_S_EXT_CTRLS!"); | ||
917 | return 0; | ||
918 | case VIDIOC_G_EXT_CTRLS: | ||
919 | { | ||
920 | struct v4l2_ext_controls *f = arg; | ||
921 | 872 | ||
922 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | 873 | static int vidioc_g_ext_ctrls (struct file *file, void *priv, |
923 | return -EINVAL; | 874 | struct v4l2_ext_controls *f) |
924 | return cx2341x_ext_ctrls(&dev->params, f, cmd); | 875 | { |
925 | } | 876 | struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; |
926 | case VIDIOC_S_EXT_CTRLS: | ||
927 | { | ||
928 | struct v4l2_ext_controls *f = arg; | ||
929 | struct cx2341x_mpeg_params p; | ||
930 | int err; | ||
931 | |||
932 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
933 | return -EINVAL; | ||
934 | p = dev->params; | ||
935 | err = cx2341x_ext_ctrls(&p, VIDIOC_S_EXT_CTRLS, cmd); | ||
936 | if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) { | ||
937 | err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); | ||
938 | dev->params = p; | ||
939 | } | ||
940 | return err; | ||
941 | } | ||
942 | case VIDIOC_TRY_EXT_CTRLS: | ||
943 | { | ||
944 | struct v4l2_ext_controls *f = arg; | ||
945 | struct cx2341x_mpeg_params p; | ||
946 | int err; | ||
947 | |||
948 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) | ||
949 | return -EINVAL; | ||
950 | p = dev->params; | ||
951 | err = cx2341x_ext_ctrls(&p, VIDIOC_TRY_EXT_CTRLS, cmd); | ||
952 | return err; | ||
953 | } | ||
954 | case VIDIOC_S_FREQUENCY: | ||
955 | { | ||
956 | struct v4l2_frequency *f = arg; | ||
957 | 877 | ||
958 | blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, | 878 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) |
959 | BLACKBIRD_END_NOW, | 879 | return -EINVAL; |
960 | BLACKBIRD_MPEG_CAPTURE, | 880 | return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS); |
961 | BLACKBIRD_RAW_BITS_NONE); | 881 | } |
962 | 882 | ||
963 | cx88_set_freq (core,f); | 883 | static int vidioc_s_ext_ctrls (struct file *file, void *priv, |
884 | struct v4l2_ext_controls *f) | ||
885 | { | ||
886 | struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; | ||
887 | struct cx2341x_mpeg_params p; | ||
888 | int err; | ||
964 | 889 | ||
965 | blackbird_initialize_codec(dev); | 890 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) |
966 | cx88_set_scale(dev->core, dev->width, dev->height, | 891 | return -EINVAL; |
967 | fh->mpegq.field); | 892 | p = dev->params; |
968 | return 0; | 893 | err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS); |
969 | } | 894 | if (!err) { |
970 | case VIDIOC_LOG_STATUS: | 895 | err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); |
971 | { | 896 | dev->params = p; |
972 | char name[32 + 2]; | ||
973 | |||
974 | snprintf(name, sizeof(name), "%s/2", core->name); | ||
975 | printk("%s/2: ============ START LOG STATUS ============\n", | ||
976 | core->name); | ||
977 | cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL); | ||
978 | cx2341x_log_status(&dev->params, name); | ||
979 | printk("%s/2: ============= END LOG STATUS =============\n", | ||
980 | core->name); | ||
981 | return 0; | ||
982 | } | 897 | } |
983 | case VIDIOC_QUERYMENU: | 898 | return err; |
984 | return blackbird_querymenu(dev, arg); | 899 | } |
985 | case VIDIOC_QUERYCTRL: | ||
986 | { | ||
987 | struct v4l2_queryctrl *qctrl = arg; | ||
988 | 900 | ||
989 | if (blackbird_queryctrl(dev, qctrl) == 0) | 901 | static int vidioc_try_ext_ctrls (struct file *file, void *priv, |
990 | return 0; | 902 | struct v4l2_ext_controls *f) |
903 | { | ||
904 | struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; | ||
905 | struct cx2341x_mpeg_params p; | ||
906 | int err; | ||
991 | 907 | ||
992 | struct v4l2_queryctrl *qctrl = arg; | 908 | if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) |
909 | return -EINVAL; | ||
910 | p = dev->params; | ||
911 | err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS); | ||
993 | 912 | ||
994 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | 913 | return err; |
995 | if (unlikely(qctrl->id == 0)) | 914 | } |
996 | return -EINVAL; | ||
997 | return cx8800_ctrl_query(qctrl); | ||
998 | } | ||
999 | 915 | ||
1000 | /* ------ input switching ---------- */ | 916 | static int vidioc_s_frequency (struct file *file, void *priv, |
1001 | case VIDIOC_ENUMINPUT: | 917 | struct v4l2_frequency *f) |
1002 | { | 918 | { |
1003 | static const char *iname[] = { | 919 | struct cx8802_fh *fh = priv; |
1004 | [ CX88_VMUX_COMPOSITE1 ] = "Composite1", | 920 | struct cx8802_dev *dev = fh->dev; |
1005 | [ CX88_VMUX_COMPOSITE2 ] = "Composite2", | 921 | struct cx88_core *core = dev->core; |
1006 | [ CX88_VMUX_COMPOSITE3 ] = "Composite3", | ||
1007 | [ CX88_VMUX_COMPOSITE4 ] = "Composite4", | ||
1008 | [ CX88_VMUX_SVIDEO ] = "S-Video", | ||
1009 | [ CX88_VMUX_TELEVISION ] = "Television", | ||
1010 | [ CX88_VMUX_CABLE ] = "Cable TV", | ||
1011 | [ CX88_VMUX_DVB ] = "DVB", | ||
1012 | [ CX88_VMUX_DEBUG ] = "for debug only", | ||
1013 | }; | ||
1014 | struct v4l2_input *i = arg; | ||
1015 | unsigned int n; | ||
1016 | |||
1017 | n = i->index; | ||
1018 | if (n >= 4) | ||
1019 | return -EINVAL; | ||
1020 | if (0 == INPUT(n)->type) | ||
1021 | return -EINVAL; | ||
1022 | memset(i,0,sizeof(*i)); | ||
1023 | i->index = n; | ||
1024 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1025 | strcpy(i->name,iname[INPUT(n)->type]); | ||
1026 | if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || | ||
1027 | (CX88_VMUX_CABLE == INPUT(n)->type)) | ||
1028 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1029 | for (n = 0; n < ARRAY_SIZE(tvnorms); n++) | ||
1030 | i->std |= tvnorms[n].id; | ||
1031 | return 0; | ||
1032 | } | ||
1033 | case VIDIOC_G_CTRL: | ||
1034 | return cx88_get_control(core,arg); | ||
1035 | case VIDIOC_S_CTRL: | ||
1036 | return cx88_set_control(core,arg); | ||
1037 | 922 | ||
1038 | case VIDIOC_G_FREQUENCY: | 923 | blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, |
1039 | { | 924 | BLACKBIRD_END_NOW, |
1040 | struct v4l2_frequency *f = arg; | 925 | BLACKBIRD_MPEG_CAPTURE, |
926 | BLACKBIRD_RAW_BITS_NONE); | ||
927 | cx88_set_freq (core,f); | ||
928 | blackbird_initialize_codec(dev); | ||
929 | cx88_set_scale(dev->core, dev->width, dev->height, | ||
930 | fh->mpegq.field); | ||
931 | return 0; | ||
932 | } | ||
1041 | 933 | ||
1042 | memset(f,0,sizeof(*f)); | 934 | static int vidioc_log_status (struct file *file, void *priv) |
935 | { | ||
936 | struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; | ||
937 | struct cx88_core *core = dev->core; | ||
938 | char name[32 + 2]; | ||
939 | |||
940 | snprintf(name, sizeof(name), "%s/2", core->name); | ||
941 | printk("%s/2: ============ START LOG STATUS ============\n", | ||
942 | core->name); | ||
943 | cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL); | ||
944 | cx2341x_log_status(&dev->params, name); | ||
945 | printk("%s/2: ============= END LOG STATUS =============\n", | ||
946 | core->name); | ||
947 | return 0; | ||
948 | } | ||
1043 | 949 | ||
1044 | if (UNSET == core->tuner_type) | 950 | static int vidioc_queryctrl (struct file *file, void *priv, |
1045 | return -EINVAL; | 951 | struct v4l2_queryctrl *qctrl) |
952 | { | ||
953 | struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; | ||
1046 | 954 | ||
1047 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ | 955 | if (blackbird_queryctrl(dev, qctrl) == 0) |
1048 | f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | 956 | return 0; |
1049 | f->frequency = core->freq; | ||
1050 | 957 | ||
1051 | cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); | 958 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); |
959 | if (unlikely(qctrl->id == 0)) | ||
960 | return -EINVAL; | ||
961 | return cx8800_ctrl_query(qctrl); | ||
962 | } | ||
1052 | 963 | ||
1053 | return 0; | 964 | static int vidioc_enum_input (struct file *file, void *priv, |
1054 | } | 965 | struct v4l2_input *i) |
1055 | case VIDIOC_G_INPUT: | 966 | { |
1056 | { | 967 | struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; |
1057 | unsigned int *i = arg; | 968 | return cx88_enum_input (core,i); |
969 | } | ||
1058 | 970 | ||
1059 | *i = core->input; | 971 | static int vidioc_g_ctrl (struct file *file, void *priv, |
1060 | return 0; | 972 | struct v4l2_control *ctl) |
1061 | } | 973 | { |
1062 | case VIDIOC_S_INPUT: | 974 | struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; |
1063 | { | 975 | return |
1064 | unsigned int *i = arg; | 976 | cx88_get_control(core,ctl); |
1065 | 977 | } | |
1066 | if (*i >= 4) | ||
1067 | return -EINVAL; | ||
1068 | mutex_lock(&core->lock); | ||
1069 | cx88_newstation(core); | ||
1070 | cx88_video_mux(core,*i); | ||
1071 | mutex_unlock(&core->lock); | ||
1072 | return 0; | ||
1073 | } | ||
1074 | 978 | ||
979 | static int vidioc_s_ctrl (struct file *file, void *priv, | ||
980 | struct v4l2_control *ctl) | ||
981 | { | ||
982 | struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; | ||
983 | return | ||
984 | cx88_set_control(core,ctl); | ||
985 | } | ||
1075 | 986 | ||
1076 | case VIDIOC_G_TUNER: | 987 | static int vidioc_g_frequency (struct file *file, void *priv, |
1077 | { | 988 | struct v4l2_frequency *f) |
1078 | struct v4l2_tuner *t = arg; | 989 | { |
1079 | u32 reg; | 990 | struct cx8802_fh *fh = priv; |
991 | struct cx88_core *core = fh->dev->core; | ||
1080 | 992 | ||
1081 | if (UNSET == core->tuner_type) | 993 | if (unlikely(UNSET == core->tuner_type)) |
1082 | return -EINVAL; | 994 | return -EINVAL; |
1083 | if (0 != t->index) | ||
1084 | return -EINVAL; | ||
1085 | 995 | ||
1086 | memset(t,0,sizeof(*t)); | 996 | f->type = V4L2_TUNER_ANALOG_TV; |
1087 | strcpy(t->name, "Television"); | 997 | f->frequency = core->freq; |
1088 | t->type = V4L2_TUNER_ANALOG_TV; | 998 | cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); |
1089 | t->capability = V4L2_TUNER_CAP_NORM; | ||
1090 | t->rangehigh = 0xffffffffUL; | ||
1091 | 999 | ||
1092 | cx88_get_stereo(core ,t); | 1000 | return 0; |
1093 | reg = cx_read(MO_DEVICE_STATUS); | 1001 | } |
1094 | t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; | ||
1095 | return 0; | ||
1096 | } | ||
1097 | case VIDIOC_S_TUNER: | ||
1098 | { | ||
1099 | struct v4l2_tuner *t = arg; | ||
1100 | |||
1101 | if (UNSET == core->tuner_type) | ||
1102 | return -EINVAL; | ||
1103 | if (0 != t->index) | ||
1104 | return -EINVAL; | ||
1105 | cx88_set_stereo(core, t->audmode, 1); | ||
1106 | return 0; | ||
1107 | } | ||
1108 | /* ---------- tv norms ---------- */ | ||
1109 | case VIDIOC_S_STD: | ||
1110 | { | ||
1111 | v4l2_std_id *id = arg; | ||
1112 | unsigned int i; | ||
1113 | |||
1114 | for(i = 0; i < ARRAY_SIZE(tvnorms); i++) | ||
1115 | if (*id & tvnorms[i].id) | ||
1116 | break; | ||
1117 | if (i == ARRAY_SIZE(tvnorms)) | ||
1118 | return -EINVAL; | ||
1119 | |||
1120 | mutex_lock(&core->lock); | ||
1121 | cx88_set_tvnorm(core,tvnorms[i].id); | ||
1122 | mutex_unlock(&core->lock); | ||
1123 | return 0; | ||
1124 | } | ||
1125 | case VIDIOC_ENUMSTD: | ||
1126 | { | ||
1127 | struct v4l2_standard *e = arg; | ||
1128 | unsigned int i; | ||
1129 | |||
1130 | i = e->index; | ||
1131 | if (i >= ARRAY_SIZE(tvnorms)) | ||
1132 | return -EINVAL; | ||
1133 | err = v4l2_video_std_construct(e, tvnorms[e->index].id, | ||
1134 | tvnorms[e->index].name); | ||
1135 | e->index = i; | ||
1136 | if (err < 0) | ||
1137 | return err; | ||
1138 | return 0; | ||
1139 | } | ||
1140 | case VIDIOC_G_STD: | ||
1141 | { | ||
1142 | v4l2_std_id *id = arg; | ||
1143 | 1002 | ||
1144 | *id = core->tvnorm; | 1003 | static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) |
1145 | return 0; | 1004 | { |
1146 | } | 1005 | struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; |
1147 | 1006 | ||
1148 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1007 | *i = core->input; |
1149 | /* ioctls to allow direct acces to the cx2388x registers */ | 1008 | return 0; |
1150 | case VIDIOC_INT_G_REGISTER: | 1009 | } |
1151 | { | ||
1152 | struct v4l2_register *reg = arg; | ||
1153 | 1010 | ||
1154 | if (reg->i2c_id != 0) | 1011 | static int vidioc_s_input (struct file *file, void *priv, unsigned int i) |
1155 | return -EINVAL; | 1012 | { |
1156 | /* cx2388x has a 24-bit register space */ | 1013 | struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; |
1157 | reg->val = cx_read(reg->reg&0xffffff); | ||
1158 | return 0; | ||
1159 | } | ||
1160 | case VIDIOC_INT_S_REGISTER: | ||
1161 | { | ||
1162 | struct v4l2_register *reg = arg; | ||
1163 | |||
1164 | if (reg->i2c_id != 0) | ||
1165 | return -EINVAL; | ||
1166 | if (!capable(CAP_SYS_ADMIN)) | ||
1167 | return -EPERM; | ||
1168 | cx_write(reg->reg&0xffffff, reg->val); | ||
1169 | return 0; | ||
1170 | } | ||
1171 | #endif | ||
1172 | 1014 | ||
1173 | default: | 1015 | if (i >= 4) |
1174 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | 1016 | return -EINVAL; |
1175 | driver_ioctl); | 1017 | |
1176 | } | 1018 | mutex_lock(&core->lock); |
1019 | cx88_newstation(core); | ||
1020 | cx88_video_mux(core,i); | ||
1021 | mutex_unlock(&core->lock); | ||
1177 | return 0; | 1022 | return 0; |
1178 | } | 1023 | } |
1179 | 1024 | ||
1180 | int (*cx88_ioctl_hook)(struct inode *inode, struct file *file, | 1025 | static int vidioc_g_tuner (struct file *file, void *priv, |
1181 | unsigned int cmd, void *arg); | 1026 | struct v4l2_tuner *t) |
1182 | unsigned int (*cx88_ioctl_translator)(unsigned int cmd); | 1027 | { |
1028 | struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; | ||
1029 | u32 reg; | ||
1030 | |||
1031 | if (unlikely(UNSET == core->tuner_type)) | ||
1032 | return -EINVAL; | ||
1033 | |||
1034 | strcpy(t->name, "Television"); | ||
1035 | t->type = V4L2_TUNER_ANALOG_TV; | ||
1036 | t->capability = V4L2_TUNER_CAP_NORM; | ||
1037 | t->rangehigh = 0xffffffffUL; | ||
1038 | |||
1039 | cx88_get_stereo(core ,t); | ||
1040 | reg = cx_read(MO_DEVICE_STATUS); | ||
1041 | t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; | ||
1042 | return 0; | ||
1043 | } | ||
1183 | 1044 | ||
1184 | static unsigned int mpeg_translate_ioctl(unsigned int cmd) | 1045 | static int vidioc_s_tuner (struct file *file, void *priv, |
1046 | struct v4l2_tuner *t) | ||
1185 | { | 1047 | { |
1186 | return cmd; | 1048 | struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; |
1049 | |||
1050 | if (UNSET == core->tuner_type) | ||
1051 | return -EINVAL; | ||
1052 | if (0 != t->index) | ||
1053 | return -EINVAL; | ||
1054 | |||
1055 | cx88_set_stereo(core, t->audmode, 1); | ||
1056 | return 0; | ||
1187 | } | 1057 | } |
1188 | 1058 | ||
1189 | static int mpeg_ioctl(struct inode *inode, struct file *file, | 1059 | static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) |
1190 | unsigned int cmd, unsigned long arg) | ||
1191 | { | 1060 | { |
1192 | cmd = cx88_ioctl_translator( cmd ); | 1061 | struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; |
1193 | return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook); | 1062 | |
1063 | mutex_lock(&core->lock); | ||
1064 | cx88_set_tvnorm(core,*id); | ||
1065 | mutex_unlock(&core->lock); | ||
1066 | return 0; | ||
1194 | } | 1067 | } |
1195 | 1068 | ||
1069 | /* FIXME: cx88_ioctl_hook not implemented */ | ||
1070 | |||
1196 | static int mpeg_open(struct inode *inode, struct file *file) | 1071 | static int mpeg_open(struct inode *inode, struct file *file) |
1197 | { | 1072 | { |
1198 | int minor = iminor(inode); | 1073 | int minor = iminor(inode); |
@@ -1318,17 +1193,47 @@ static const struct file_operations mpeg_fops = | |||
1318 | .read = mpeg_read, | 1193 | .read = mpeg_read, |
1319 | .poll = mpeg_poll, | 1194 | .poll = mpeg_poll, |
1320 | .mmap = mpeg_mmap, | 1195 | .mmap = mpeg_mmap, |
1321 | .ioctl = mpeg_ioctl, | 1196 | .ioctl = video_ioctl2, |
1322 | .llseek = no_llseek, | 1197 | .llseek = no_llseek, |
1323 | }; | 1198 | }; |
1324 | 1199 | ||
1325 | static struct video_device cx8802_mpeg_template = | 1200 | static struct video_device cx8802_mpeg_template = |
1326 | { | 1201 | { |
1327 | .name = "cx8802", | 1202 | .name = "cx8802", |
1328 | .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER, | 1203 | .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER, |
1329 | .hardware = 0, | 1204 | .fops = &mpeg_fops, |
1330 | .fops = &mpeg_fops, | 1205 | .minor = -1, |
1331 | .minor = -1, | 1206 | .vidioc_querymenu = vidioc_querymenu, |
1207 | .vidioc_querycap = vidioc_querycap, | ||
1208 | .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, | ||
1209 | .vidioc_g_fmt_cap = vidioc_g_fmt_cap, | ||
1210 | .vidioc_try_fmt_cap = vidioc_try_fmt_cap, | ||
1211 | .vidioc_s_fmt_cap = vidioc_s_fmt_cap, | ||
1212 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1213 | .vidioc_querybuf = vidioc_querybuf, | ||
1214 | .vidioc_qbuf = vidioc_qbuf, | ||
1215 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1216 | .vidioc_streamon = vidioc_streamon, | ||
1217 | .vidioc_streamoff = vidioc_streamoff, | ||
1218 | .vidioc_g_mpegcomp = vidioc_g_mpegcomp, | ||
1219 | .vidioc_s_mpegcomp = vidioc_s_mpegcomp, | ||
1220 | .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, | ||
1221 | .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, | ||
1222 | .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, | ||
1223 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1224 | .vidioc_log_status = vidioc_log_status, | ||
1225 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1226 | .vidioc_enum_input = vidioc_enum_input, | ||
1227 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1228 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1229 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1230 | .vidioc_g_input = vidioc_g_input, | ||
1231 | .vidioc_s_input = vidioc_s_input, | ||
1232 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1233 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1234 | .vidioc_s_std = vidioc_s_std, | ||
1235 | .tvnorms = CX88_NORMS, | ||
1236 | .current_norm = V4L2_STD_PAL_BG, | ||
1332 | }; | 1237 | }; |
1333 | 1238 | ||
1334 | /* ------------------------------------------------------------------ */ | 1239 | /* ------------------------------------------------------------------ */ |
@@ -1423,6 +1328,8 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) | |||
1423 | cx2341x_fill_defaults(&dev->params); | 1328 | cx2341x_fill_defaults(&dev->params); |
1424 | dev->params.port = CX2341X_PORT_STREAMING; | 1329 | dev->params.port = CX2341X_PORT_STREAMING; |
1425 | 1330 | ||
1331 | cx8802_mpeg_template.current_norm = core->tvnorm; | ||
1332 | |||
1426 | if (core->tvnorm & V4L2_STD_525_60) { | 1333 | if (core->tvnorm & V4L2_STD_525_60) { |
1427 | dev->height = 480; | 1334 | dev->height = 480; |
1428 | } else { | 1335 | } else { |
@@ -1437,6 +1344,11 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) | |||
1437 | blackbird_register_video(dev); | 1344 | blackbird_register_video(dev); |
1438 | 1345 | ||
1439 | /* initial device configuration: needed ? */ | 1346 | /* initial device configuration: needed ? */ |
1347 | mutex_lock(&dev->core->lock); | ||
1348 | // init_controls(core); | ||
1349 | cx88_set_tvnorm(core,core->tvnorm); | ||
1350 | cx88_video_mux(core,0); | ||
1351 | mutex_unlock(&dev->core->lock); | ||
1440 | 1352 | ||
1441 | return 0; | 1353 | return 0; |
1442 | 1354 | ||
@@ -1471,8 +1383,6 @@ static int blackbird_init(void) | |||
1471 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", | 1383 | printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n", |
1472 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | 1384 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); |
1473 | #endif | 1385 | #endif |
1474 | cx88_ioctl_hook = mpeg_do_ioctl; | ||
1475 | cx88_ioctl_translator = mpeg_translate_ioctl; | ||
1476 | return cx8802_register_driver(&cx8802_blackbird_driver); | 1386 | return cx8802_register_driver(&cx8802_blackbird_driver); |
1477 | } | 1387 | } |
1478 | 1388 | ||
@@ -1484,8 +1394,8 @@ static void blackbird_fini(void) | |||
1484 | module_init(blackbird_init); | 1394 | module_init(blackbird_init); |
1485 | module_exit(blackbird_fini); | 1395 | module_exit(blackbird_fini); |
1486 | 1396 | ||
1487 | EXPORT_SYMBOL(cx88_ioctl_hook); | 1397 | module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644); |
1488 | EXPORT_SYMBOL(cx88_ioctl_translator); | 1398 | MODULE_PARM_DESC(debug,"enable debug messages [video]"); |
1489 | 1399 | ||
1490 | /* ----------------------------------------------------------- */ | 1400 | /* ----------------------------------------------------------- */ |
1491 | /* | 1401 | /* |