diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-01-20 11:58:17 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-02-21 10:34:42 -0500 |
commit | 8d87cb9f31930c7ac25d03043fa90cbd5313fe26 (patch) | |
tree | f98c3dee7886ed7c2405c9e97ad534c1ea46c6c6 /drivers/media/video/cx88/cx88-video.c | |
parent | fd69496461050296fb0fdd9acf6d789d27a0ef44 (diff) |
V4L/DVB (5097): Convert cx8800 driver to video_ioctl2 handler
video_ioctl2 handler provides V4L2 API parsing.
Using it makes the driver simpler, and isolates API parsing.
This allows future reusage of driver controls using other ways, like sysfs
and/or procfs and increases isolation of driver-specific handling from the
generic common ioctl processing.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/cx88/cx88-video.c')
-rw-r--r-- | drivers/media/video/cx88/cx88-video.c | 1072 |
1 files changed, 466 insertions, 606 deletions
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index c86a7e06235..d9d1a07f3a4 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -1,3 +1,4 @@ | |||
1 | |||
1 | /* | 2 | /* |
2 | * | 3 | * |
3 | * device driver for Conexant 2388x based TV cards | 4 | * device driver for Conexant 2388x based TV cards |
@@ -5,6 +6,11 @@ | |||
5 | * | 6 | * |
6 | * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | 7 | * (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] |
7 | * | 8 | * |
9 | * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> | ||
10 | * - Multituner support | ||
11 | * - video_ioctl2 conversion | ||
12 | * - PAL/M fixes | ||
13 | * | ||
8 | * 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 |
9 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 16 | * the Free Software Foundation; either version 2 of the License, or |
@@ -80,62 +86,47 @@ static LIST_HEAD(cx8800_devlist); | |||
80 | /* ------------------------------------------------------------------- */ | 86 | /* ------------------------------------------------------------------- */ |
81 | /* static data */ | 87 | /* static data */ |
82 | 88 | ||
83 | static struct cx88_tvnorm tvnorms[] = { | 89 | static struct v4l2_tvnorm tvnorms[] = { |
84 | { | 90 | { |
85 | .name = "NTSC-M", | 91 | .name = "NTSC-M", |
86 | .id = V4L2_STD_NTSC_M, | 92 | .id = V4L2_STD_NTSC_M, |
87 | .cxiformat = VideoFormatNTSC, | ||
88 | .cxoformat = 0x181f0008, | ||
89 | },{ | 93 | },{ |
90 | .name = "NTSC-JP", | 94 | .name = "NTSC-JP", |
91 | .id = V4L2_STD_NTSC_M_JP, | 95 | .id = V4L2_STD_NTSC_M_JP, |
92 | .cxiformat = VideoFormatNTSCJapan, | ||
93 | .cxoformat = 0x181f0008, | ||
94 | },{ | 96 | },{ |
95 | .name = "PAL-BG", | 97 | .name = "PAL-BG", |
96 | .id = V4L2_STD_PAL_BG, | 98 | .id = V4L2_STD_PAL_BG, |
97 | .cxiformat = VideoFormatPAL, | ||
98 | .cxoformat = 0x181f0008, | ||
99 | },{ | 99 | },{ |
100 | .name = "PAL-DK", | 100 | .name = "PAL-DK", |
101 | .id = V4L2_STD_PAL_DK, | 101 | .id = V4L2_STD_PAL_DK, |
102 | .cxiformat = VideoFormatPAL, | ||
103 | .cxoformat = 0x181f0008, | ||
104 | },{ | 102 | },{ |
105 | .name = "PAL-I", | 103 | .name = "PAL-I", |
106 | .id = V4L2_STD_PAL_I, | 104 | .id = V4L2_STD_PAL_I, |
107 | .cxiformat = VideoFormatPAL, | ||
108 | .cxoformat = 0x181f0008, | ||
109 | },{ | 105 | },{ |
110 | .name = "PAL-M", | 106 | .name = "PAL-M", |
111 | .id = V4L2_STD_PAL_M, | 107 | .id = V4L2_STD_PAL_M, |
112 | .cxiformat = VideoFormatPALM, | ||
113 | .cxoformat = 0x1c1f0008, | ||
114 | },{ | 108 | },{ |
115 | .name = "PAL-N", | 109 | .name = "PAL-N", |
116 | .id = V4L2_STD_PAL_N, | 110 | .id = V4L2_STD_PAL_N, |
117 | .cxiformat = VideoFormatPALN, | ||
118 | .cxoformat = 0x1c1f0008, | ||
119 | },{ | 111 | },{ |
120 | .name = "PAL-Nc", | 112 | .name = "PAL-Nc", |
121 | .id = V4L2_STD_PAL_Nc, | 113 | .id = V4L2_STD_PAL_Nc, |
122 | .cxiformat = VideoFormatPALNC, | ||
123 | .cxoformat = 0x1c1f0008, | ||
124 | },{ | 114 | },{ |
125 | .name = "PAL-60", | 115 | .name = "PAL-60", |
126 | .id = V4L2_STD_PAL_60, | 116 | .id = V4L2_STD_PAL_60, |
127 | .cxiformat = VideoFormatPAL60, | ||
128 | .cxoformat = 0x181f0008, | ||
129 | },{ | 117 | },{ |
130 | .name = "SECAM-L", | 118 | .name = "SECAM-L", |
131 | .id = V4L2_STD_SECAM_L, | 119 | .id = V4L2_STD_SECAM_L, |
132 | .cxiformat = VideoFormatSECAM, | ||
133 | .cxoformat = 0x181f0008, | ||
134 | },{ | 120 | },{ |
135 | .name = "SECAM-DK", | 121 | .name = "SECAM-DK", |
136 | .id = V4L2_STD_SECAM_DK, | 122 | .id = V4L2_STD_SECAM_DK, |
137 | .cxiformat = VideoFormatSECAM, | 123 | } |
138 | .cxoformat = 0x181f0008, | 124 | }; |
125 | |||
126 | static struct v4l2_tvnorm radionorms[] = { | ||
127 | { | ||
128 | .name = "RADIO", | ||
129 | .id = 0, | ||
139 | } | 130 | } |
140 | }; | 131 | }; |
141 | 132 | ||
@@ -364,14 +355,6 @@ int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl) | |||
364 | } | 355 | } |
365 | EXPORT_SYMBOL(cx8800_ctrl_query); | 356 | EXPORT_SYMBOL(cx8800_ctrl_query); |
366 | 357 | ||
367 | static int cx88_queryctrl(struct v4l2_queryctrl *qctrl) | ||
368 | { | ||
369 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
370 | if (qctrl->id == 0) | ||
371 | return -EINVAL; | ||
372 | return cx8800_ctrl_query(qctrl); | ||
373 | } | ||
374 | |||
375 | /* ------------------------------------------------------------------- */ | 358 | /* ------------------------------------------------------------------- */ |
376 | /* resource management */ | 359 | /* resource management */ |
377 | 360 | ||
@@ -944,19 +927,20 @@ video_mmap(struct file *file, struct vm_area_struct * vma) | |||
944 | } | 927 | } |
945 | 928 | ||
946 | /* ------------------------------------------------------------------ */ | 929 | /* ------------------------------------------------------------------ */ |
930 | /* VIDEO CTRL IOCTLS */ | ||
947 | 931 | ||
948 | /* static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */ | 932 | static int vidioc_g_ctrl (struct file *file, void *priv, |
949 | static int get_control(struct cx88_core *core, struct v4l2_control *ctl) | 933 | struct v4l2_control *ctl) |
950 | { | 934 | { |
951 | /* struct cx88_core *core = dev->core; */ | 935 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
952 | struct cx88_ctrl *c = NULL; | 936 | struct cx88_ctrl *c = NULL; |
953 | u32 value; | 937 | u32 value; |
954 | int i; | 938 | int i; |
955 | 939 | ||
956 | for (i = 0; i < CX8800_CTLS; i++) | 940 | for (i = 0; i < CX8800_CTLS; i++) |
957 | if (cx8800_ctls[i].v.id == ctl->id) | 941 | if (cx8800_ctls[i].v.id == ctl->id) |
958 | c = &cx8800_ctls[i]; | 942 | c = &cx8800_ctls[i]; |
959 | if (NULL == c) | 943 | if (unlikely(NULL == c)) |
960 | return -EINVAL; | 944 | return -EINVAL; |
961 | 945 | ||
962 | value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); | 946 | value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); |
@@ -978,19 +962,18 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl) | |||
978 | return 0; | 962 | return 0; |
979 | } | 963 | } |
980 | 964 | ||
981 | /* static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */ | ||
982 | static int set_control(struct cx88_core *core, struct v4l2_control *ctl) | 965 | static int set_control(struct cx88_core *core, struct v4l2_control *ctl) |
983 | { | 966 | { |
984 | /* struct cx88_core *core = dev->core; */ | ||
985 | struct cx88_ctrl *c = NULL; | 967 | struct cx88_ctrl *c = NULL; |
986 | u32 value,mask; | 968 | u32 value,mask; |
987 | int i; | 969 | int i; |
970 | |||
988 | for (i = 0; i < CX8800_CTLS; i++) { | 971 | for (i = 0; i < CX8800_CTLS; i++) { |
989 | if (cx8800_ctls[i].v.id == ctl->id) { | 972 | if (cx8800_ctls[i].v.id == ctl->id) { |
990 | c = &cx8800_ctls[i]; | 973 | c = &cx8800_ctls[i]; |
991 | } | 974 | } |
992 | } | 975 | } |
993 | if (NULL == c) | 976 | if (unlikely(NULL == c)) |
994 | return -EINVAL; | 977 | return -EINVAL; |
995 | 978 | ||
996 | if (ctl->value < c->v.minimum) | 979 | if (ctl->value < c->v.minimum) |
@@ -1042,648 +1025,483 @@ static void init_controls(struct cx88_core *core) | |||
1042 | for (i = 0; i < CX8800_CTLS; i++) { | 1025 | for (i = 0; i < CX8800_CTLS; i++) { |
1043 | ctrl.id=cx8800_ctls[i].v.id; | 1026 | ctrl.id=cx8800_ctls[i].v.id; |
1044 | ctrl.value=cx8800_ctls[i].v.default_value; | 1027 | ctrl.value=cx8800_ctls[i].v.default_value; |
1028 | |||
1045 | set_control(core, &ctrl); | 1029 | set_control(core, &ctrl); |
1046 | } | 1030 | } |
1047 | } | 1031 | } |
1048 | 1032 | ||
1049 | /* ------------------------------------------------------------------ */ | 1033 | /* ------------------------------------------------------------------ */ |
1034 | /* VIDEO IOCTLS */ | ||
1035 | |||
1036 | static int vidioc_g_fmt_cap (struct file *file, void *priv, | ||
1037 | struct v4l2_format *f) | ||
1038 | { | ||
1039 | struct cx8800_fh *fh = priv; | ||
1040 | |||
1041 | f->fmt.pix.width = fh->width; | ||
1042 | f->fmt.pix.height = fh->height; | ||
1043 | f->fmt.pix.field = fh->vidq.field; | ||
1044 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | ||
1045 | f->fmt.pix.bytesperline = | ||
1046 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | ||
1047 | f->fmt.pix.sizeimage = | ||
1048 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1049 | return 0; | ||
1050 | } | ||
1050 | 1051 | ||
1051 | static int cx8800_g_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, | 1052 | static int vidioc_try_fmt_cap (struct file *file, void *priv, |
1052 | struct v4l2_format *f) | 1053 | struct v4l2_format *f) |
1053 | { | 1054 | { |
1054 | switch (f->type) { | 1055 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1055 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1056 | struct cx8800_fmt *fmt; |
1056 | memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); | 1057 | enum v4l2_field field; |
1057 | f->fmt.pix.width = fh->width; | 1058 | unsigned int maxw, maxh; |
1058 | f->fmt.pix.height = fh->height; | 1059 | |
1059 | f->fmt.pix.field = fh->vidq.field; | 1060 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1060 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | 1061 | if (NULL == fmt) |
1061 | f->fmt.pix.bytesperline = | 1062 | return -EINVAL; |
1062 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | 1063 | |
1063 | f->fmt.pix.sizeimage = | 1064 | field = f->fmt.pix.field; |
1064 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 1065 | maxw = norm_maxw(core->tvnorm); |
1065 | return 0; | 1066 | maxh = norm_maxh(core->tvnorm); |
1066 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 1067 | |
1067 | cx8800_vbi_fmt(dev, f); | 1068 | if (V4L2_FIELD_ANY == field) { |
1068 | return 0; | 1069 | field = (f->fmt.pix.height > maxh/2) |
1070 | ? V4L2_FIELD_INTERLACED | ||
1071 | : V4L2_FIELD_BOTTOM; | ||
1072 | } | ||
1073 | |||
1074 | switch (field) { | ||
1075 | case V4L2_FIELD_TOP: | ||
1076 | case V4L2_FIELD_BOTTOM: | ||
1077 | maxh = maxh / 2; | ||
1078 | break; | ||
1079 | case V4L2_FIELD_INTERLACED: | ||
1080 | break; | ||
1069 | default: | 1081 | default: |
1070 | return -EINVAL; | 1082 | return -EINVAL; |
1071 | } | 1083 | } |
1084 | |||
1085 | f->fmt.pix.field = field; | ||
1086 | if (f->fmt.pix.height < 32) | ||
1087 | f->fmt.pix.height = 32; | ||
1088 | if (f->fmt.pix.height > maxh) | ||
1089 | f->fmt.pix.height = maxh; | ||
1090 | if (f->fmt.pix.width < 48) | ||
1091 | f->fmt.pix.width = 48; | ||
1092 | if (f->fmt.pix.width > maxw) | ||
1093 | f->fmt.pix.width = maxw; | ||
1094 | f->fmt.pix.width &= ~0x03; | ||
1095 | f->fmt.pix.bytesperline = | ||
1096 | (f->fmt.pix.width * fmt->depth) >> 3; | ||
1097 | f->fmt.pix.sizeimage = | ||
1098 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1099 | |||
1100 | return 0; | ||
1072 | } | 1101 | } |
1073 | 1102 | ||
1074 | static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, | 1103 | static int vidioc_s_fmt_cap (struct file *file, void *priv, |
1075 | struct v4l2_format *f) | 1104 | struct v4l2_format *f) |
1076 | { | 1105 | { |
1077 | struct cx88_core *core = dev->core; | 1106 | struct cx8800_fh *fh = priv; |
1107 | int err = vidioc_try_fmt_cap (file,priv,f); | ||
1078 | 1108 | ||
1079 | switch (f->type) { | 1109 | if (0 != err) |
1080 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1110 | return err; |
1081 | { | 1111 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); |
1082 | struct cx8800_fmt *fmt; | 1112 | fh->width = f->fmt.pix.width; |
1083 | enum v4l2_field field; | 1113 | fh->height = f->fmt.pix.height; |
1084 | unsigned int maxw, maxh; | 1114 | fh->vidq.field = f->fmt.pix.field; |
1085 | 1115 | return 0; | |
1086 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 1116 | } |
1087 | if (NULL == fmt) | ||
1088 | return -EINVAL; | ||
1089 | |||
1090 | field = f->fmt.pix.field; | ||
1091 | maxw = norm_maxw(core->tvnorm); | ||
1092 | maxh = norm_maxh(core->tvnorm); | ||
1093 | |||
1094 | if (V4L2_FIELD_ANY == field) { | ||
1095 | field = (f->fmt.pix.height > maxh/2) | ||
1096 | ? V4L2_FIELD_INTERLACED | ||
1097 | : V4L2_FIELD_BOTTOM; | ||
1098 | } | ||
1099 | 1117 | ||
1100 | switch (field) { | 1118 | static int vidioc_querycap (struct file *file, void *priv, |
1101 | case V4L2_FIELD_TOP: | 1119 | struct v4l2_capability *cap) |
1102 | case V4L2_FIELD_BOTTOM: | 1120 | { |
1103 | maxh = maxh / 2; | 1121 | struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; |
1104 | break; | 1122 | struct cx88_core *core = dev->core; |
1105 | case V4L2_FIELD_INTERLACED: | ||
1106 | break; | ||
1107 | default: | ||
1108 | return -EINVAL; | ||
1109 | } | ||
1110 | 1123 | ||
1111 | f->fmt.pix.field = field; | 1124 | strcpy(cap->driver, "cx8800"); |
1112 | if (f->fmt.pix.height < 32) | 1125 | strlcpy(cap->card, cx88_boards[core->board].name, |
1113 | f->fmt.pix.height = 32; | 1126 | sizeof(cap->card)); |
1114 | if (f->fmt.pix.height > maxh) | 1127 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); |
1115 | f->fmt.pix.height = maxh; | 1128 | cap->version = CX88_VERSION_CODE; |
1116 | if (f->fmt.pix.width < 48) | 1129 | cap->capabilities = |
1117 | f->fmt.pix.width = 48; | 1130 | V4L2_CAP_VIDEO_CAPTURE | |
1118 | if (f->fmt.pix.width > maxw) | 1131 | V4L2_CAP_READWRITE | |
1119 | f->fmt.pix.width = maxw; | 1132 | V4L2_CAP_STREAMING | |
1120 | f->fmt.pix.width &= ~0x03; | 1133 | V4L2_CAP_VBI_CAPTURE; |
1121 | f->fmt.pix.bytesperline = | 1134 | if (UNSET != core->tuner_type) |
1122 | (f->fmt.pix.width * fmt->depth) >> 3; | 1135 | cap->capabilities |= V4L2_CAP_TUNER; |
1123 | f->fmt.pix.sizeimage = | 1136 | return 0; |
1124 | f->fmt.pix.height * f->fmt.pix.bytesperline; | 1137 | } |
1125 | 1138 | ||
1126 | return 0; | 1139 | static int vidioc_enum_fmt_cap (struct file *file, void *priv, |
1127 | } | 1140 | struct v4l2_fmtdesc *f) |
1128 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 1141 | { |
1129 | cx8800_vbi_fmt(dev, f); | 1142 | if (unlikely(f->index >= ARRAY_SIZE(formats))) |
1130 | return 0; | ||
1131 | default: | ||
1132 | return -EINVAL; | 1143 | return -EINVAL; |
1133 | } | 1144 | |
1145 | strlcpy(f->description,formats[f->index].name,sizeof(f->description)); | ||
1146 | f->pixelformat = formats[f->index].fourcc; | ||
1147 | |||
1148 | return 0; | ||
1134 | } | 1149 | } |
1135 | 1150 | ||
1136 | static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh, | 1151 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1137 | struct v4l2_format *f) | 1152 | static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf) |
1138 | { | 1153 | { |
1154 | struct cx8800_fh *fh = priv; | ||
1155 | struct videobuf_queue *q; | ||
1156 | struct v4l2_requestbuffers req; | ||
1157 | unsigned int i; | ||
1139 | int err; | 1158 | int err; |
1140 | 1159 | ||
1141 | switch (f->type) { | 1160 | q = get_queue(fh); |
1142 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 1161 | memset(&req,0,sizeof(req)); |
1143 | err = cx8800_try_fmt(dev,fh,f); | 1162 | req.type = q->type; |
1144 | if (0 != err) | 1163 | req.count = 8; |
1145 | return err; | 1164 | req.memory = V4L2_MEMORY_MMAP; |
1165 | err = videobuf_reqbufs(q,&req); | ||
1166 | if (err < 0) | ||
1167 | return err; | ||
1146 | 1168 | ||
1147 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | 1169 | mbuf->frames = req.count; |
1148 | fh->width = f->fmt.pix.width; | 1170 | mbuf->size = 0; |
1149 | fh->height = f->fmt.pix.height; | 1171 | for (i = 0; i < mbuf->frames; i++) { |
1150 | fh->vidq.field = f->fmt.pix.field; | 1172 | mbuf->offsets[i] = q->bufs[i]->boff; |
1151 | return 0; | 1173 | mbuf->size += q->bufs[i]->bsize; |
1152 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1153 | cx8800_vbi_fmt(dev, f); | ||
1154 | return 0; | ||
1155 | default: | ||
1156 | return -EINVAL; | ||
1157 | } | 1174 | } |
1175 | return 0; | ||
1158 | } | 1176 | } |
1177 | #endif | ||
1159 | 1178 | ||
1160 | /* | 1179 | |
1161 | * This function is _not_ called directly, but from | 1180 | static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) |
1162 | * video_generic_ioctl (and maybe others). userspace | ||
1163 | * copying is done already, arg is a kernel pointer. | ||
1164 | */ | ||
1165 | static int video_do_ioctl(struct inode *inode, struct file *file, | ||
1166 | unsigned int cmd, void *arg) | ||
1167 | { | 1181 | { |
1168 | struct cx8800_fh *fh = file->private_data; | 1182 | struct cx8800_fh *fh = priv; |
1169 | struct cx8800_dev *dev = fh->dev; | 1183 | return (videobuf_reqbufs(get_queue(fh), p)); |
1170 | struct cx88_core *core = dev->core; | 1184 | } |
1171 | int err; | ||
1172 | 1185 | ||
1173 | if (video_debug > 1) | 1186 | static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) |
1174 | v4l_print_ioctl(core->name,cmd); | 1187 | { |
1175 | switch (cmd) { | 1188 | struct cx8800_fh *fh = priv; |
1189 | return (videobuf_querybuf(get_queue(fh), p)); | ||
1190 | } | ||
1176 | 1191 | ||
1177 | /* --- capabilities ------------------------------------------ */ | 1192 | static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) |
1178 | case VIDIOC_QUERYCAP: | 1193 | { |
1179 | { | 1194 | struct cx8800_fh *fh = priv; |
1180 | struct v4l2_capability *cap = arg; | 1195 | return (videobuf_qbuf(get_queue(fh), p)); |
1181 | 1196 | } | |
1182 | memset(cap,0,sizeof(*cap)); | ||
1183 | strcpy(cap->driver, "cx8800"); | ||
1184 | strlcpy(cap->card, cx88_boards[core->board].name, | ||
1185 | sizeof(cap->card)); | ||
1186 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); | ||
1187 | cap->version = CX88_VERSION_CODE; | ||
1188 | cap->capabilities = | ||
1189 | V4L2_CAP_VIDEO_CAPTURE | | ||
1190 | V4L2_CAP_READWRITE | | ||
1191 | V4L2_CAP_STREAMING | | ||
1192 | V4L2_CAP_VBI_CAPTURE | | ||
1193 | 0; | ||
1194 | if (UNSET != core->tuner_type) | ||
1195 | cap->capabilities |= V4L2_CAP_TUNER; | ||
1196 | return 0; | ||
1197 | } | ||
1198 | 1197 | ||
1199 | /* --- capture ioctls ---------------------------------------- */ | 1198 | static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) |
1200 | case VIDIOC_ENUM_FMT: | 1199 | { |
1201 | { | 1200 | struct cx8800_fh *fh = priv; |
1202 | struct v4l2_fmtdesc *f = arg; | 1201 | return (videobuf_dqbuf(get_queue(fh), p, |
1203 | enum v4l2_buf_type type; | 1202 | file->f_flags & O_NONBLOCK)); |
1204 | unsigned int index; | 1203 | } |
1205 | |||
1206 | index = f->index; | ||
1207 | type = f->type; | ||
1208 | switch (type) { | ||
1209 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1210 | if (index >= ARRAY_SIZE(formats)) | ||
1211 | return -EINVAL; | ||
1212 | memset(f,0,sizeof(*f)); | ||
1213 | f->index = index; | ||
1214 | f->type = type; | ||
1215 | strlcpy(f->description,formats[index].name,sizeof(f->description)); | ||
1216 | f->pixelformat = formats[index].fourcc; | ||
1217 | break; | ||
1218 | default: | ||
1219 | return -EINVAL; | ||
1220 | } | ||
1221 | return 0; | ||
1222 | } | ||
1223 | case VIDIOC_G_FMT: | ||
1224 | { | ||
1225 | struct v4l2_format *f = arg; | ||
1226 | return cx8800_g_fmt(dev,fh,f); | ||
1227 | } | ||
1228 | case VIDIOC_S_FMT: | ||
1229 | { | ||
1230 | struct v4l2_format *f = arg; | ||
1231 | return cx8800_s_fmt(dev,fh,f); | ||
1232 | } | ||
1233 | case VIDIOC_TRY_FMT: | ||
1234 | { | ||
1235 | struct v4l2_format *f = arg; | ||
1236 | return cx8800_try_fmt(dev,fh,f); | ||
1237 | } | ||
1238 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
1239 | /* --- streaming capture ------------------------------------- */ | ||
1240 | case VIDIOCGMBUF: | ||
1241 | { | ||
1242 | struct video_mbuf *mbuf = arg; | ||
1243 | struct videobuf_queue *q; | ||
1244 | struct v4l2_requestbuffers req; | ||
1245 | unsigned int i; | ||
1246 | |||
1247 | q = get_queue(fh); | ||
1248 | memset(&req,0,sizeof(req)); | ||
1249 | req.type = q->type; | ||
1250 | req.count = 8; | ||
1251 | req.memory = V4L2_MEMORY_MMAP; | ||
1252 | err = videobuf_reqbufs(q,&req); | ||
1253 | if (err < 0) | ||
1254 | return err; | ||
1255 | memset(mbuf,0,sizeof(*mbuf)); | ||
1256 | mbuf->frames = req.count; | ||
1257 | mbuf->size = 0; | ||
1258 | for (i = 0; i < mbuf->frames; i++) { | ||
1259 | mbuf->offsets[i] = q->bufs[i]->boff; | ||
1260 | mbuf->size += q->bufs[i]->bsize; | ||
1261 | } | ||
1262 | return 0; | ||
1263 | } | ||
1264 | #endif | ||
1265 | case VIDIOC_REQBUFS: | ||
1266 | return videobuf_reqbufs(get_queue(fh), arg); | ||
1267 | 1204 | ||
1268 | case VIDIOC_QUERYBUF: | 1205 | static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) |
1269 | return videobuf_querybuf(get_queue(fh), arg); | 1206 | { |
1207 | struct cx8800_fh *fh = priv; | ||
1208 | struct cx8800_dev *dev = fh->dev; | ||
1270 | 1209 | ||
1271 | case VIDIOC_QBUF: | 1210 | if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)) |
1272 | return videobuf_qbuf(get_queue(fh), arg); | 1211 | return -EINVAL; |
1212 | if (unlikely(i != fh->type)) | ||
1213 | return -EINVAL; | ||
1273 | 1214 | ||
1274 | case VIDIOC_DQBUF: | 1215 | if (unlikely(!res_get(dev,fh,get_ressource(fh)))) |
1275 | return videobuf_dqbuf(get_queue(fh), arg, | 1216 | return -EBUSY; |
1276 | file->f_flags & O_NONBLOCK); | 1217 | return videobuf_streamon(get_queue(fh)); |
1218 | } | ||
1277 | 1219 | ||
1278 | case VIDIOC_STREAMON: | 1220 | static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) |
1279 | { | 1221 | { |
1280 | int res = get_ressource(fh); | 1222 | struct cx8800_fh *fh = priv; |
1223 | struct cx8800_dev *dev = fh->dev; | ||
1224 | int err, res; | ||
1281 | 1225 | ||
1282 | if (!res_get(dev,fh,res)) | 1226 | if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1283 | return -EBUSY; | 1227 | return -EINVAL; |
1284 | return videobuf_streamon(get_queue(fh)); | 1228 | if (i != fh->type) |
1285 | } | 1229 | return -EINVAL; |
1286 | case VIDIOC_STREAMOFF: | ||
1287 | { | ||
1288 | int res = get_ressource(fh); | ||
1289 | 1230 | ||
1290 | err = videobuf_streamoff(get_queue(fh)); | 1231 | res = get_ressource(fh); |
1291 | if (err < 0) | 1232 | err = videobuf_streamoff(get_queue(fh)); |
1292 | return err; | 1233 | if (err < 0) |
1293 | res_free(dev,fh,res); | 1234 | return err; |
1294 | return 0; | 1235 | res_free(dev,fh,res); |
1295 | } | ||
1296 | default: | ||
1297 | return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl ); | ||
1298 | } | ||
1299 | return 0; | 1236 | return 0; |
1300 | } | 1237 | } |
1301 | 1238 | ||
1302 | int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, | 1239 | static int vidioc_s_std (struct file *file, void *priv, unsigned int i) |
1303 | struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl) | ||
1304 | { | 1240 | { |
1305 | int err; | 1241 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1306 | 1242 | ||
1307 | if (video_debug) { | 1243 | mutex_lock(&core->lock); |
1308 | if (video_debug > 1) { | 1244 | cx88_set_tvnorm(core,&tvnorms[i]); |
1309 | if (_IOC_DIR(cmd) & _IOC_WRITE) | 1245 | mutex_unlock(&core->lock); |
1310 | v4l_printk_ioctl_arg("cx88(w)",cmd, arg); | 1246 | return 0; |
1311 | else if (!_IOC_DIR(cmd) & _IOC_READ) { | 1247 | } |
1312 | v4l_print_ioctl("cx88", cmd); | ||
1313 | } | ||
1314 | } else | ||
1315 | v4l_print_ioctl(core->name,cmd); | ||
1316 | |||
1317 | } | ||
1318 | |||
1319 | switch (cmd) { | ||
1320 | /* ---------- tv norms ---------- */ | ||
1321 | case VIDIOC_ENUMSTD: | ||
1322 | { | ||
1323 | struct v4l2_standard *e = arg; | ||
1324 | unsigned int i; | ||
1325 | |||
1326 | i = e->index; | ||
1327 | if (i >= ARRAY_SIZE(tvnorms)) | ||
1328 | return -EINVAL; | ||
1329 | err = v4l2_video_std_construct(e, tvnorms[e->index].id, | ||
1330 | tvnorms[e->index].name); | ||
1331 | e->index = i; | ||
1332 | if (err < 0) | ||
1333 | return err; | ||
1334 | return 0; | ||
1335 | } | ||
1336 | case VIDIOC_G_STD: | ||
1337 | { | ||
1338 | v4l2_std_id *id = arg; | ||
1339 | 1248 | ||
1340 | *id = core->tvnorm->id; | 1249 | /* only one input in this sample driver */ |
1341 | return 0; | 1250 | static int vidioc_enum_input (struct file *file, void *priv, |
1342 | } | 1251 | struct v4l2_input *i) |
1343 | case VIDIOC_S_STD: | 1252 | { |
1344 | { | 1253 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1345 | v4l2_std_id *id = arg; | 1254 | |
1346 | unsigned int i; | 1255 | static const char *iname[] = { |
1256 | [ CX88_VMUX_COMPOSITE1 ] = "Composite1", | ||
1257 | [ CX88_VMUX_COMPOSITE2 ] = "Composite2", | ||
1258 | [ CX88_VMUX_COMPOSITE3 ] = "Composite3", | ||
1259 | [ CX88_VMUX_COMPOSITE4 ] = "Composite4", | ||
1260 | [ CX88_VMUX_SVIDEO ] = "S-Video", | ||
1261 | [ CX88_VMUX_TELEVISION ] = "Television", | ||
1262 | [ CX88_VMUX_CABLE ] = "Cable TV", | ||
1263 | [ CX88_VMUX_DVB ] = "DVB", | ||
1264 | [ CX88_VMUX_DEBUG ] = "for debug only", | ||
1265 | }; | ||
1266 | unsigned int n; | ||
1347 | 1267 | ||
1348 | for(i = 0; i < ARRAY_SIZE(tvnorms); i++) | 1268 | n = i->index; |
1349 | if (*id & tvnorms[i].id) | 1269 | if (n >= 4) |
1350 | break; | 1270 | return -EINVAL; |
1351 | if (i == ARRAY_SIZE(tvnorms)) | 1271 | if (0 == INPUT(n)->type) |
1352 | return -EINVAL; | 1272 | return -EINVAL; |
1273 | memset(i,0,sizeof(*i)); | ||
1274 | i->index = n; | ||
1275 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1276 | strcpy(i->name,iname[INPUT(n)->type]); | ||
1277 | if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || | ||
1278 | (CX88_VMUX_CABLE == INPUT(n)->type)) | ||
1279 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1280 | for (n = 0; n < ARRAY_SIZE(tvnorms); n++) | ||
1281 | i->std |= tvnorms[n].id; | ||
1282 | return 0; | ||
1283 | } | ||
1353 | 1284 | ||
1354 | mutex_lock(&core->lock); | 1285 | static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) |
1355 | cx88_set_tvnorm(core,&tvnorms[i]); | 1286 | { |
1356 | mutex_unlock(&core->lock); | 1287 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1357 | return 0; | ||
1358 | } | ||
1359 | 1288 | ||
1360 | /* ------ input switching ---------- */ | 1289 | *i = core->input; |
1361 | case VIDIOC_ENUMINPUT: | 1290 | return 0; |
1362 | { | 1291 | } |
1363 | static const char *iname[] = { | ||
1364 | [ CX88_VMUX_COMPOSITE1 ] = "Composite1", | ||
1365 | [ CX88_VMUX_COMPOSITE2 ] = "Composite2", | ||
1366 | [ CX88_VMUX_COMPOSITE3 ] = "Composite3", | ||
1367 | [ CX88_VMUX_COMPOSITE4 ] = "Composite4", | ||
1368 | [ CX88_VMUX_SVIDEO ] = "S-Video", | ||
1369 | [ CX88_VMUX_TELEVISION ] = "Television", | ||
1370 | [ CX88_VMUX_CABLE ] = "Cable TV", | ||
1371 | [ CX88_VMUX_DVB ] = "DVB", | ||
1372 | [ CX88_VMUX_DEBUG ] = "for debug only", | ||
1373 | }; | ||
1374 | struct v4l2_input *i = arg; | ||
1375 | unsigned int n; | ||
1376 | |||
1377 | n = i->index; | ||
1378 | if (n >= 4) | ||
1379 | return -EINVAL; | ||
1380 | if (0 == INPUT(n)->type) | ||
1381 | return -EINVAL; | ||
1382 | memset(i,0,sizeof(*i)); | ||
1383 | i->index = n; | ||
1384 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1385 | strcpy(i->name,iname[INPUT(n)->type]); | ||
1386 | if ((CX88_VMUX_TELEVISION == INPUT(n)->type) || | ||
1387 | (CX88_VMUX_CABLE == INPUT(n)->type)) | ||
1388 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1389 | for (n = 0; n < ARRAY_SIZE(tvnorms); n++) | ||
1390 | i->std |= tvnorms[n].id; | ||
1391 | return 0; | ||
1392 | } | ||
1393 | case VIDIOC_G_INPUT: | ||
1394 | { | ||
1395 | unsigned int *i = arg; | ||
1396 | 1292 | ||
1397 | *i = core->input; | 1293 | static int vidioc_s_input (struct file *file, void *priv, unsigned int i) |
1398 | return 0; | 1294 | { |
1399 | } | 1295 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1400 | case VIDIOC_S_INPUT: | ||
1401 | { | ||
1402 | unsigned int *i = arg; | ||
1403 | 1296 | ||
1404 | if (*i >= 4) | 1297 | if (i >= 4) |
1405 | return -EINVAL; | 1298 | return -EINVAL; |
1406 | mutex_lock(&core->lock); | ||
1407 | cx88_newstation(core); | ||
1408 | video_mux(core,*i); | ||
1409 | mutex_unlock(&core->lock); | ||
1410 | return 0; | ||
1411 | } | ||
1412 | 1299 | ||
1300 | mutex_lock(&core->lock); | ||
1301 | cx88_newstation(core); | ||
1302 | video_mux(core,i); | ||
1303 | mutex_unlock(&core->lock); | ||
1304 | return 0; | ||
1305 | } | ||
1413 | 1306 | ||
1414 | 1307 | ||
1415 | /* --- controls ---------------------------------------------- */ | ||
1416 | case VIDIOC_QUERYCTRL: | ||
1417 | { | ||
1418 | struct v4l2_queryctrl *c = arg; | ||
1419 | 1308 | ||
1420 | return cx88_queryctrl(c); | 1309 | static int vidioc_queryctrl (struct file *file, void *priv, |
1421 | } | 1310 | struct v4l2_queryctrl *qctrl) |
1422 | case VIDIOC_G_CTRL: | 1311 | { |
1423 | return get_control(core,arg); | 1312 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); |
1424 | case VIDIOC_S_CTRL: | 1313 | if (unlikely(qctrl->id == 0)) |
1425 | return set_control(core,arg); | 1314 | return -EINVAL; |
1315 | return cx8800_ctrl_query(qctrl); | ||
1316 | } | ||
1426 | 1317 | ||
1427 | /* --- tuner ioctls ------------------------------------------ */ | 1318 | static int vidioc_s_ctrl (struct file *file, void *priv, |
1428 | case VIDIOC_G_TUNER: | 1319 | struct v4l2_control *ctl) |
1429 | { | 1320 | { |
1430 | struct v4l2_tuner *t = arg; | 1321 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1431 | u32 reg; | ||
1432 | |||
1433 | if (UNSET == core->tuner_type) | ||
1434 | return -EINVAL; | ||
1435 | if (0 != t->index) | ||
1436 | return -EINVAL; | ||
1437 | |||
1438 | memset(t,0,sizeof(*t)); | ||
1439 | strcpy(t->name, "Television"); | ||
1440 | t->type = V4L2_TUNER_ANALOG_TV; | ||
1441 | t->capability = V4L2_TUNER_CAP_NORM; | ||
1442 | t->rangehigh = 0xffffffffUL; | ||
1443 | |||
1444 | cx88_get_stereo(core ,t); | ||
1445 | reg = cx_read(MO_DEVICE_STATUS); | ||
1446 | t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; | ||
1447 | return 0; | ||
1448 | } | ||
1449 | case VIDIOC_S_TUNER: | ||
1450 | { | ||
1451 | struct v4l2_tuner *t = arg; | ||
1452 | 1322 | ||
1453 | if (UNSET == core->tuner_type) | 1323 | return |
1454 | return -EINVAL; | 1324 | set_control(core,ctl); |
1455 | if (0 != t->index) | 1325 | } |
1456 | return -EINVAL; | ||
1457 | cx88_set_stereo(core, t->audmode, 1); | ||
1458 | return 0; | ||
1459 | } | ||
1460 | case VIDIOC_G_FREQUENCY: | ||
1461 | { | ||
1462 | struct v4l2_frequency *f = arg; | ||
1463 | 1326 | ||
1464 | memset(f,0,sizeof(*f)); | 1327 | static int vidioc_g_tuner (struct file *file, void *priv, |
1328 | struct v4l2_tuner *t) | ||
1329 | { | ||
1330 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1331 | u32 reg; | ||
1465 | 1332 | ||
1466 | if (UNSET == core->tuner_type) | 1333 | if (unlikely(UNSET == core->tuner_type)) |
1467 | return -EINVAL; | 1334 | return -EINVAL; |
1468 | 1335 | ||
1469 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ | 1336 | strcpy(t->name, "Television"); |
1470 | f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | 1337 | t->type = V4L2_TUNER_ANALOG_TV; |
1471 | f->frequency = core->freq; | 1338 | t->capability = V4L2_TUNER_CAP_NORM; |
1339 | t->rangehigh = 0xffffffffUL; | ||
1472 | 1340 | ||
1473 | cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); | 1341 | cx88_get_stereo(core ,t); |
1342 | reg = cx_read(MO_DEVICE_STATUS); | ||
1343 | t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; | ||
1344 | return 0; | ||
1345 | } | ||
1474 | 1346 | ||
1475 | return 0; | 1347 | static int vidioc_s_tuner (struct file *file, void *priv, |
1476 | } | 1348 | struct v4l2_tuner *t) |
1477 | case VIDIOC_S_FREQUENCY: | 1349 | { |
1478 | { | 1350 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; |
1479 | struct v4l2_frequency *f = arg; | ||
1480 | |||
1481 | if (UNSET == core->tuner_type) | ||
1482 | return -EINVAL; | ||
1483 | if (f->tuner != 0) | ||
1484 | return -EINVAL; | ||
1485 | if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV) | ||
1486 | return -EINVAL; | ||
1487 | if (1 == radio && f->type != V4L2_TUNER_RADIO) | ||
1488 | return -EINVAL; | ||
1489 | mutex_lock(&core->lock); | ||
1490 | core->freq = f->frequency; | ||
1491 | cx88_newstation(core); | ||
1492 | cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); | ||
1493 | |||
1494 | /* When changing channels it is required to reset TVAUDIO */ | ||
1495 | msleep (10); | ||
1496 | cx88_set_tvaudio(core); | ||
1497 | 1351 | ||
1498 | mutex_unlock(&core->lock); | 1352 | if (UNSET == core->tuner_type) |
1499 | return 0; | 1353 | return -EINVAL; |
1500 | } | 1354 | if (0 != t->index) |
1501 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1355 | return -EINVAL; |
1502 | /* ioctls to allow direct acces to the cx2388x registers */ | ||
1503 | case VIDIOC_INT_G_REGISTER: | ||
1504 | { | ||
1505 | struct v4l2_register *reg = arg; | ||
1506 | 1356 | ||
1507 | if (reg->i2c_id != 0) | 1357 | cx88_set_stereo(core, t->audmode, 1); |
1508 | return -EINVAL; | 1358 | return 0; |
1509 | /* cx2388x has a 24-bit register space */ | 1359 | } |
1510 | reg->val = cx_read(reg->reg&0xffffff); | ||
1511 | return 0; | ||
1512 | } | ||
1513 | case VIDIOC_INT_S_REGISTER: | ||
1514 | { | ||
1515 | struct v4l2_register *reg = arg; | ||
1516 | 1360 | ||
1517 | if (reg->i2c_id != 0) | 1361 | static int vidioc_g_frequency (struct file *file, void *priv, |
1518 | return -EINVAL; | 1362 | struct v4l2_frequency *f) |
1519 | if (!capable(CAP_SYS_ADMIN)) | 1363 | { |
1520 | return -EPERM; | 1364 | struct cx8800_fh *fh = priv; |
1521 | cx_write(reg->reg&0xffffff, reg->val); | 1365 | struct cx88_core *core = fh->dev->core; |
1522 | return 0; | 1366 | |
1523 | } | 1367 | if (unlikely(UNSET == core->tuner_type)) |
1524 | #endif | 1368 | return -EINVAL; |
1369 | |||
1370 | /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ | ||
1371 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | ||
1372 | f->frequency = core->freq; | ||
1373 | |||
1374 | cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); | ||
1525 | 1375 | ||
1526 | default: | ||
1527 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
1528 | driver_ioctl); | ||
1529 | } | ||
1530 | return 0; | 1376 | return 0; |
1531 | } | 1377 | } |
1532 | 1378 | ||
1533 | static int video_ioctl(struct inode *inode, struct file *file, | 1379 | static int vidioc_s_frequency (struct file *file, void *priv, |
1534 | unsigned int cmd, unsigned long arg) | 1380 | struct v4l2_frequency *f) |
1535 | { | 1381 | { |
1536 | int retval; | 1382 | struct cx8800_fh *fh = priv; |
1383 | struct cx88_core *core = fh->dev->core; | ||
1537 | 1384 | ||
1538 | retval=video_usercopy(inode, file, cmd, arg, video_do_ioctl); | 1385 | if (unlikely(UNSET == core->tuner_type)) |
1386 | return -EINVAL; | ||
1387 | if (unlikely(f->tuner != 0)) | ||
1388 | return -EINVAL; | ||
1389 | if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) | ||
1390 | return -EINVAL; | ||
1391 | if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) | ||
1392 | return -EINVAL; | ||
1393 | mutex_lock(&core->lock); | ||
1394 | core->freq = f->frequency; | ||
1395 | cx88_newstation(core); | ||
1396 | cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); | ||
1539 | 1397 | ||
1540 | if (video_debug > 1) { | 1398 | /* When changing channels it is required to reset TVAUDIO */ |
1541 | if (retval < 0) { | 1399 | msleep (10); |
1542 | v4l_print_ioctl("cx88(err)", cmd); | 1400 | cx88_set_tvaudio(core); |
1543 | printk(KERN_DEBUG "cx88(err): errcode=%d\n",retval); | ||
1544 | } else if (_IOC_DIR(cmd) & _IOC_READ) | ||
1545 | v4l_printk_ioctl_arg("cx88(r)",cmd, (void *)arg); | ||
1546 | } | ||
1547 | 1401 | ||
1548 | return retval; | 1402 | mutex_unlock(&core->lock); |
1403 | return 0; | ||
1549 | } | 1404 | } |
1550 | 1405 | ||
1406 | |||
1407 | /* ----------------------------------------------------------- */ | ||
1408 | /* RADIO ESPECIFIC IOCTLS */ | ||
1551 | /* ----------------------------------------------------------- */ | 1409 | /* ----------------------------------------------------------- */ |
1552 | 1410 | ||
1553 | static int radio_do_ioctl(struct inode *inode, struct file *file, | 1411 | static int radio_querycap (struct file *file, void *priv, |
1554 | unsigned int cmd, void *arg) | 1412 | struct v4l2_capability *cap) |
1555 | { | 1413 | { |
1556 | struct cx8800_fh *fh = file->private_data; | 1414 | struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; |
1557 | struct cx8800_dev *dev = fh->dev; | ||
1558 | struct cx88_core *core = dev->core; | 1415 | struct cx88_core *core = dev->core; |
1559 | 1416 | ||
1560 | if (video_debug > 1) | 1417 | strcpy(cap->driver, "cx8800"); |
1561 | v4l_print_ioctl(core->name,cmd); | 1418 | strlcpy(cap->card, cx88_boards[core->board].name, |
1562 | 1419 | sizeof(cap->card)); | |
1563 | switch (cmd) { | 1420 | sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); |
1564 | case VIDIOC_QUERYCAP: | 1421 | cap->version = CX88_VERSION_CODE; |
1565 | { | 1422 | cap->capabilities = V4L2_CAP_TUNER; |
1566 | struct v4l2_capability *cap = arg; | 1423 | return 0; |
1567 | 1424 | } | |
1568 | memset(cap,0,sizeof(*cap)); | ||
1569 | strcpy(cap->driver, "cx8800"); | ||
1570 | strlcpy(cap->card, cx88_boards[core->board].name, | ||
1571 | sizeof(cap->card)); | ||
1572 | sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); | ||
1573 | cap->version = CX88_VERSION_CODE; | ||
1574 | cap->capabilities = V4L2_CAP_TUNER; | ||
1575 | return 0; | ||
1576 | } | ||
1577 | case VIDIOC_G_TUNER: | ||
1578 | { | ||
1579 | struct v4l2_tuner *t = arg; | ||
1580 | 1425 | ||
1581 | if (t->index > 0) | 1426 | static int radio_g_tuner (struct file *file, void *priv, |
1582 | return -EINVAL; | 1427 | struct v4l2_tuner *t) |
1428 | { | ||
1429 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1583 | 1430 | ||
1584 | memset(t,0,sizeof(*t)); | 1431 | if (unlikely(t->index > 0)) |
1585 | strcpy(t->name, "Radio"); | 1432 | return -EINVAL; |
1586 | t->type = V4L2_TUNER_RADIO; | ||
1587 | 1433 | ||
1588 | cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); | 1434 | strcpy(t->name, "Radio"); |
1589 | return 0; | 1435 | t->type = V4L2_TUNER_RADIO; |
1590 | } | ||
1591 | case VIDIOC_ENUMINPUT: | ||
1592 | { | ||
1593 | struct v4l2_input *i = arg; | ||
1594 | 1436 | ||
1595 | if (i->index != 0) | 1437 | cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); |
1596 | return -EINVAL; | 1438 | return 0; |
1597 | strcpy(i->name,"Radio"); | 1439 | } |
1598 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1599 | return 0; | ||
1600 | } | ||
1601 | case VIDIOC_G_INPUT: | ||
1602 | { | ||
1603 | int *i = arg; | ||
1604 | *i = 0; | ||
1605 | return 0; | ||
1606 | } | ||
1607 | case VIDIOC_G_AUDIO: | ||
1608 | { | ||
1609 | struct v4l2_audio *a = arg; | ||
1610 | 1440 | ||
1611 | memset(a,0,sizeof(*a)); | 1441 | static int radio_enum_input (struct file *file, void *priv, |
1612 | strcpy(a->name,"Radio"); | 1442 | struct v4l2_input *i) |
1613 | return 0; | 1443 | { |
1614 | } | 1444 | if (i->index != 0) |
1615 | case VIDIOC_G_STD: | 1445 | return -EINVAL; |
1616 | { | 1446 | strcpy(i->name,"Radio"); |
1617 | v4l2_std_id *id = arg; | 1447 | i->type = V4L2_INPUT_TYPE_TUNER; |
1618 | *id = 0; | ||
1619 | return 0; | ||
1620 | } | ||
1621 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
1622 | case VIDIOCSTUNER: | ||
1623 | { | ||
1624 | struct video_tuner *v = arg; | ||
1625 | 1448 | ||
1626 | if (v->tuner) /* Only tuner 0 */ | 1449 | return 0; |
1627 | return -EINVAL; | 1450 | } |
1628 | 1451 | ||
1629 | cx88_call_i2c_clients(core,VIDIOCSTUNER,v); | 1452 | static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a) |
1630 | return 0; | 1453 | { |
1631 | } | 1454 | if (unlikely(a->index)) |
1632 | #endif | 1455 | return -EINVAL; |
1633 | case VIDIOC_S_TUNER: | ||
1634 | { | ||
1635 | struct v4l2_tuner *t = arg; | ||
1636 | 1456 | ||
1637 | if (0 != t->index) | 1457 | memset(a,0,sizeof(*a)); |
1638 | return -EINVAL; | 1458 | strcpy(a->name,"Radio"); |
1459 | return 0; | ||
1460 | } | ||
1639 | 1461 | ||
1640 | cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); | 1462 | /* FIXME: Should add a standard for radio */ |
1641 | 1463 | ||
1642 | return 0; | 1464 | static int radio_s_tuner (struct file *file, void *priv, |
1643 | } | 1465 | struct v4l2_tuner *t) |
1466 | { | ||
1467 | struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; | ||
1644 | 1468 | ||
1645 | case VIDIOC_S_AUDIO: | 1469 | if (0 != t->index) |
1646 | case VIDIOC_S_INPUT: | 1470 | return -EINVAL; |
1647 | case VIDIOC_S_STD: | ||
1648 | return 0; | ||
1649 | 1471 | ||
1650 | case VIDIOC_QUERYCTRL: | 1472 | cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); |
1651 | { | ||
1652 | struct v4l2_queryctrl *c = arg; | ||
1653 | int i; | ||
1654 | |||
1655 | if (c->id < V4L2_CID_BASE || | ||
1656 | c->id >= V4L2_CID_LASTP1) | ||
1657 | return -EINVAL; | ||
1658 | if (c->id == V4L2_CID_AUDIO_MUTE) { | ||
1659 | for (i = 0; i < CX8800_CTLS; i++) | ||
1660 | if (cx8800_ctls[i].v.id == c->id) | ||
1661 | break; | ||
1662 | *c = cx8800_ctls[i].v; | ||
1663 | } else | ||
1664 | *c = no_ctl; | ||
1665 | return 0; | ||
1666 | } | ||
1667 | 1473 | ||
1474 | return 0; | ||
1475 | } | ||
1668 | 1476 | ||
1669 | case VIDIOC_G_CTRL: | 1477 | static int radio_s_audio (struct file *file, void *fh, |
1670 | case VIDIOC_S_CTRL: | 1478 | struct v4l2_audio *a) |
1671 | case VIDIOC_G_FREQUENCY: | 1479 | { |
1672 | case VIDIOC_S_FREQUENCY: | 1480 | return 0; |
1673 | return video_do_ioctl(inode,file,cmd,arg); | 1481 | } |
1674 | 1482 | ||
1675 | default: | 1483 | static int radio_s_input (struct file *file, void *fh, unsigned int i) |
1676 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | 1484 | { |
1677 | radio_do_ioctl); | ||
1678 | } | ||
1679 | return 0; | 1485 | return 0; |
1680 | }; | 1486 | } |
1681 | 1487 | ||
1682 | static int radio_ioctl(struct inode *inode, struct file *file, | 1488 | static int radio_queryctrl (struct file *file, void *priv, |
1683 | unsigned int cmd, unsigned long arg) | 1489 | struct v4l2_queryctrl *c) |
1684 | { | 1490 | { |
1685 | return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); | 1491 | int i; |
1686 | }; | 1492 | |
1493 | if (c->id < V4L2_CID_BASE || | ||
1494 | c->id >= V4L2_CID_LASTP1) | ||
1495 | return -EINVAL; | ||
1496 | if (c->id == V4L2_CID_AUDIO_MUTE) { | ||
1497 | for (i = 0; i < CX8800_CTLS; i++) | ||
1498 | if (cx8800_ctls[i].v.id == c->id) | ||
1499 | break; | ||
1500 | *c = cx8800_ctls[i].v; | ||
1501 | } else | ||
1502 | *c = no_ctl; | ||
1503 | return 0; | ||
1504 | } | ||
1687 | 1505 | ||
1688 | /* ----------------------------------------------------------- */ | 1506 | /* ----------------------------------------------------------- */ |
1689 | 1507 | ||
@@ -1816,27 +1634,48 @@ static const struct file_operations video_fops = | |||
1816 | .read = video_read, | 1634 | .read = video_read, |
1817 | .poll = video_poll, | 1635 | .poll = video_poll, |
1818 | .mmap = video_mmap, | 1636 | .mmap = video_mmap, |
1819 | .ioctl = video_ioctl, | 1637 | .ioctl = video_ioctl2, |
1820 | .compat_ioctl = v4l_compat_ioctl32, | 1638 | .compat_ioctl = v4l_compat_ioctl32, |
1821 | .llseek = no_llseek, | 1639 | .llseek = no_llseek, |
1822 | }; | 1640 | }; |
1823 | 1641 | ||
1642 | static struct video_device cx8800_vbi_template; | ||
1824 | static struct video_device cx8800_video_template = | 1643 | static struct video_device cx8800_video_template = |
1825 | { | 1644 | { |
1826 | .name = "cx8800-video", | 1645 | .name = "cx8800-video", |
1827 | .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, | 1646 | .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, |
1828 | .hardware = 0, | 1647 | .fops = &video_fops, |
1829 | .fops = &video_fops, | 1648 | .minor = -1, |
1830 | .minor = -1, | 1649 | .vidioc_querycap = vidioc_querycap, |
1831 | }; | 1650 | .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, |
1832 | 1651 | .vidioc_g_fmt_cap = vidioc_g_fmt_cap, | |
1833 | static struct video_device cx8800_vbi_template = | 1652 | .vidioc_try_fmt_cap = vidioc_try_fmt_cap, |
1834 | { | 1653 | .vidioc_s_fmt_cap = vidioc_s_fmt_cap, |
1835 | .name = "cx8800-vbi", | 1654 | .vidioc_g_fmt_vbi = cx8800_vbi_fmt, |
1836 | .type = VID_TYPE_TELETEXT|VID_TYPE_TUNER, | 1655 | .vidioc_try_fmt_vbi = cx8800_vbi_fmt, |
1837 | .hardware = 0, | 1656 | .vidioc_s_fmt_vbi = cx8800_vbi_fmt, |
1838 | .fops = &video_fops, | 1657 | .vidioc_reqbufs = vidioc_reqbufs, |
1839 | .minor = -1, | 1658 | .vidioc_querybuf = vidioc_querybuf, |
1659 | .vidioc_qbuf = vidioc_qbuf, | ||
1660 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1661 | .vidioc_s_std = vidioc_s_std, | ||
1662 | .vidioc_enum_input = vidioc_enum_input, | ||
1663 | .vidioc_g_input = vidioc_g_input, | ||
1664 | .vidioc_s_input = vidioc_s_input, | ||
1665 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1666 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1667 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1668 | .vidioc_streamon = vidioc_streamon, | ||
1669 | .vidioc_streamoff = vidioc_streamoff, | ||
1670 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
1671 | .vidiocgmbuf = vidiocgmbuf, | ||
1672 | #endif | ||
1673 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1674 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1675 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1676 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1677 | .tvnorms = tvnorms, | ||
1678 | .tvnormsize = ARRAY_SIZE(tvnorms), | ||
1840 | }; | 1679 | }; |
1841 | 1680 | ||
1842 | static const struct file_operations radio_fops = | 1681 | static const struct file_operations radio_fops = |
@@ -1844,18 +1683,32 @@ static const struct file_operations radio_fops = | |||
1844 | .owner = THIS_MODULE, | 1683 | .owner = THIS_MODULE, |
1845 | .open = video_open, | 1684 | .open = video_open, |
1846 | .release = video_release, | 1685 | .release = video_release, |
1847 | .ioctl = radio_ioctl, | 1686 | .ioctl = video_ioctl2, |
1848 | .compat_ioctl = v4l_compat_ioctl32, | 1687 | .compat_ioctl = v4l_compat_ioctl32, |
1849 | .llseek = no_llseek, | 1688 | .llseek = no_llseek, |
1850 | }; | 1689 | }; |
1851 | 1690 | ||
1852 | static struct video_device cx8800_radio_template = | 1691 | static struct video_device cx8800_radio_template = |
1853 | { | 1692 | { |
1854 | .name = "cx8800-radio", | 1693 | .name = "cx8800-radio", |
1855 | .type = VID_TYPE_TUNER, | 1694 | .type = VID_TYPE_TUNER, |
1856 | .hardware = 0, | 1695 | .hardware = 0, |
1857 | .fops = &radio_fops, | 1696 | .fops = &radio_fops, |
1858 | .minor = -1, | 1697 | .minor = -1, |
1698 | .vidioc_querycap = radio_querycap, | ||
1699 | .vidioc_g_tuner = radio_g_tuner, | ||
1700 | .vidioc_enum_input = radio_enum_input, | ||
1701 | .vidioc_g_audio = radio_g_audio, | ||
1702 | .vidioc_s_tuner = radio_s_tuner, | ||
1703 | .vidioc_s_audio = radio_s_audio, | ||
1704 | .vidioc_s_input = radio_s_input, | ||
1705 | .vidioc_queryctrl = radio_queryctrl, | ||
1706 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1707 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1708 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1709 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1710 | .tvnorms = radionorms, | ||
1711 | .tvnormsize = ARRAY_SIZE(radionorms), | ||
1859 | }; | 1712 | }; |
1860 | 1713 | ||
1861 | /* ----------------------------------------------------------- */ | 1714 | /* ----------------------------------------------------------- */ |
@@ -1890,6 +1743,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1890 | { | 1743 | { |
1891 | struct cx8800_dev *dev; | 1744 | struct cx8800_dev *dev; |
1892 | struct cx88_core *core; | 1745 | struct cx88_core *core; |
1746 | |||
1893 | int err; | 1747 | int err; |
1894 | 1748 | ||
1895 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); | 1749 | dev = kzalloc(sizeof(*dev),GFP_KERNEL); |
@@ -1924,6 +1778,12 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1924 | goto fail_core; | 1778 | goto fail_core; |
1925 | } | 1779 | } |
1926 | 1780 | ||
1781 | /* Initialize VBI template */ | ||
1782 | memcpy( &cx8800_vbi_template, &cx8800_video_template, | ||
1783 | sizeof(cx8800_vbi_template) ); | ||
1784 | strcpy(cx8800_vbi_template.name,"cx8800-vbi"); | ||
1785 | cx8800_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER; | ||
1786 | |||
1927 | /* initialize driver struct */ | 1787 | /* initialize driver struct */ |
1928 | spin_lock_init(&dev->slock); | 1788 | spin_lock_init(&dev->slock); |
1929 | core->tvnorm = tvnorms; | 1789 | core->tvnorm = tvnorms; |