diff options
author | Andy Walls <awalls@radix.net> | 2008-06-21 07:36:31 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:10:43 -0400 |
commit | 3b6fe58f0f18880200969e813d0181d1bdab0966 (patch) | |
tree | e059efc521b5eeb2b0f022f7c7e56d3a8f3b7a86 | |
parent | 1a05221bc45ccb1b5c583a87dc3639bfc10c4f10 (diff) |
V4L/DVB (8082): cx18: convert to video_ioctl2()
cx18: convert driver to use video_ioctl2(). Pushed down ioctl debug
messages and priority checks as well. Still left serialization lock in
place for now. #if 0'ed out sliced vbi ioctl code for now.
Patch heavily based on similar changes made to ivtv by Hans Verkuil.
Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/video/cx18/cx18-controls.c | 195 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-controls.h | 9 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 9 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.c | 1211 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-ioctl.h | 6 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 4 |
6 files changed, 745 insertions, 689 deletions
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c index 87cf41021665..6eae75f4ee7c 100644 --- a/drivers/media/video/cx18/cx18-controls.c +++ b/drivers/media/video/cx18/cx18-controls.c | |||
@@ -51,8 +51,9 @@ static const u32 *ctrl_classes[] = { | |||
51 | NULL | 51 | NULL |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl) | 54 | int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl) |
55 | { | 55 | { |
56 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
56 | const char *name; | 57 | const char *name; |
57 | 58 | ||
58 | CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); | 59 | CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); |
@@ -91,19 +92,28 @@ static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl) | |||
91 | return 0; | 92 | return 0; |
92 | } | 93 | } |
93 | 94 | ||
94 | static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu) | 95 | int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu) |
95 | { | 96 | { |
97 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
96 | struct v4l2_queryctrl qctrl; | 98 | struct v4l2_queryctrl qctrl; |
97 | 99 | ||
100 | CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); | ||
98 | qctrl.id = qmenu->id; | 101 | qctrl.id = qmenu->id; |
99 | cx18_queryctrl(cx, &qctrl); | 102 | cx18_queryctrl(file, fh, &qctrl); |
100 | return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); | 103 | return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); |
101 | } | 104 | } |
102 | 105 | ||
103 | static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) | 106 | int cx18_s_ctrl(struct file *file, void *fh, struct v4l2_control *vctrl) |
104 | { | 107 | { |
108 | struct cx18_open_id *id = fh; | ||
109 | struct cx18 *cx = id->cx; | ||
110 | int ret; | ||
105 | s32 v = vctrl->value; | 111 | s32 v = vctrl->value; |
106 | 112 | ||
113 | ret = v4l2_prio_check(&cx->prio, &id->prio); | ||
114 | if (ret) | ||
115 | return ret; | ||
116 | |||
107 | CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); | 117 | CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); |
108 | 118 | ||
109 | switch (vctrl->id) { | 119 | switch (vctrl->id) { |
@@ -129,8 +139,10 @@ static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) | |||
129 | return 0; | 139 | return 0; |
130 | } | 140 | } |
131 | 141 | ||
132 | static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) | 142 | int cx18_g_ctrl(struct file *file, void *fh, struct v4l2_control *vctrl) |
133 | { | 143 | { |
144 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
145 | |||
134 | CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); | 146 | CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); |
135 | 147 | ||
136 | switch (vctrl->id) { | 148 | switch (vctrl->id) { |
@@ -194,113 +206,100 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt | |||
194 | return 0; | 206 | return 0; |
195 | } | 207 | } |
196 | 208 | ||
197 | int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg) | 209 | int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) |
198 | { | 210 | { |
211 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
199 | struct v4l2_control ctrl; | 212 | struct v4l2_control ctrl; |
200 | 213 | ||
201 | switch (cmd) { | 214 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { |
202 | case VIDIOC_QUERYMENU: | 215 | int i; |
203 | CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); | 216 | int err = 0; |
204 | return cx18_querymenu(cx, arg); | 217 | |
205 | 218 | for (i = 0; i < c->count; i++) { | |
206 | case VIDIOC_QUERYCTRL: | 219 | ctrl.id = c->controls[i].id; |
207 | return cx18_queryctrl(cx, arg); | 220 | ctrl.value = c->controls[i].value; |
208 | 221 | err = cx18_g_ctrl(file, fh, &ctrl); | |
209 | case VIDIOC_S_CTRL: | 222 | c->controls[i].value = ctrl.value; |
210 | return cx18_s_ctrl(cx, arg); | 223 | if (err) { |
211 | 224 | c->error_idx = i; | |
212 | case VIDIOC_G_CTRL: | 225 | break; |
213 | return cx18_g_ctrl(cx, arg); | ||
214 | |||
215 | case VIDIOC_S_EXT_CTRLS: | ||
216 | { | ||
217 | struct v4l2_ext_controls *c = arg; | ||
218 | |||
219 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
220 | int i; | ||
221 | int err = 0; | ||
222 | |||
223 | for (i = 0; i < c->count; i++) { | ||
224 | ctrl.id = c->controls[i].id; | ||
225 | ctrl.value = c->controls[i].value; | ||
226 | err = cx18_s_ctrl(cx, &ctrl); | ||
227 | c->controls[i].value = ctrl.value; | ||
228 | if (err) { | ||
229 | c->error_idx = i; | ||
230 | break; | ||
231 | } | ||
232 | } | 226 | } |
233 | return err; | ||
234 | } | 227 | } |
235 | CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); | 228 | return err; |
236 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | 229 | } |
237 | struct cx2341x_mpeg_params p = cx->params; | 230 | CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); |
238 | int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), arg, cmd); | 231 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) |
232 | return cx2341x_ext_ctrls(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS); | ||
233 | return -EINVAL; | ||
234 | } | ||
239 | 235 | ||
240 | if (err) | 236 | int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) |
241 | return err; | 237 | { |
238 | struct cx18_open_id *id = fh; | ||
239 | struct cx18 *cx = id->cx; | ||
240 | int ret; | ||
241 | struct v4l2_control ctrl; | ||
242 | 242 | ||
243 | if (p.video_encoding != cx->params.video_encoding) { | 243 | ret = v4l2_prio_check(&cx->prio, &id->prio); |
244 | int is_mpeg1 = p.video_encoding == | 244 | if (ret) |
245 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | 245 | return ret; |
246 | struct v4l2_format fmt; | ||
247 | 246 | ||
248 | /* fix videodecoder resolution */ | 247 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { |
249 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 248 | int i; |
250 | fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1); | 249 | int err = 0; |
251 | fmt.fmt.pix.height = cx->params.height; | 250 | |
252 | cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); | 251 | for (i = 0; i < c->count; i++) { |
252 | ctrl.id = c->controls[i].id; | ||
253 | ctrl.value = c->controls[i].value; | ||
254 | err = cx18_s_ctrl(file, fh, &ctrl); | ||
255 | c->controls[i].value = ctrl.value; | ||
256 | if (err) { | ||
257 | c->error_idx = i; | ||
258 | break; | ||
253 | } | 259 | } |
254 | err = cx2341x_update(cx, cx18_api_func, &cx->params, &p); | ||
255 | if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt) | ||
256 | err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); | ||
257 | cx->params = p; | ||
258 | cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; | ||
259 | cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03); | ||
260 | return err; | ||
261 | } | 260 | } |
262 | return -EINVAL; | 261 | return err; |
263 | } | 262 | } |
263 | CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); | ||
264 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
265 | struct cx2341x_mpeg_params p = cx->params; | ||
266 | int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing), | ||
267 | c, VIDIOC_S_EXT_CTRLS); | ||
264 | 268 | ||
265 | case VIDIOC_G_EXT_CTRLS: | 269 | if (err) |
266 | { | ||
267 | struct v4l2_ext_controls *c = arg; | ||
268 | |||
269 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
270 | int i; | ||
271 | int err = 0; | ||
272 | |||
273 | for (i = 0; i < c->count; i++) { | ||
274 | ctrl.id = c->controls[i].id; | ||
275 | ctrl.value = c->controls[i].value; | ||
276 | err = cx18_g_ctrl(cx, &ctrl); | ||
277 | c->controls[i].value = ctrl.value; | ||
278 | if (err) { | ||
279 | c->error_idx = i; | ||
280 | break; | ||
281 | } | ||
282 | } | ||
283 | return err; | 270 | return err; |
284 | } | ||
285 | CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); | ||
286 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
287 | return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | 271 | ||
291 | case VIDIOC_TRY_EXT_CTRLS: | 272 | if (p.video_encoding != cx->params.video_encoding) { |
292 | { | 273 | int is_mpeg1 = p.video_encoding == |
293 | struct v4l2_ext_controls *c = arg; | 274 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1; |
294 | 275 | struct v4l2_format fmt; | |
295 | CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); | 276 | |
296 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | 277 | /* fix videodecoder resolution */ |
297 | return cx2341x_ext_ctrls(&cx->params, | 278 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
298 | atomic_read(&cx->ana_capturing), arg, cmd); | 279 | fmt.fmt.pix.width = cx->params.width |
299 | return -EINVAL; | 280 | / (is_mpeg1 ? 2 : 1); |
281 | fmt.fmt.pix.height = cx->params.height; | ||
282 | cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); | ||
283 | } | ||
284 | err = cx2341x_update(cx, cx18_api_func, &cx->params, &p); | ||
285 | if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt) | ||
286 | err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); | ||
287 | cx->params = p; | ||
288 | cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; | ||
289 | cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03); | ||
290 | return err; | ||
300 | } | 291 | } |
292 | return -EINVAL; | ||
293 | } | ||
301 | 294 | ||
302 | default: | 295 | int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c) |
303 | return -EINVAL; | 296 | { |
304 | } | 297 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
305 | return 0; | 298 | |
299 | CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); | ||
300 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
301 | return cx2341x_ext_ctrls(&cx->params, | ||
302 | atomic_read(&cx->ana_capturing), | ||
303 | c, VIDIOC_TRY_EXT_CTRLS); | ||
304 | return -EINVAL; | ||
306 | } | 305 | } |
diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h index 6e985cf422a0..81b8996e5860 100644 --- a/drivers/media/video/cx18/cx18-controls.h +++ b/drivers/media/video/cx18/cx18-controls.h | |||
@@ -21,4 +21,11 @@ | |||
21 | * 02111-1307 USA | 21 | * 02111-1307 USA |
22 | */ | 22 | */ |
23 | 23 | ||
24 | int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg); | 24 | int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); |
25 | int cx18_g_ctrl(struct file *file, void *fh, struct v4l2_control *a); | ||
26 | int cx18_s_ctrl(struct file *file, void *fh, struct v4l2_control *a); | ||
27 | int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); | ||
28 | int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a); | ||
29 | int cx18_try_ext_ctrls(struct file *file, void *fh, | ||
30 | struct v4l2_ext_controls *a); | ||
31 | int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a); | ||
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index d9178843e8d2..e9c7e07b9fed 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c | |||
@@ -818,6 +818,9 @@ int cx18_init_on_first_open(struct cx18 *cx) | |||
818 | int video_input; | 818 | int video_input; |
819 | int fw_retry_count = 3; | 819 | int fw_retry_count = 3; |
820 | struct v4l2_frequency vf; | 820 | struct v4l2_frequency vf; |
821 | struct cx18_open_id fh; | ||
822 | |||
823 | fh.cx = cx; | ||
821 | 824 | ||
822 | if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) | 825 | if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) |
823 | return -ENXIO; | 826 | return -ENXIO; |
@@ -869,13 +872,13 @@ int cx18_init_on_first_open(struct cx18 *cx) | |||
869 | 872 | ||
870 | video_input = cx->active_input; | 873 | video_input = cx->active_input; |
871 | cx->active_input++; /* Force update of input */ | 874 | cx->active_input++; /* Force update of input */ |
872 | cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input); | 875 | cx18_s_input(NULL, &fh, video_input); |
873 | 876 | ||
874 | /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code | 877 | /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code |
875 | in one place. */ | 878 | in one place. */ |
876 | cx->std++; /* Force full standard initialization */ | 879 | cx->std++; /* Force full standard initialization */ |
877 | cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std); | 880 | cx18_s_std(NULL, &fh, &cx->tuner_std); |
878 | cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf); | 881 | cx18_s_frequency(NULL, &fh, &vf); |
879 | return 0; | 882 | return 0; |
880 | } | 883 | } |
881 | 884 | ||
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c index 4151f1e5493f..70afedf4763f 100644 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ b/drivers/media/video/cx18/cx18-ioctl.c | |||
@@ -100,19 +100,6 @@ void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) | |||
100 | } | 100 | } |
101 | } | 101 | } |
102 | 102 | ||
103 | static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) | ||
104 | { | ||
105 | int f, l; | ||
106 | u16 set = 0; | ||
107 | |||
108 | for (f = 0; f < 2; f++) { | ||
109 | for (l = 0; l < 24; l++) { | ||
110 | fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); | ||
111 | set |= fmt->service_lines[f][l]; | ||
112 | } | ||
113 | } | ||
114 | return set != 0; | ||
115 | } | ||
116 | 103 | ||
117 | u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) | 104 | u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) |
118 | { | 105 | { |
@@ -126,35 +113,6 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) | |||
126 | return set; | 113 | return set; |
127 | } | 114 | } |
128 | 115 | ||
129 | static const struct { | ||
130 | v4l2_std_id std; | ||
131 | char *name; | ||
132 | } enum_stds[] = { | ||
133 | { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, | ||
134 | { V4L2_STD_PAL_DK, "PAL-DK" }, | ||
135 | { V4L2_STD_PAL_I, "PAL-I" }, | ||
136 | { V4L2_STD_PAL_M, "PAL-M" }, | ||
137 | { V4L2_STD_PAL_N, "PAL-N" }, | ||
138 | { V4L2_STD_PAL_Nc, "PAL-Nc" }, | ||
139 | { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, | ||
140 | { V4L2_STD_SECAM_DK, "SECAM-DK" }, | ||
141 | { V4L2_STD_SECAM_L, "SECAM-L" }, | ||
142 | { V4L2_STD_SECAM_LC, "SECAM-L'" }, | ||
143 | { V4L2_STD_NTSC_M, "NTSC-M" }, | ||
144 | { V4L2_STD_NTSC_M_JP, "NTSC-J" }, | ||
145 | { V4L2_STD_NTSC_M_KR, "NTSC-K" }, | ||
146 | }; | ||
147 | |||
148 | static const struct v4l2_standard cx18_std_60hz = { | ||
149 | .frameperiod = {.numerator = 1001, .denominator = 30000}, | ||
150 | .framelines = 525, | ||
151 | }; | ||
152 | |||
153 | static const struct v4l2_standard cx18_std_50hz = { | ||
154 | .frameperiod = { .numerator = 1, .denominator = 25 }, | ||
155 | .framelines = 625, | ||
156 | }; | ||
157 | |||
158 | static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) | 116 | static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) |
159 | { | 117 | { |
160 | struct v4l2_register *regs = arg; | 118 | struct v4l2_register *regs = arg; |
@@ -174,665 +132,702 @@ static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) | |||
174 | return 0; | 132 | return 0; |
175 | } | 133 | } |
176 | 134 | ||
177 | static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt) | 135 | static int cx18_g_fmt_vid_cap(struct file *file, void *fh, |
178 | { | 136 | struct v4l2_format *fmt) |
179 | switch (fmt->type) { | 137 | { |
180 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 138 | struct cx18_open_id *id = fh; |
181 | fmt->fmt.pix.width = cx->params.width; | 139 | struct cx18 *cx = id->cx; |
182 | fmt->fmt.pix.height = cx->params.height; | ||
183 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
184 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; | ||
185 | if (streamtype == CX18_ENC_STREAM_TYPE_YUV) { | ||
186 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; | ||
187 | /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ | ||
188 | fmt->fmt.pix.sizeimage = | ||
189 | fmt->fmt.pix.height * fmt->fmt.pix.width + | ||
190 | fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); | ||
191 | } else { | ||
192 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
193 | fmt->fmt.pix.sizeimage = 128 * 1024; | ||
194 | } | ||
195 | break; | ||
196 | 140 | ||
197 | case V4L2_BUF_TYPE_VBI_CAPTURE: | 141 | CX18_DEBUG_IOCTL("VIDIOC_G_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); |
198 | fmt->fmt.vbi.sampling_rate = 27000000; | 142 | |
199 | fmt->fmt.vbi.offset = 248; | 143 | fmt->fmt.pix.width = cx->params.width; |
200 | fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4; | 144 | fmt->fmt.pix.height = cx->params.height; |
201 | fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | 145 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; |
202 | fmt->fmt.vbi.start[0] = cx->vbi.start[0]; | 146 | fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; |
203 | fmt->fmt.vbi.start[1] = cx->vbi.start[1]; | 147 | if (id->type == CX18_ENC_STREAM_TYPE_YUV) { |
204 | fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count; | 148 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; |
205 | break; | 149 | /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ |
150 | fmt->fmt.pix.sizeimage = | ||
151 | fmt->fmt.pix.height * fmt->fmt.pix.width + | ||
152 | fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); | ||
153 | } else { | ||
154 | fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
155 | fmt->fmt.pix.sizeimage = 128 * 1024; | ||
156 | } | ||
157 | return 0; | ||
158 | } | ||
206 | 159 | ||
207 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | 160 | static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, |
208 | { | 161 | struct v4l2_format *fmt) |
209 | struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; | 162 | { |
163 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
210 | 164 | ||
211 | vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | 165 | CX18_DEBUG_IOCTL("VIDIOC_G_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n"); |
212 | memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); | ||
213 | memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); | ||
214 | 166 | ||
215 | cx18_av_cmd(cx, VIDIOC_G_FMT, fmt); | 167 | fmt->fmt.vbi.sampling_rate = 27000000; |
216 | vbifmt->service_set = cx18_get_service_set(vbifmt); | 168 | fmt->fmt.vbi.offset = 248; |
217 | break; | 169 | fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4; |
218 | } | 170 | fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; |
219 | default: | 171 | fmt->fmt.vbi.start[0] = cx->vbi.start[0]; |
220 | return -EINVAL; | 172 | fmt->fmt.vbi.start[1] = cx->vbi.start[1]; |
221 | } | 173 | fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count; |
222 | return 0; | 174 | return 0; |
223 | } | 175 | } |
224 | 176 | ||
225 | static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, | 177 | static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, |
226 | struct v4l2_format *fmt, int set_fmt) | 178 | struct v4l2_format *fmt) |
227 | { | 179 | { |
228 | struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; | 180 | return -EINVAL; |
229 | u16 set; | 181 | } |
230 | 182 | ||
231 | /* set window size */ | 183 | static int cx18_try_fmt_vid_cap(struct file *file, void *fh, |
232 | if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 184 | struct v4l2_format *fmt) |
233 | int w = fmt->fmt.pix.width; | 185 | { |
234 | int h = fmt->fmt.pix.height; | 186 | struct cx18_open_id *id = fh; |
187 | struct cx18 *cx = id->cx; | ||
235 | 188 | ||
236 | if (w > 720) | 189 | int w = fmt->fmt.pix.width; |
237 | w = 720; | 190 | int h = fmt->fmt.pix.height; |
238 | else if (w < 1) | ||
239 | w = 1; | ||
240 | if (h > (cx->is_50hz ? 576 : 480)) | ||
241 | h = (cx->is_50hz ? 576 : 480); | ||
242 | else if (h < 2) | ||
243 | h = 2; | ||
244 | cx18_get_fmt(cx, streamtype, fmt); | ||
245 | fmt->fmt.pix.width = w; | ||
246 | fmt->fmt.pix.height = h; | ||
247 | 191 | ||
248 | if (!set_fmt || (cx->params.width == w && cx->params.height == h)) | 192 | CX18_DEBUG_IOCTL("VIDIOC_TRY_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); |
249 | return 0; | ||
250 | if (atomic_read(&cx->ana_capturing) > 0) | ||
251 | return -EBUSY; | ||
252 | |||
253 | cx->params.width = w; | ||
254 | cx->params.height = h; | ||
255 | if (w != 720 || h != (cx->is_50hz ? 576 : 480)) | ||
256 | cx->params.video_temporal_filter = 0; | ||
257 | else | ||
258 | cx->params.video_temporal_filter = 8; | ||
259 | cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); | ||
260 | return cx18_get_fmt(cx, streamtype, fmt); | ||
261 | } | ||
262 | 193 | ||
263 | /* set raw VBI format */ | 194 | w = min(w, 720); |
264 | if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { | 195 | w = max(w, 1); |
265 | if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI && | 196 | h = min(h, cx->is_50hz ? 576 : 480); |
266 | cx->vbi.sliced_in->service_set && | 197 | h = max(h, 2); |
267 | atomic_read(&cx->ana_capturing) > 0) | 198 | cx18_g_fmt_vid_cap(file, fh, fmt); |
268 | return -EBUSY; | 199 | fmt->fmt.pix.width = w; |
269 | if (set_fmt) { | 200 | fmt->fmt.pix.height = h; |
270 | cx->vbi.sliced_in->service_set = 0; | 201 | return 0; |
271 | cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); | 202 | } |
272 | } | ||
273 | return cx18_get_fmt(cx, streamtype, fmt); | ||
274 | } | ||
275 | 203 | ||
276 | /* any else but sliced VBI capture is an error */ | 204 | static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, |
277 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | 205 | struct v4l2_format *fmt) |
278 | return -EINVAL; | 206 | { |
207 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
279 | 208 | ||
280 | /* TODO: implement sliced VBI, for now silently return 0 */ | 209 | CX18_DEBUG_IOCTL("VIDIOC_TRY_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n"); |
281 | return 0; | 210 | |
211 | return cx18_g_fmt_vbi_cap(file, fh, fmt); | ||
212 | } | ||
213 | |||
214 | static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, | ||
215 | struct v4l2_format *fmt) | ||
216 | { | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | |||
220 | static int cx18_s_fmt_vid_cap(struct file *file, void *fh, | ||
221 | struct v4l2_format *fmt) | ||
222 | { | ||
223 | struct cx18_open_id *id = fh; | ||
224 | struct cx18 *cx = id->cx; | ||
225 | int ret; | ||
226 | int w = fmt->fmt.pix.width; | ||
227 | int h = fmt->fmt.pix.height; | ||
228 | |||
229 | ret = v4l2_prio_check(&cx->prio, &id->prio); | ||
230 | if (ret) | ||
231 | return ret; | ||
282 | 232 | ||
283 | /* set sliced VBI capture format */ | 233 | CX18_DEBUG_IOCTL("VIDIOC_S_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); |
284 | vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; | ||
285 | memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); | ||
286 | 234 | ||
287 | if (vbifmt->service_set) | 235 | ret = cx18_try_fmt_vid_cap(file, fh, fmt); |
288 | cx18_expand_service_set(vbifmt, cx->is_50hz); | 236 | if (ret) |
289 | set = check_service_set(vbifmt, cx->is_50hz); | 237 | return ret; |
290 | vbifmt->service_set = cx18_get_service_set(vbifmt); | ||
291 | 238 | ||
292 | if (!set_fmt) | 239 | if (cx->params.width == w && cx->params.height == h) |
293 | return 0; | 240 | return 0; |
294 | if (set == 0) | 241 | |
295 | return -EINVAL; | 242 | if (atomic_read(&cx->ana_capturing) > 0) |
296 | if (atomic_read(&cx->ana_capturing) > 0 && cx->vbi.sliced_in->service_set == 0) | ||
297 | return -EBUSY; | 243 | return -EBUSY; |
244 | |||
245 | cx->params.width = w; | ||
246 | cx->params.height = h; | ||
247 | if (w != 720 || h != (cx->is_50hz ? 576 : 480)) | ||
248 | cx->params.video_temporal_filter = 0; | ||
249 | else | ||
250 | cx->params.video_temporal_filter = 8; | ||
298 | cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); | 251 | cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); |
299 | memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); | 252 | return cx18_g_fmt_vid_cap(file, fh, fmt); |
300 | return 0; | ||
301 | } | 253 | } |
302 | 254 | ||
303 | static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) | 255 | static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, |
256 | struct v4l2_format *fmt) | ||
304 | { | 257 | { |
305 | struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; | 258 | struct cx18_open_id *id = fh; |
306 | struct cx18 *cx = id->cx; | 259 | struct cx18 *cx = id->cx; |
307 | struct v4l2_register *reg = arg; | 260 | int ret; |
308 | 261 | ||
309 | switch (cmd) { | 262 | ret = v4l2_prio_check(&cx->prio, &id->prio); |
310 | /* ioctls to allow direct access to the encoder registers for testing */ | 263 | if (ret) |
311 | case VIDIOC_DBG_G_REGISTER: | 264 | return ret; |
312 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) | ||
313 | return cx18_cxc(cx, cmd, arg); | ||
314 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
315 | return cx18_i2c_id(cx, reg->match_chip, cmd, arg); | ||
316 | return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); | ||
317 | |||
318 | case VIDIOC_DBG_S_REGISTER: | ||
319 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) | ||
320 | return cx18_cxc(cx, cmd, arg); | ||
321 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
322 | return cx18_i2c_id(cx, reg->match_chip, cmd, arg); | ||
323 | return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); | ||
324 | |||
325 | case VIDIOC_G_CHIP_IDENT: { | ||
326 | struct v4l2_chip_ident *chip = arg; | ||
327 | |||
328 | chip->ident = V4L2_IDENT_NONE; | ||
329 | chip->revision = 0; | ||
330 | if (reg->match_type == V4L2_CHIP_MATCH_HOST) { | ||
331 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { | ||
332 | struct v4l2_chip_ident *chip = arg; | ||
333 | |||
334 | chip->ident = V4L2_IDENT_CX23418; | ||
335 | } | ||
336 | return 0; | ||
337 | } | ||
338 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
339 | return cx18_i2c_id(cx, reg->match_chip, cmd, arg); | ||
340 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) | ||
341 | return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); | ||
342 | return -EINVAL; | ||
343 | } | ||
344 | 265 | ||
345 | case VIDIOC_INT_S_AUDIO_ROUTING: { | 266 | CX18_DEBUG_IOCTL("VIDIOC_S_FMT: V4L2_BUF_TYPE_VBI_CAPTURE\n"); |
346 | struct v4l2_routing *route = arg; | ||
347 | 267 | ||
348 | cx18_audio_set_route(cx, route); | 268 | if (id->type == CX18_ENC_STREAM_TYPE_VBI && |
349 | break; | 269 | cx->vbi.sliced_in->service_set && |
350 | } | 270 | atomic_read(&cx->ana_capturing) > 0) |
271 | return -EBUSY; | ||
351 | 272 | ||
352 | default: | 273 | cx->vbi.sliced_in->service_set = 0; |
353 | return -EINVAL; | 274 | cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); |
275 | return cx18_g_fmt_vbi_cap(file, fh, fmt); | ||
276 | } | ||
277 | |||
278 | static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, | ||
279 | struct v4l2_format *fmt) | ||
280 | { | ||
281 | return -EINVAL; | ||
282 | } | ||
283 | |||
284 | static int cx18_g_chip_ident(struct file *file, void *fh, | ||
285 | struct v4l2_chip_ident *chip) | ||
286 | { | ||
287 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
288 | |||
289 | CX18_DEBUG_IOCTL("VIDIOC_G_CHIP_IDENT\n"); | ||
290 | |||
291 | chip->ident = V4L2_IDENT_NONE; | ||
292 | chip->revision = 0; | ||
293 | if (chip->match_type == V4L2_CHIP_MATCH_HOST) { | ||
294 | if (v4l2_chip_match_host(chip->match_type, chip->match_chip)) | ||
295 | chip->ident = V4L2_IDENT_CX23418; | ||
296 | return 0; | ||
354 | } | 297 | } |
298 | if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
299 | return cx18_i2c_id(cx, chip->match_chip, VIDIOC_G_CHIP_IDENT, | ||
300 | chip); | ||
301 | if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR) | ||
302 | return cx18_call_i2c_client(cx, chip->match_chip, | ||
303 | VIDIOC_G_CHIP_IDENT, chip); | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | |||
307 | static int cx18_g_register(struct file *file, void *fh, | ||
308 | struct v4l2_register *reg) | ||
309 | { | ||
310 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
311 | |||
312 | CX18_DEBUG_IOCTL("VIDIOC_DBG_G_REGISTER\n"); | ||
313 | |||
314 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) | ||
315 | return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); | ||
316 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
317 | return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER, | ||
318 | reg); | ||
319 | return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_G_REGISTER, | ||
320 | reg); | ||
321 | } | ||
322 | |||
323 | static int cx18_s_register(struct file *file, void *fh, | ||
324 | struct v4l2_register *reg) | ||
325 | { | ||
326 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
327 | |||
328 | CX18_DEBUG_IOCTL("VIDIOC_DBG_S_REGISTER\n"); | ||
329 | |||
330 | if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) | ||
331 | return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); | ||
332 | if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) | ||
333 | return cx18_i2c_id(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER, | ||
334 | reg); | ||
335 | return cx18_call_i2c_client(cx, reg->match_chip, VIDIOC_DBG_S_REGISTER, | ||
336 | reg); | ||
337 | } | ||
338 | |||
339 | static int cx18_g_priority(struct file *file, void *fh, enum v4l2_priority *p) | ||
340 | { | ||
341 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
342 | |||
343 | CX18_DEBUG_IOCTL("VIDIOC_G_PRIORITY\n"); | ||
344 | |||
345 | *p = v4l2_prio_max(&cx->prio); | ||
355 | return 0; | 346 | return 0; |
356 | } | 347 | } |
357 | 348 | ||
358 | int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg) | 349 | static int cx18_s_priority(struct file *file, void *fh, enum v4l2_priority prio) |
359 | { | 350 | { |
360 | struct cx18_open_id *id = NULL; | 351 | struct cx18_open_id *id = fh; |
352 | struct cx18 *cx = id->cx; | ||
361 | 353 | ||
362 | if (filp) | 354 | CX18_DEBUG_IOCTL("VIDIOC_S_PRIORITY\n"); |
363 | id = (struct cx18_open_id *)filp->private_data; | ||
364 | 355 | ||
365 | switch (cmd) { | 356 | return v4l2_prio_change(&cx->prio, &id->prio, prio); |
366 | case VIDIOC_G_PRIORITY: | 357 | } |
367 | { | ||
368 | enum v4l2_priority *p = arg; | ||
369 | 358 | ||
370 | *p = v4l2_prio_max(&cx->prio); | 359 | static int cx18_querycap(struct file *file, void *fh, |
371 | break; | 360 | struct v4l2_capability *vcap) |
372 | } | 361 | { |
362 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
373 | 363 | ||
374 | case VIDIOC_S_PRIORITY: | 364 | CX18_DEBUG_IOCTL("VIDIOC_QUERYCAP\n"); |
375 | { | ||
376 | enum v4l2_priority *prio = arg; | ||
377 | 365 | ||
378 | return v4l2_prio_change(&cx->prio, &id->prio, *prio); | 366 | strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); |
379 | } | 367 | strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); |
368 | strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info)); | ||
369 | vcap->version = CX18_DRIVER_VERSION; /* version */ | ||
370 | vcap->capabilities = cx->v4l2_cap; /* capabilities */ | ||
371 | return 0; | ||
372 | } | ||
380 | 373 | ||
381 | case VIDIOC_QUERYCAP:{ | 374 | static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) |
382 | struct v4l2_capability *vcap = arg; | 375 | { |
376 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
383 | 377 | ||
384 | memset(vcap, 0, sizeof(*vcap)); | 378 | CX18_DEBUG_IOCTL("VIDIOC_ENUMAUDIO\n"); |
385 | strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); | ||
386 | strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); | ||
387 | strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info)); | ||
388 | vcap->version = CX18_DRIVER_VERSION; /* version */ | ||
389 | vcap->capabilities = cx->v4l2_cap; /* capabilities */ | ||
390 | 379 | ||
391 | /* reserved.. must set to 0! */ | 380 | return cx18_get_audio_input(cx, vin->index, vin); |
392 | vcap->reserved[0] = vcap->reserved[1] = | 381 | } |
393 | vcap->reserved[2] = vcap->reserved[3] = 0; | ||
394 | break; | ||
395 | } | ||
396 | 382 | ||
397 | case VIDIOC_ENUMAUDIO:{ | 383 | static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) |
398 | struct v4l2_audio *vin = arg; | 384 | { |
385 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
399 | 386 | ||
400 | return cx18_get_audio_input(cx, vin->index, vin); | 387 | CX18_DEBUG_IOCTL("VIDIOC_G_AUDIO\n"); |
401 | } | ||
402 | 388 | ||
403 | case VIDIOC_G_AUDIO:{ | 389 | vin->index = cx->audio_input; |
404 | struct v4l2_audio *vin = arg; | 390 | return cx18_get_audio_input(cx, vin->index, vin); |
391 | } | ||
405 | 392 | ||
406 | vin->index = cx->audio_input; | 393 | static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) |
407 | return cx18_get_audio_input(cx, vin->index, vin); | 394 | { |
408 | } | 395 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
409 | 396 | ||
410 | case VIDIOC_S_AUDIO:{ | 397 | CX18_DEBUG_IOCTL("VIDIOC_S_AUDIO\n"); |
411 | struct v4l2_audio *vout = arg; | ||
412 | 398 | ||
413 | if (vout->index >= cx->nof_audio_inputs) | 399 | if (vout->index >= cx->nof_audio_inputs) |
414 | return -EINVAL; | 400 | return -EINVAL; |
415 | cx->audio_input = vout->index; | 401 | cx->audio_input = vout->index; |
416 | cx18_audio_set_io(cx); | 402 | cx18_audio_set_io(cx); |
417 | break; | 403 | return 0; |
418 | } | 404 | } |
419 | 405 | ||
420 | case VIDIOC_ENUMINPUT:{ | 406 | static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) |
421 | struct v4l2_input *vin = arg; | 407 | { |
408 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
422 | 409 | ||
423 | /* set it to defaults from our table */ | 410 | CX18_DEBUG_IOCTL("VIDIOC_ENUMINPUT\n"); |
424 | return cx18_get_input(cx, vin->index, vin); | ||
425 | } | ||
426 | 411 | ||
427 | case VIDIOC_TRY_FMT: | 412 | /* set it to defaults from our table */ |
428 | case VIDIOC_S_FMT: { | 413 | return cx18_get_input(cx, vin->index, vin); |
429 | struct v4l2_format *fmt = arg; | 414 | } |
430 | 415 | ||
431 | return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT); | 416 | static int cx18_cropcap(struct file *file, void *fh, |
432 | } | 417 | struct v4l2_cropcap *cropcap) |
418 | { | ||
419 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
433 | 420 | ||
434 | case VIDIOC_G_FMT: { | 421 | CX18_DEBUG_IOCTL("VIDIOC_CROPCAP\n"); |
435 | struct v4l2_format *fmt = arg; | ||
436 | int type = fmt->type; | ||
437 | 422 | ||
438 | memset(fmt, 0, sizeof(*fmt)); | 423 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
439 | fmt->type = type; | 424 | return -EINVAL; |
440 | return cx18_get_fmt(cx, id->type, fmt); | 425 | cropcap->bounds.top = cropcap->bounds.left = 0; |
441 | } | 426 | cropcap->bounds.width = 720; |
427 | cropcap->bounds.height = cx->is_50hz ? 576 : 480; | ||
428 | cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; | ||
429 | cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; | ||
430 | cropcap->defrect = cropcap->bounds; | ||
431 | return 0; | ||
432 | } | ||
442 | 433 | ||
443 | case VIDIOC_CROPCAP: { | 434 | static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) |
444 | struct v4l2_cropcap *cropcap = arg; | 435 | { |
445 | 436 | struct cx18_open_id *id = fh; | |
446 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 437 | struct cx18 *cx = id->cx; |
447 | return -EINVAL; | 438 | int ret; |
448 | cropcap->bounds.top = cropcap->bounds.left = 0; | ||
449 | cropcap->bounds.width = 720; | ||
450 | cropcap->bounds.height = cx->is_50hz ? 576 : 480; | ||
451 | cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; | ||
452 | cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; | ||
453 | cropcap->defrect = cropcap->bounds; | ||
454 | return 0; | ||
455 | } | ||
456 | 439 | ||
457 | case VIDIOC_S_CROP: { | 440 | ret = v4l2_prio_check(&cx->prio, &id->prio); |
458 | struct v4l2_crop *crop = arg; | 441 | if (ret) |
442 | return ret; | ||
459 | 443 | ||
460 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 444 | CX18_DEBUG_IOCTL("VIDIOC_S_CROP\n"); |
461 | return -EINVAL; | ||
462 | return cx18_av_cmd(cx, VIDIOC_S_CROP, arg); | ||
463 | } | ||
464 | 445 | ||
465 | case VIDIOC_G_CROP: { | 446 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
466 | struct v4l2_crop *crop = arg; | 447 | return -EINVAL; |
448 | return cx18_av_cmd(cx, VIDIOC_S_CROP, crop); | ||
449 | } | ||
467 | 450 | ||
468 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 451 | static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) |
469 | return -EINVAL; | 452 | { |
470 | return cx18_av_cmd(cx, VIDIOC_G_CROP, arg); | 453 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
471 | } | ||
472 | 454 | ||
473 | case VIDIOC_ENUM_FMT: { | 455 | CX18_DEBUG_IOCTL("VIDIOC_G_CROP\n"); |
474 | static struct v4l2_fmtdesc formats[] = { | 456 | |
475 | { 0, 0, 0, | 457 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
476 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, | 458 | return -EINVAL; |
477 | { 0, 0, 0, 0 } | 459 | return cx18_av_cmd(cx, VIDIOC_G_CROP, crop); |
478 | }, | 460 | } |
479 | { 1, 0, V4L2_FMT_FLAG_COMPRESSED, | 461 | |
480 | "MPEG", V4L2_PIX_FMT_MPEG, | 462 | static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, |
481 | { 0, 0, 0, 0 } | 463 | struct v4l2_fmtdesc *fmt) |
482 | } | 464 | { |
483 | }; | 465 | static struct v4l2_fmtdesc formats[] = { |
484 | struct v4l2_fmtdesc *fmt = arg; | 466 | { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, |
485 | enum v4l2_buf_type type = fmt->type; | 467 | "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } |
486 | 468 | }, | |
487 | switch (type) { | 469 | { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, |
488 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | 470 | "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } |
489 | break; | ||
490 | default: | ||
491 | return -EINVAL; | ||
492 | } | 471 | } |
493 | if (fmt->index > 1) | 472 | }; |
494 | return -EINVAL; | 473 | |
495 | *fmt = formats[fmt->index]; | 474 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
496 | fmt->type = type; | 475 | |
476 | CX18_DEBUG_IOCTL("VIDIOC_ENUM_FMT: V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); | ||
477 | |||
478 | if (fmt->index > 1) | ||
479 | return -EINVAL; | ||
480 | *fmt = formats[fmt->index]; | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int cx18_g_input(struct file *file, void *fh, unsigned int *i) | ||
485 | { | ||
486 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
487 | |||
488 | CX18_DEBUG_IOCTL("VIDIOC_G_INPUT\n"); | ||
489 | |||
490 | *i = cx->active_input; | ||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | int cx18_s_input(struct file *file, void *fh, unsigned int inp) | ||
495 | { | ||
496 | struct cx18_open_id *id = fh; | ||
497 | struct cx18 *cx = id->cx; | ||
498 | int ret; | ||
499 | |||
500 | ret = v4l2_prio_check(&cx->prio, &id->prio); | ||
501 | if (ret) | ||
502 | return ret; | ||
503 | |||
504 | CX18_DEBUG_IOCTL("VIDIOC_S_INPUT\n"); | ||
505 | |||
506 | if (inp < 0 || inp >= cx->nof_inputs) | ||
507 | return -EINVAL; | ||
508 | |||
509 | if (inp == cx->active_input) { | ||
510 | CX18_DEBUG_INFO("Input unchanged\n"); | ||
497 | return 0; | 511 | return 0; |
498 | } | 512 | } |
499 | 513 | ||
500 | case VIDIOC_G_INPUT:{ | 514 | CX18_DEBUG_INFO("Changing input from %d to %d\n", |
501 | *(int *)arg = cx->active_input; | 515 | cx->active_input, inp); |
502 | break; | ||
503 | } | ||
504 | 516 | ||
505 | case VIDIOC_S_INPUT:{ | 517 | cx->active_input = inp; |
506 | int inp = *(int *)arg; | 518 | /* Set the audio input to whatever is appropriate for the input type. */ |
519 | cx->audio_input = cx->card->video_inputs[inp].audio_index; | ||
507 | 520 | ||
508 | if (inp < 0 || inp >= cx->nof_inputs) | 521 | /* prevent others from messing with the streams until |
509 | return -EINVAL; | 522 | we're finished changing inputs. */ |
523 | cx18_mute(cx); | ||
524 | cx18_video_set_io(cx); | ||
525 | cx18_audio_set_io(cx); | ||
526 | cx18_unmute(cx); | ||
527 | return 0; | ||
528 | } | ||
510 | 529 | ||
511 | if (inp == cx->active_input) { | 530 | static int cx18_g_frequency(struct file *file, void *fh, |
512 | CX18_DEBUG_INFO("Input unchanged\n"); | 531 | struct v4l2_frequency *vf) |
513 | break; | 532 | { |
514 | } | 533 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
515 | CX18_DEBUG_INFO("Changing input from %d to %d\n", | ||
516 | cx->active_input, inp); | ||
517 | 534 | ||
518 | cx->active_input = inp; | 535 | CX18_DEBUG_IOCTL("VIDIOC_G_FREQUENCY\n"); |
519 | /* Set the audio input to whatever is appropriate for the | ||
520 | input type. */ | ||
521 | cx->audio_input = cx->card->video_inputs[inp].audio_index; | ||
522 | 536 | ||
523 | /* prevent others from messing with the streams until | 537 | if (vf->tuner != 0) |
524 | we're finished changing inputs. */ | 538 | return -EINVAL; |
525 | cx18_mute(cx); | ||
526 | cx18_video_set_io(cx); | ||
527 | cx18_audio_set_io(cx); | ||
528 | cx18_unmute(cx); | ||
529 | break; | ||
530 | } | ||
531 | 539 | ||
532 | case VIDIOC_G_FREQUENCY:{ | 540 | cx18_call_i2c_clients(cx, VIDIOC_G_FREQUENCY, vf); |
533 | struct v4l2_frequency *vf = arg; | 541 | return 0; |
542 | } | ||
534 | 543 | ||
535 | if (vf->tuner != 0) | 544 | int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) |
536 | return -EINVAL; | 545 | { |
537 | cx18_call_i2c_clients(cx, cmd, arg); | 546 | struct cx18_open_id *id = fh; |
538 | break; | 547 | struct cx18 *cx = id->cx; |
539 | } | 548 | int ret; |
540 | 549 | ||
541 | case VIDIOC_S_FREQUENCY:{ | 550 | ret = v4l2_prio_check(&cx->prio, &id->prio); |
542 | struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; | 551 | if (ret) |
552 | return ret; | ||
543 | 553 | ||
544 | if (vf.tuner != 0) | 554 | CX18_DEBUG_IOCTL("VIDIOC_S_FREQUENCY\n"); |
545 | return -EINVAL; | ||
546 | 555 | ||
547 | cx18_mute(cx); | 556 | if (vf->tuner != 0) |
548 | CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); | 557 | return -EINVAL; |
549 | cx18_call_i2c_clients(cx, cmd, &vf); | ||
550 | cx18_unmute(cx); | ||
551 | break; | ||
552 | } | ||
553 | 558 | ||
554 | case VIDIOC_ENUMSTD:{ | 559 | cx18_mute(cx); |
555 | struct v4l2_standard *vs = arg; | 560 | CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); |
556 | int idx = vs->index; | 561 | cx18_call_i2c_clients(cx, VIDIOC_S_FREQUENCY, vf); |
562 | cx18_unmute(cx); | ||
563 | return 0; | ||
564 | } | ||
557 | 565 | ||
558 | if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) | 566 | static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) |
559 | return -EINVAL; | 567 | { |
568 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
560 | 569 | ||
561 | *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? | 570 | CX18_DEBUG_IOCTL("VIDIOC_G_STD\n"); |
562 | cx18_std_60hz : cx18_std_50hz; | ||
563 | vs->index = idx; | ||
564 | vs->id = enum_stds[idx].std; | ||
565 | strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); | ||
566 | break; | ||
567 | } | ||
568 | 571 | ||
569 | case VIDIOC_G_STD:{ | 572 | *std = cx->std; |
570 | *(v4l2_std_id *) arg = cx->std; | 573 | return 0; |
571 | break; | 574 | } |
572 | } | ||
573 | 575 | ||
574 | case VIDIOC_S_STD: { | 576 | int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) |
575 | v4l2_std_id std = *(v4l2_std_id *) arg; | 577 | { |
578 | struct cx18_open_id *id = fh; | ||
579 | struct cx18 *cx = id->cx; | ||
580 | int ret; | ||
576 | 581 | ||
577 | if ((std & V4L2_STD_ALL) == 0) | 582 | ret = v4l2_prio_check(&cx->prio, &id->prio); |
578 | return -EINVAL; | 583 | if (ret) |
584 | return ret; | ||
579 | 585 | ||
580 | if (std == cx->std) | 586 | CX18_DEBUG_IOCTL("VIDIOC_S_STD\n"); |
581 | break; | ||
582 | 587 | ||
583 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || | 588 | if ((*std & V4L2_STD_ALL) == 0) |
584 | atomic_read(&cx->ana_capturing) > 0) { | 589 | return -EINVAL; |
585 | /* Switching standard would turn off the radio or mess | ||
586 | with already running streams, prevent that by | ||
587 | returning EBUSY. */ | ||
588 | return -EBUSY; | ||
589 | } | ||
590 | 590 | ||
591 | cx->std = std; | 591 | if (*std == cx->std) |
592 | cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; | 592 | return 0; |
593 | cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; | 593 | |
594 | cx->params.width = 720; | 594 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || |
595 | cx->params.height = cx->is_50hz ? 576 : 480; | 595 | atomic_read(&cx->ana_capturing) > 0) { |
596 | cx->vbi.count = cx->is_50hz ? 18 : 12; | 596 | /* Switching standard would turn off the radio or mess |
597 | cx->vbi.start[0] = cx->is_50hz ? 6 : 10; | 597 | with already running streams, prevent that by |
598 | cx->vbi.start[1] = cx->is_50hz ? 318 : 273; | 598 | returning EBUSY. */ |
599 | cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284; | 599 | return -EBUSY; |
600 | CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std); | ||
601 | |||
602 | /* Tuner */ | ||
603 | cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); | ||
604 | break; | ||
605 | } | 600 | } |
606 | 601 | ||
607 | case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ | 602 | cx->std = *std; |
608 | struct v4l2_tuner *vt = arg; | 603 | cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; |
604 | cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; | ||
605 | cx->params.width = 720; | ||
606 | cx->params.height = cx->is_50hz ? 576 : 480; | ||
607 | cx->vbi.count = cx->is_50hz ? 18 : 12; | ||
608 | cx->vbi.start[0] = cx->is_50hz ? 6 : 10; | ||
609 | cx->vbi.start[1] = cx->is_50hz ? 318 : 273; | ||
610 | cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284; | ||
611 | CX18_DEBUG_INFO("Switching standard to %llx.\n", | ||
612 | (unsigned long long) cx->std); | ||
613 | |||
614 | /* Tuner */ | ||
615 | cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); | ||
616 | return 0; | ||
617 | } | ||
609 | 618 | ||
610 | if (vt->index != 0) | 619 | static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) |
611 | return -EINVAL; | 620 | { |
621 | struct cx18_open_id *id = fh; | ||
622 | struct cx18 *cx = id->cx; | ||
623 | int ret; | ||
612 | 624 | ||
613 | cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); | 625 | ret = v4l2_prio_check(&cx->prio, &id->prio); |
614 | break; | 626 | if (ret) |
627 | return ret; | ||
628 | |||
629 | CX18_DEBUG_IOCTL("VIDIOC_S_TUNER\n"); | ||
630 | |||
631 | if (vt->index != 0) | ||
632 | return -EINVAL; | ||
633 | |||
634 | /* Setting tuner can only set audio mode */ | ||
635 | cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) | ||
641 | { | ||
642 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
643 | |||
644 | CX18_DEBUG_IOCTL("VIDIOC_G_TUNER\n"); | ||
645 | |||
646 | if (vt->index != 0) | ||
647 | return -EINVAL; | ||
648 | |||
649 | cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); | ||
650 | |||
651 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { | ||
652 | strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); | ||
653 | vt->type = V4L2_TUNER_RADIO; | ||
654 | } else { | ||
655 | strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); | ||
656 | vt->type = V4L2_TUNER_ANALOG_TV; | ||
615 | } | 657 | } |
616 | 658 | ||
617 | case VIDIOC_G_TUNER: { | 659 | return 0; |
618 | struct v4l2_tuner *vt = arg; | 660 | } |
661 | |||
662 | static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, | ||
663 | struct v4l2_sliced_vbi_cap *cap) | ||
664 | { | ||
665 | return -EINVAL; | ||
666 | } | ||
619 | 667 | ||
620 | if (vt->index != 0) | 668 | static int cx18_g_enc_index(struct file *file, void *fh, |
621 | return -EINVAL; | 669 | struct v4l2_enc_idx *idx) |
670 | { | ||
671 | return -EINVAL; | ||
672 | } | ||
622 | 673 | ||
623 | memset(vt, 0, sizeof(*vt)); | 674 | static int cx18_encoder_cmd(struct file *file, void *fh, |
624 | cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); | 675 | struct v4l2_encoder_cmd *enc) |
676 | { | ||
677 | struct cx18_open_id *id = fh; | ||
678 | struct cx18 *cx = id->cx; | ||
625 | 679 | ||
626 | if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { | 680 | CX18_DEBUG_IOCTL("VIDIOC_ENCODER_CMD:\n"); |
627 | strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); | 681 | |
628 | vt->type = V4L2_TUNER_RADIO; | 682 | memset(&enc->raw, 0, sizeof(enc->raw)); |
629 | } else { | 683 | |
630 | strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); | 684 | switch (enc->cmd) { |
631 | vt->type = V4L2_TUNER_ANALOG_TV; | 685 | case V4L2_ENC_CMD_START: |
632 | } | 686 | CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); |
687 | enc->flags = 0; | ||
688 | return cx18_start_capture(id); | ||
689 | |||
690 | case V4L2_ENC_CMD_STOP: | ||
691 | CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); | ||
692 | enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; | ||
693 | cx18_stop_capture(id, | ||
694 | enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); | ||
633 | break; | 695 | break; |
634 | } | ||
635 | 696 | ||
636 | case VIDIOC_G_SLICED_VBI_CAP: { | 697 | case V4L2_ENC_CMD_PAUSE: |
637 | struct v4l2_sliced_vbi_cap *cap = arg; | 698 | CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); |
638 | int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; | 699 | enc->flags = 0; |
639 | int f, l; | 700 | if (!atomic_read(&cx->ana_capturing)) |
640 | enum v4l2_buf_type type = cap->type; | 701 | return -EPERM; |
641 | 702 | if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) | |
642 | memset(cap, 0, sizeof(*cap)); | ||
643 | cap->type = type; | ||
644 | if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { | ||
645 | for (f = 0; f < 2; f++) { | ||
646 | for (l = 0; l < 24; l++) { | ||
647 | if (valid_service_line(f, l, cx->is_50hz)) | ||
648 | cap->service_lines[f][l] = set; | ||
649 | } | ||
650 | } | ||
651 | return 0; | 703 | return 0; |
652 | } | 704 | cx18_mute(cx); |
705 | cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx)); | ||
706 | break; | ||
707 | |||
708 | case V4L2_ENC_CMD_RESUME: | ||
709 | CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); | ||
710 | enc->flags = 0; | ||
711 | if (!atomic_read(&cx->ana_capturing)) | ||
712 | return -EPERM; | ||
713 | if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) | ||
714 | return 0; | ||
715 | cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx)); | ||
716 | cx18_unmute(cx); | ||
717 | break; | ||
718 | |||
719 | default: | ||
720 | CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); | ||
653 | return -EINVAL; | 721 | return -EINVAL; |
654 | } | 722 | } |
723 | return 0; | ||
724 | } | ||
655 | 725 | ||
656 | case VIDIOC_ENCODER_CMD: | 726 | static int cx18_try_encoder_cmd(struct file *file, void *fh, |
657 | case VIDIOC_TRY_ENCODER_CMD: { | 727 | struct v4l2_encoder_cmd *enc) |
658 | struct v4l2_encoder_cmd *enc = arg; | 728 | { |
659 | int try = cmd == VIDIOC_TRY_ENCODER_CMD; | 729 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
660 | |||
661 | memset(&enc->raw, 0, sizeof(enc->raw)); | ||
662 | switch (enc->cmd) { | ||
663 | case V4L2_ENC_CMD_START: | ||
664 | enc->flags = 0; | ||
665 | if (try) | ||
666 | return 0; | ||
667 | return cx18_start_capture(id); | ||
668 | |||
669 | case V4L2_ENC_CMD_STOP: | ||
670 | enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; | ||
671 | if (try) | ||
672 | return 0; | ||
673 | cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); | ||
674 | return 0; | ||
675 | 730 | ||
676 | case V4L2_ENC_CMD_PAUSE: | 731 | CX18_DEBUG_IOCTL("VIDIOC_TRY_ENCDOER_CMD:\n"); |
677 | enc->flags = 0; | 732 | |
678 | if (try) | 733 | memset(&enc->raw, 0, sizeof(enc->raw)); |
679 | return 0; | 734 | |
680 | if (!atomic_read(&cx->ana_capturing)) | 735 | switch (enc->cmd) { |
681 | return -EPERM; | 736 | case V4L2_ENC_CMD_START: |
682 | if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) | 737 | CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); |
683 | return 0; | 738 | enc->flags = 0; |
684 | cx18_mute(cx); | ||
685 | cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx)); | ||
686 | break; | ||
687 | |||
688 | case V4L2_ENC_CMD_RESUME: | ||
689 | enc->flags = 0; | ||
690 | if (try) | ||
691 | return 0; | ||
692 | if (!atomic_read(&cx->ana_capturing)) | ||
693 | return -EPERM; | ||
694 | if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) | ||
695 | return 0; | ||
696 | cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx)); | ||
697 | cx18_unmute(cx); | ||
698 | break; | ||
699 | default: | ||
700 | return -EINVAL; | ||
701 | } | ||
702 | break; | 739 | break; |
703 | } | ||
704 | 740 | ||
705 | case VIDIOC_LOG_STATUS: | 741 | case V4L2_ENC_CMD_STOP: |
706 | { | 742 | CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); |
707 | struct v4l2_input vidin; | 743 | enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; |
708 | struct v4l2_audio audin; | 744 | break; |
709 | int i; | ||
710 | 745 | ||
711 | CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); | 746 | case V4L2_ENC_CMD_PAUSE: |
712 | if (cx->hw_flags & CX18_HW_TVEEPROM) { | 747 | CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); |
713 | struct tveeprom tv; | 748 | enc->flags = 0; |
749 | break; | ||
714 | 750 | ||
715 | cx18_read_eeprom(cx, &tv); | 751 | case V4L2_ENC_CMD_RESUME: |
716 | } | 752 | CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); |
717 | cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL); | 753 | enc->flags = 0; |
718 | cx18_get_input(cx, cx->active_input, &vidin); | ||
719 | cx18_get_audio_input(cx, cx->audio_input, &audin); | ||
720 | CX18_INFO("Video Input: %s\n", vidin.name); | ||
721 | CX18_INFO("Audio Input: %s\n", audin.name); | ||
722 | CX18_INFO("Tuner: %s\n", | ||
723 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? | ||
724 | "Radio" : "TV"); | ||
725 | cx2341x_log_status(&cx->params, cx->name); | ||
726 | CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); | ||
727 | for (i = 0; i < CX18_MAX_STREAMS; i++) { | ||
728 | struct cx18_stream *s = &cx->streams[i]; | ||
729 | |||
730 | if (s->v4l2dev == NULL || s->buffers == 0) | ||
731 | continue; | ||
732 | CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", | ||
733 | s->name, s->s_flags, | ||
734 | (s->buffers - s->q_free.buffers) * 100 / s->buffers, | ||
735 | (s->buffers * s->buf_size) / 1024, s->buffers); | ||
736 | } | ||
737 | CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", | ||
738 | (long long)cx->mpg_data_received, | ||
739 | (long long)cx->vbi_data_inserted); | ||
740 | CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); | ||
741 | break; | 754 | break; |
742 | } | ||
743 | 755 | ||
744 | default: | 756 | default: |
757 | CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); | ||
745 | return -EINVAL; | 758 | return -EINVAL; |
746 | } | 759 | } |
747 | return 0; | 760 | return 0; |
748 | } | 761 | } |
749 | 762 | ||
750 | static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp, | 763 | static int cx18_log_status(struct file *file, void *fh) |
751 | unsigned int cmd, void *arg) | ||
752 | { | 764 | { |
753 | struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; | 765 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; |
754 | struct cx18 *cx = id->cx; | 766 | struct v4l2_input vidin; |
755 | int ret; | 767 | struct v4l2_audio audin; |
768 | int i; | ||
756 | 769 | ||
757 | /* check priority */ | 770 | CX18_DEBUG_IOCTL("VIDIOC_LOG_STATUS\n"); |
758 | switch (cmd) { | 771 | CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); |
759 | case VIDIOC_S_CTRL: | 772 | if (cx->hw_flags & CX18_HW_TVEEPROM) { |
760 | case VIDIOC_S_STD: | 773 | struct tveeprom tv; |
761 | case VIDIOC_S_INPUT: | 774 | |
762 | case VIDIOC_S_TUNER: | 775 | cx18_read_eeprom(cx, &tv); |
763 | case VIDIOC_S_FREQUENCY: | 776 | } |
764 | case VIDIOC_S_FMT: | 777 | cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL); |
765 | case VIDIOC_S_CROP: | 778 | cx18_get_input(cx, cx->active_input, &vidin); |
766 | case VIDIOC_S_EXT_CTRLS: | 779 | cx18_get_audio_input(cx, cx->audio_input, &audin); |
767 | ret = v4l2_prio_check(&cx->prio, &id->prio); | 780 | CX18_INFO("Video Input: %s\n", vidin.name); |
768 | if (ret) | 781 | CX18_INFO("Audio Input: %s\n", audin.name); |
769 | return ret; | 782 | CX18_INFO("Tuner: %s\n", |
770 | } | 783 | test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); |
784 | cx2341x_log_status(&cx->params, cx->name); | ||
785 | CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); | ||
786 | for (i = 0; i < CX18_MAX_STREAMS; i++) { | ||
787 | struct cx18_stream *s = &cx->streams[i]; | ||
788 | |||
789 | if (s->v4l2dev == NULL || s->buffers == 0) | ||
790 | continue; | ||
791 | CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", | ||
792 | s->name, s->s_flags, | ||
793 | (s->buffers - s->q_free.buffers) * 100 / s->buffers, | ||
794 | (s->buffers * s->buf_size) / 1024, s->buffers); | ||
795 | } | ||
796 | CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", | ||
797 | (long long)cx->mpg_data_received, | ||
798 | (long long)cx->vbi_data_inserted); | ||
799 | CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); | ||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | static int cx18_default(struct file *file, void *fh, int cmd, void *arg) | ||
804 | { | ||
805 | struct cx18 *cx = ((struct cx18_open_id *)fh)->cx; | ||
771 | 806 | ||
772 | switch (cmd) { | 807 | switch (cmd) { |
773 | case VIDIOC_DBG_G_REGISTER: | 808 | case VIDIOC_INT_S_AUDIO_ROUTING: { |
774 | case VIDIOC_DBG_S_REGISTER: | 809 | struct v4l2_routing *route = arg; |
775 | case VIDIOC_G_CHIP_IDENT: | 810 | CX18_DEBUG_IOCTL("VIDIOC_INT_S_AUDIO_ROUTING (%d, %d)\n", |
776 | case VIDIOC_INT_S_AUDIO_ROUTING: | 811 | route->input, route->output); |
777 | case VIDIOC_INT_RESET: | 812 | cx18_audio_set_route(cx, route); |
778 | if (cx18_debug & CX18_DBGFLG_IOCTL) { | 813 | break; |
779 | printk(KERN_INFO "cx18%d ioctl: ", cx->num); | 814 | } |
780 | v4l_printk_ioctl(cmd); | 815 | case VIDIOC_INT_RESET: { |
781 | } | 816 | u32 val = *(u32 *)arg; |
782 | return cx18_debug_ioctls(filp, cmd, arg); | 817 | CX18_DEBUG_IOCTL("VIDIOC_INT_RESET (%#10x)\n", val); |
783 | 818 | /* No op right now */ | |
784 | case VIDIOC_G_PRIORITY: | 819 | /* cx18_av_cmd(cx, cmd, arg) */ |
785 | case VIDIOC_S_PRIORITY: | 820 | /* cx18_call_i2c_clients(cx, cmd, arg) */ |
786 | case VIDIOC_QUERYCAP: | 821 | break; |
787 | case VIDIOC_ENUMINPUT: | 822 | } |
788 | case VIDIOC_G_INPUT: | 823 | default: |
789 | case VIDIOC_S_INPUT: | ||
790 | case VIDIOC_G_FMT: | ||
791 | case VIDIOC_S_FMT: | ||
792 | case VIDIOC_TRY_FMT: | ||
793 | case VIDIOC_ENUM_FMT: | ||
794 | case VIDIOC_CROPCAP: | ||
795 | case VIDIOC_G_CROP: | ||
796 | case VIDIOC_S_CROP: | ||
797 | case VIDIOC_G_FREQUENCY: | ||
798 | case VIDIOC_S_FREQUENCY: | ||
799 | case VIDIOC_ENUMSTD: | ||
800 | case VIDIOC_G_STD: | ||
801 | case VIDIOC_S_STD: | ||
802 | case VIDIOC_S_TUNER: | ||
803 | case VIDIOC_G_TUNER: | ||
804 | case VIDIOC_ENUMAUDIO: | ||
805 | case VIDIOC_S_AUDIO: | ||
806 | case VIDIOC_G_AUDIO: | ||
807 | case VIDIOC_G_SLICED_VBI_CAP: | ||
808 | case VIDIOC_LOG_STATUS: | ||
809 | case VIDIOC_G_ENC_INDEX: | ||
810 | case VIDIOC_ENCODER_CMD: | ||
811 | case VIDIOC_TRY_ENCODER_CMD: | ||
812 | if (cx18_debug & CX18_DBGFLG_IOCTL) { | ||
813 | printk(KERN_INFO "cx18%d ioctl: ", cx->num); | ||
814 | v4l_printk_ioctl(cmd); | ||
815 | } | ||
816 | return cx18_v4l2_ioctls(cx, filp, cmd, arg); | ||
817 | |||
818 | case VIDIOC_QUERYMENU: | ||
819 | case VIDIOC_QUERYCTRL: | ||
820 | case VIDIOC_S_CTRL: | ||
821 | case VIDIOC_G_CTRL: | ||
822 | case VIDIOC_S_EXT_CTRLS: | ||
823 | case VIDIOC_G_EXT_CTRLS: | ||
824 | case VIDIOC_TRY_EXT_CTRLS: | ||
825 | if (cx18_debug & CX18_DBGFLG_IOCTL) { | 824 | if (cx18_debug & CX18_DBGFLG_IOCTL) { |
826 | printk(KERN_INFO "cx18%d ioctl: ", cx->num); | 825 | printk(KERN_INFO "cx18%d ioctl: unsupported cmd: ", |
826 | cx->num); | ||
827 | v4l_printk_ioctl(cmd); | 827 | v4l_printk_ioctl(cmd); |
828 | printk("\n"); | ||
828 | } | 829 | } |
829 | return cx18_control_ioctls(cx, cmd, arg); | ||
830 | |||
831 | case 0x00005401: /* Handle isatty() calls */ | ||
832 | return -EINVAL; | 830 | return -EINVAL; |
833 | default: | ||
834 | return v4l_compat_translate_ioctl(inode, filp, cmd, arg, | ||
835 | cx18_v4l2_do_ioctl); | ||
836 | } | 831 | } |
837 | return 0; | 832 | return 0; |
838 | } | 833 | } |
@@ -845,7 +840,55 @@ int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
845 | int res; | 840 | int res; |
846 | 841 | ||
847 | mutex_lock(&cx->serialize_lock); | 842 | mutex_lock(&cx->serialize_lock); |
848 | res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl); | 843 | res = video_ioctl2(inode, filp, cmd, arg); |
849 | mutex_unlock(&cx->serialize_lock); | 844 | mutex_unlock(&cx->serialize_lock); |
850 | return res; | 845 | return res; |
851 | } | 846 | } |
847 | |||
848 | void cx18_set_funcs(struct video_device *vdev) | ||
849 | { | ||
850 | vdev->vidioc_querycap = cx18_querycap; | ||
851 | vdev->vidioc_g_priority = cx18_g_priority; | ||
852 | vdev->vidioc_s_priority = cx18_s_priority; | ||
853 | vdev->vidioc_s_audio = cx18_s_audio; | ||
854 | vdev->vidioc_g_audio = cx18_g_audio; | ||
855 | vdev->vidioc_enumaudio = cx18_enumaudio; | ||
856 | vdev->vidioc_enum_input = cx18_enum_input; | ||
857 | vdev->vidioc_cropcap = cx18_cropcap; | ||
858 | vdev->vidioc_s_crop = cx18_s_crop; | ||
859 | vdev->vidioc_g_crop = cx18_g_crop; | ||
860 | vdev->vidioc_g_input = cx18_g_input; | ||
861 | vdev->vidioc_s_input = cx18_s_input; | ||
862 | vdev->vidioc_g_frequency = cx18_g_frequency; | ||
863 | vdev->vidioc_s_frequency = cx18_s_frequency; | ||
864 | vdev->vidioc_s_tuner = cx18_s_tuner; | ||
865 | vdev->vidioc_g_tuner = cx18_g_tuner; | ||
866 | vdev->vidioc_g_enc_index = cx18_g_enc_index; | ||
867 | vdev->vidioc_g_std = cx18_g_std; | ||
868 | vdev->vidioc_s_std = cx18_s_std; | ||
869 | vdev->vidioc_log_status = cx18_log_status; | ||
870 | vdev->vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap; | ||
871 | vdev->vidioc_encoder_cmd = cx18_encoder_cmd; | ||
872 | vdev->vidioc_try_encoder_cmd = cx18_try_encoder_cmd; | ||
873 | vdev->vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap; | ||
874 | vdev->vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap; | ||
875 | vdev->vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap; | ||
876 | vdev->vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap; | ||
877 | vdev->vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap; | ||
878 | vdev->vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap; | ||
879 | vdev->vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap; | ||
880 | vdev->vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap; | ||
881 | vdev->vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap; | ||
882 | vdev->vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap; | ||
883 | vdev->vidioc_g_chip_ident = cx18_g_chip_ident; | ||
884 | vdev->vidioc_g_register = cx18_g_register; | ||
885 | vdev->vidioc_s_register = cx18_s_register; | ||
886 | vdev->vidioc_default = cx18_default; | ||
887 | vdev->vidioc_queryctrl = cx18_queryctrl; | ||
888 | vdev->vidioc_querymenu = cx18_querymenu; | ||
889 | vdev->vidioc_g_ctrl = cx18_g_ctrl; | ||
890 | vdev->vidioc_s_ctrl = cx18_s_ctrl; | ||
891 | vdev->vidioc_g_ext_ctrls = cx18_g_ext_ctrls; | ||
892 | vdev->vidioc_s_ext_ctrls = cx18_s_ext_ctrls; | ||
893 | vdev->vidioc_try_ext_ctrls = cx18_try_ext_ctrls; | ||
894 | } | ||
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h index 9f4c7eb2897f..2222f679d86d 100644 --- a/drivers/media/video/cx18/cx18-ioctl.h +++ b/drivers/media/video/cx18/cx18-ioctl.h | |||
@@ -24,7 +24,9 @@ | |||
24 | u16 cx18_service2vbi(int type); | 24 | u16 cx18_service2vbi(int type); |
25 | void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); | 25 | void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); |
26 | u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); | 26 | u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); |
27 | void cx18_set_funcs(struct video_device *vdev); | ||
28 | int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); | ||
29 | int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); | ||
30 | int cx18_s_input(struct file *file, void *fh, unsigned int inp); | ||
27 | int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | 31 | int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, |
28 | unsigned long arg); | 32 | unsigned long arg); |
29 | int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, | ||
30 | void *arg); | ||
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c index 1b921a336092..805847370cba 100644 --- a/drivers/media/video/cx18/cx18-streams.c +++ b/drivers/media/video/cx18/cx18-streams.c | |||
@@ -39,6 +39,7 @@ static struct file_operations cx18_v4l2_enc_fops = { | |||
39 | .owner = THIS_MODULE, | 39 | .owner = THIS_MODULE, |
40 | .read = cx18_v4l2_read, | 40 | .read = cx18_v4l2_read, |
41 | .open = cx18_v4l2_open, | 41 | .open = cx18_v4l2_open, |
42 | /* FIXME change to video_ioctl2 if serialization lock can be removed */ | ||
42 | .ioctl = cx18_v4l2_ioctl, | 43 | .ioctl = cx18_v4l2_ioctl, |
43 | .compat_ioctl = v4l_compat_ioctl32, | 44 | .compat_ioctl = v4l_compat_ioctl32, |
44 | .release = cx18_v4l2_close, | 45 | .release = cx18_v4l2_close, |
@@ -196,7 +197,8 @@ static int cx18_prep_dev(struct cx18 *cx, int type) | |||
196 | s->v4l2dev->dev = &cx->dev->dev; | 197 | s->v4l2dev->dev = &cx->dev->dev; |
197 | s->v4l2dev->fops = cx18_stream_info[type].fops; | 198 | s->v4l2dev->fops = cx18_stream_info[type].fops; |
198 | s->v4l2dev->release = video_device_release; | 199 | s->v4l2dev->release = video_device_release; |
199 | 200 | s->v4l2dev->tvnorms = V4L2_STD_ALL; | |
201 | cx18_set_funcs(s->v4l2dev); | ||
200 | return 0; | 202 | return 0; |
201 | } | 203 | } |
202 | 204 | ||