aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-ioctl.c
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2008-06-21 07:36:31 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-07-20 06:10:43 -0400
commit3b6fe58f0f18880200969e813d0181d1bdab0966 (patch)
treee059efc521b5eeb2b0f022f7c7e56d3a8f3b7a86 /drivers/media/video/cx18/cx18-ioctl.c
parent1a05221bc45ccb1b5c583a87dc3639bfc10c4f10 (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>
Diffstat (limited to 'drivers/media/video/cx18/cx18-ioctl.c')
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c1211
1 files changed, 627 insertions, 584 deletions
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
103static 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
117u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) 104u16 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
129static 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
148static const struct v4l2_standard cx18_std_60hz = {
149 .frameperiod = {.numerator = 1001, .denominator = 30000},
150 .framelines = 525,
151};
152
153static const struct v4l2_standard cx18_std_50hz = {
154 .frameperiod = { .numerator = 1, .denominator = 25 },
155 .framelines = 625,
156};
157
158static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) 116static 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
177static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt) 135static 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: 160static 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
225static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, 177static 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 */ 183static 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 */ 204static 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
214static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh,
215 struct v4l2_format *fmt)
216{
217 return -EINVAL;
218}
219
220static 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
303static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) 255static 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
278static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh,
279 struct v4l2_format *fmt)
280{
281 return -EINVAL;
282}
283
284static 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
307static 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
323static 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
339static 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
358int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg) 349static 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); 359static 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:{ 374static 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:{ 383static 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; 393static 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:{ 406static 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); 416static 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: { 434static 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) 451static 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, 462static 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
484static 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
494int 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) { 530static 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) 544int 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)) 566static 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: { 576int 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) 619static 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
640static 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
662static 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) 668static 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)); 674static 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: 726static 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
750static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp, 763static 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
803static 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
848void 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}