2 * cx18 ioctl system call
4 * Derived from ivtv-ioctl.c
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 #include "cx18-driver.h"
25 #include "cx18-version.h"
26 #include "cx18-mailbox.h"
28 #include "cx18-queue.h"
29 #include "cx18-fileops.h"
31 #include "cx18-audio.h"
32 #include "cx18-video.h"
33 #include "cx18-streams.h"
34 #include "cx18-ioctl.h"
35 #include "cx18-gpio.h"
36 #include "cx18-controls.h"
37 #include "cx18-cards.h"
38 #include "cx18-av-core.h"
39 #include <media/tveeprom.h>
40 #include <media/v4l2-chip-ident.h>
41 #include <linux/i2c-id.h>
43 u16
cx18_service2vbi(int type
)
46 case V4L2_SLICED_TELETEXT_B
:
47 return CX18_SLICED_TYPE_TELETEXT_B
;
48 case V4L2_SLICED_CAPTION_525
:
49 return CX18_SLICED_TYPE_CAPTION_525
;
50 case V4L2_SLICED_WSS_625
:
51 return CX18_SLICED_TYPE_WSS_625
;
53 return CX18_SLICED_TYPE_VPS
;
59 static int valid_service_line(int field
, int line
, int is_pal
)
61 return (is_pal
&& line
>= 6 && (line
!= 23 || field
== 0)) ||
62 (!is_pal
&& line
>= 10 && line
< 22);
65 static u16
select_service_from_set(int field
, int line
, u16 set
, int is_pal
)
67 u16 valid_set
= (is_pal
? V4L2_SLICED_VBI_625
: V4L2_SLICED_VBI_525
);
70 set
= set
& valid_set
;
71 if (set
== 0 || !valid_service_line(field
, line
, is_pal
))
74 if (line
== 21 && (set
& V4L2_SLICED_CAPTION_525
))
75 return V4L2_SLICED_CAPTION_525
;
77 if (line
== 16 && field
== 0 && (set
& V4L2_SLICED_VPS
))
78 return V4L2_SLICED_VPS
;
79 if (line
== 23 && field
== 0 && (set
& V4L2_SLICED_WSS_625
))
80 return V4L2_SLICED_WSS_625
;
84 for (i
= 0; i
< 32; i
++) {
91 void cx18_expand_service_set(struct v4l2_sliced_vbi_format
*fmt
, int is_pal
)
93 u16 set
= fmt
->service_set
;
97 for (f
= 0; f
< 2; f
++) {
98 for (l
= 0; l
< 24; l
++)
99 fmt
->service_lines
[f
][l
] = select_service_from_set(f
, l
, set
, is_pal
);
103 static int check_service_set(struct v4l2_sliced_vbi_format
*fmt
, int is_pal
)
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
];
117 u16
cx18_get_service_set(struct v4l2_sliced_vbi_format
*fmt
)
122 for (f
= 0; f
< 2; f
++) {
123 for (l
= 0; l
< 24; l
++)
124 set
|= fmt
->service_lines
[f
][l
];
129 static const struct {
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" },
148 static const struct v4l2_standard cx18_std_60hz
= {
149 .frameperiod
= {.numerator
= 1001, .denominator
= 30000},
153 static const struct v4l2_standard cx18_std_50hz
= {
154 .frameperiod
= { .numerator
= 1, .denominator
= 25 },
158 static int cx18_cxc(struct cx18
*cx
, unsigned int cmd
, void *arg
)
160 struct v4l2_register
*regs
= arg
;
163 if (!capable(CAP_SYS_ADMIN
))
165 if (regs
->reg
>= CX18_MEM_OFFSET
+ CX18_MEM_SIZE
)
168 spin_lock_irqsave(&cx18_cards_lock
, flags
);
169 if (cmd
== VIDIOC_DBG_G_REGISTER
)
170 regs
->val
= read_enc(regs
->reg
);
172 write_enc(regs
->val
, regs
->reg
);
173 spin_unlock_irqrestore(&cx18_cards_lock
, flags
);
177 static int cx18_get_fmt(struct cx18
*cx
, int streamtype
, struct v4l2_format
*fmt
)
180 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
181 fmt
->fmt
.pix
.width
= cx
->params
.width
;
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);
192 fmt
->fmt
.pix
.pixelformat
= V4L2_PIX_FMT_MPEG
;
193 fmt
->fmt
.pix
.sizeimage
= 128 * 1024;
197 case V4L2_BUF_TYPE_VBI_CAPTURE
:
198 fmt
->fmt
.vbi
.sampling_rate
= 27000000;
199 fmt
->fmt
.vbi
.offset
= 248;
200 fmt
->fmt
.vbi
.samples_per_line
= cx
->vbi
.raw_decoder_line_size
- 4;
201 fmt
->fmt
.vbi
.sample_format
= V4L2_PIX_FMT_GREY
;
202 fmt
->fmt
.vbi
.start
[0] = cx
->vbi
.start
[0];
203 fmt
->fmt
.vbi
.start
[1] = cx
->vbi
.start
[1];
204 fmt
->fmt
.vbi
.count
[0] = fmt
->fmt
.vbi
.count
[1] = cx
->vbi
.count
;
207 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
:
209 struct v4l2_sliced_vbi_format
*vbifmt
= &fmt
->fmt
.sliced
;
211 vbifmt
->io_size
= sizeof(struct v4l2_sliced_vbi_data
) * 36;
212 memset(vbifmt
->reserved
, 0, sizeof(vbifmt
->reserved
));
213 memset(vbifmt
->service_lines
, 0, sizeof(vbifmt
->service_lines
));
215 cx18_av_cmd(cx
, VIDIOC_G_FMT
, fmt
);
216 vbifmt
->service_set
= cx18_get_service_set(vbifmt
);
225 static int cx18_try_or_set_fmt(struct cx18
*cx
, int streamtype
,
226 struct v4l2_format
*fmt
, int set_fmt
)
228 struct v4l2_sliced_vbi_format
*vbifmt
= &fmt
->fmt
.sliced
;
231 /* set window size */
232 if (fmt
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE
) {
233 int w
= fmt
->fmt
.pix
.width
;
234 int h
= fmt
->fmt
.pix
.height
;
240 if (h
> (cx
->is_50hz
? 576 : 480))
241 h
= (cx
->is_50hz
? 576 : 480);
244 cx18_get_fmt(cx
, streamtype
, fmt
);
245 fmt
->fmt
.pix
.width
= w
;
246 fmt
->fmt
.pix
.height
= h
;
248 if (!set_fmt
|| (cx
->params
.width
== w
&& cx
->params
.height
== h
))
250 if (atomic_read(&cx
->capturing
) > 0)
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;
258 cx
->params
.video_temporal_filter
= 8;
259 cx18_av_cmd(cx
, VIDIOC_S_FMT
, fmt
);
260 return cx18_get_fmt(cx
, streamtype
, fmt
);
263 /* set raw VBI format */
264 if (fmt
->type
== V4L2_BUF_TYPE_VBI_CAPTURE
) {
265 if (set_fmt
&& streamtype
== CX18_ENC_STREAM_TYPE_VBI
&&
266 cx
->vbi
.sliced_in
->service_set
&&
267 atomic_read(&cx
->capturing
) > 0)
270 cx
->vbi
.sliced_in
->service_set
= 0;
271 cx18_av_cmd(cx
, VIDIOC_S_FMT
, &cx
->vbi
.in
);
273 return cx18_get_fmt(cx
, streamtype
, fmt
);
276 /* any else but sliced VBI capture is an error */
277 if (fmt
->type
!= V4L2_BUF_TYPE_SLICED_VBI_CAPTURE
)
280 /* TODO: implement sliced VBI, for now silently return 0 */
283 /* set sliced VBI capture format */
284 vbifmt
->io_size
= sizeof(struct v4l2_sliced_vbi_data
) * 36;
285 memset(vbifmt
->reserved
, 0, sizeof(vbifmt
->reserved
));
287 if (vbifmt
->service_set
)
288 cx18_expand_service_set(vbifmt
, cx
->is_50hz
);
289 set
= check_service_set(vbifmt
, cx
->is_50hz
);
290 vbifmt
->service_set
= cx18_get_service_set(vbifmt
);
296 if (atomic_read(&cx
->capturing
) > 0 && cx
->vbi
.sliced_in
->service_set
== 0)
298 cx18_av_cmd(cx
, VIDIOC_S_FMT
, fmt
);
299 memcpy(cx
->vbi
.sliced_in
, vbifmt
, sizeof(*cx
->vbi
.sliced_in
));
303 static int cx18_debug_ioctls(struct file
*filp
, unsigned int cmd
, void *arg
)
305 struct cx18_open_id
*id
= (struct cx18_open_id
*)filp
->private_data
;
306 struct cx18
*cx
= id
->cx
;
307 struct v4l2_register
*reg
= arg
;
310 /* ioctls to allow direct access to the encoder registers for testing */
311 case VIDIOC_DBG_G_REGISTER
:
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
);
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
);
325 case VIDIOC_G_CHIP_IDENT
: {
326 struct v4l2_chip_ident
*chip
= arg
;
328 chip
->ident
= V4L2_IDENT_NONE
;
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
;
334 chip
->ident
= V4L2_IDENT_CX23418
;
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
);
345 case VIDIOC_INT_S_AUDIO_ROUTING
: {
346 struct v4l2_routing
*route
= arg
;
348 cx18_audio_set_route(cx
, route
);
358 int cx18_v4l2_ioctls(struct cx18
*cx
, struct file
*filp
, unsigned cmd
, void *arg
)
360 struct cx18_open_id
*id
= NULL
;
363 id
= (struct cx18_open_id
*)filp
->private_data
;
366 case VIDIOC_G_PRIORITY
:
368 enum v4l2_priority
*p
= arg
;
370 *p
= v4l2_prio_max(&cx
->prio
);
374 case VIDIOC_S_PRIORITY
:
376 enum v4l2_priority
*prio
= arg
;
378 return v4l2_prio_change(&cx
->prio
, &id
->prio
, *prio
);
381 case VIDIOC_QUERYCAP
:{
382 struct v4l2_capability
*vcap
= arg
;
384 memset(vcap
, 0, sizeof(*vcap
));
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 */
391 /* reserved.. must set to 0! */
392 vcap
->reserved
[0] = vcap
->reserved
[1] =
393 vcap
->reserved
[2] = vcap
->reserved
[3] = 0;
397 case VIDIOC_ENUMAUDIO
:{
398 struct v4l2_audio
*vin
= arg
;
400 return cx18_get_audio_input(cx
, vin
->index
, vin
);
403 case VIDIOC_G_AUDIO
:{
404 struct v4l2_audio
*vin
= arg
;
406 vin
->index
= cx
->audio_input
;
407 return cx18_get_audio_input(cx
, vin
->index
, vin
);
410 case VIDIOC_S_AUDIO
:{
411 struct v4l2_audio
*vout
= arg
;
413 if (vout
->index
>= cx
->nof_audio_inputs
)
415 cx
->audio_input
= vout
->index
;
416 cx18_audio_set_io(cx
);
420 case VIDIOC_ENUMINPUT
:{
421 struct v4l2_input
*vin
= arg
;
423 /* set it to defaults from our table */
424 return cx18_get_input(cx
, vin
->index
, vin
);
429 struct v4l2_format
*fmt
= arg
;
431 return cx18_try_or_set_fmt(cx
, id
->type
, fmt
, cmd
== VIDIOC_S_FMT
);
435 struct v4l2_format
*fmt
= arg
;
436 int type
= fmt
->type
;
438 memset(fmt
, 0, sizeof(*fmt
));
440 return cx18_get_fmt(cx
, id
->type
, fmt
);
443 case VIDIOC_CROPCAP
: {
444 struct v4l2_cropcap
*cropcap
= arg
;
446 if (cropcap
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
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
;
457 case VIDIOC_S_CROP
: {
458 struct v4l2_crop
*crop
= arg
;
460 if (crop
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
462 return cx18_av_cmd(cx
, VIDIOC_S_CROP
, arg
);
465 case VIDIOC_G_CROP
: {
466 struct v4l2_crop
*crop
= arg
;
468 if (crop
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
470 return cx18_av_cmd(cx
, VIDIOC_G_CROP
, arg
);
473 case VIDIOC_ENUM_FMT
: {
474 static struct v4l2_fmtdesc formats
[] = {
476 "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12
,
479 { 1, 0, V4L2_FMT_FLAG_COMPRESSED
,
480 "MPEG", V4L2_PIX_FMT_MPEG
,
484 struct v4l2_fmtdesc
*fmt
= arg
;
485 enum v4l2_buf_type type
= fmt
->type
;
488 case V4L2_BUF_TYPE_VIDEO_CAPTURE
:
495 *fmt
= formats
[fmt
->index
];
500 case VIDIOC_G_INPUT
:{
501 *(int *)arg
= cx
->active_input
;
505 case VIDIOC_S_INPUT
:{
506 int inp
= *(int *)arg
;
508 if (inp
< 0 || inp
>= cx
->nof_inputs
)
511 if (inp
== cx
->active_input
) {
512 CX18_DEBUG_INFO("Input unchanged\n");
515 CX18_DEBUG_INFO("Changing input from %d to %d\n",
516 cx
->active_input
, inp
);
518 cx
->active_input
= inp
;
519 /* Set the audio input to whatever is appropriate for the
521 cx
->audio_input
= cx
->card
->video_inputs
[inp
].audio_index
;
523 /* prevent others from messing with the streams until
524 we're finished changing inputs. */
526 cx18_video_set_io(cx
);
527 cx18_audio_set_io(cx
);
532 case VIDIOC_G_FREQUENCY
:{
533 struct v4l2_frequency
*vf
= arg
;
537 cx18_call_i2c_clients(cx
, cmd
, arg
);
541 case VIDIOC_S_FREQUENCY
:{
542 struct v4l2_frequency vf
= *(struct v4l2_frequency
*)arg
;
548 CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf
.frequency
);
549 cx18_call_i2c_clients(cx
, cmd
, &vf
);
554 case VIDIOC_ENUMSTD
:{
555 struct v4l2_standard
*vs
= arg
;
558 if (idx
< 0 || idx
>= ARRAY_SIZE(enum_stds
))
561 *vs
= (enum_stds
[idx
].std
& V4L2_STD_525_60
) ?
562 cx18_std_60hz
: cx18_std_50hz
;
564 vs
->id
= enum_stds
[idx
].std
;
565 strlcpy(vs
->name
, enum_stds
[idx
].name
, sizeof(vs
->name
));
570 *(v4l2_std_id
*) arg
= cx
->std
;
575 v4l2_std_id std
= *(v4l2_std_id
*) arg
;
577 if ((std
& V4L2_STD_ALL
) == 0)
583 if (test_bit(CX18_F_I_RADIO_USER
, &cx
->i_flags
) ||
584 atomic_read(&cx
->capturing
) > 0) {
585 /* Switching standard would turn off the radio or mess
586 with already running streams, prevent that by
592 cx
->is_60hz
= (std
& V4L2_STD_525_60
) ? 1 : 0;
593 cx
->params
.is_50hz
= cx
->is_50hz
= !cx
->is_60hz
;
594 cx
->params
.width
= 720;
595 cx
->params
.height
= cx
->is_50hz
? 576 : 480;
596 cx
->vbi
.count
= cx
->is_50hz
? 18 : 12;
597 cx
->vbi
.start
[0] = cx
->is_50hz
? 6 : 10;
598 cx
->vbi
.start
[1] = cx
->is_50hz
? 318 : 273;
599 cx
->vbi
.sliced_decoder_line_size
= cx
->is_60hz
? 272 : 284;
600 CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx
->std
);
603 cx18_call_i2c_clients(cx
, VIDIOC_S_STD
, &cx
->std
);
607 case VIDIOC_S_TUNER
: { /* Setting tuner can only set audio mode */
608 struct v4l2_tuner
*vt
= arg
;
613 cx18_call_i2c_clients(cx
, VIDIOC_S_TUNER
, vt
);
617 case VIDIOC_G_TUNER
: {
618 struct v4l2_tuner
*vt
= arg
;
623 memset(vt
, 0, sizeof(*vt
));
624 cx18_call_i2c_clients(cx
, VIDIOC_G_TUNER
, vt
);
626 if (test_bit(CX18_F_I_RADIO_USER
, &cx
->i_flags
)) {
627 strlcpy(vt
->name
, "cx18 Radio Tuner", sizeof(vt
->name
));
628 vt
->type
= V4L2_TUNER_RADIO
;
630 strlcpy(vt
->name
, "cx18 TV Tuner", sizeof(vt
->name
));
631 vt
->type
= V4L2_TUNER_ANALOG_TV
;
636 case VIDIOC_G_SLICED_VBI_CAP
: {
637 struct v4l2_sliced_vbi_cap
*cap
= arg
;
638 int set
= cx
->is_50hz
? V4L2_SLICED_VBI_625
: V4L2_SLICED_VBI_525
;
640 enum v4l2_buf_type type
= cap
->type
;
642 memset(cap
, 0, sizeof(*cap
));
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
;
656 case VIDIOC_ENCODER_CMD
:
657 case VIDIOC_TRY_ENCODER_CMD
: {
658 struct v4l2_encoder_cmd
*enc
= arg
;
659 int try = cmd
== VIDIOC_TRY_ENCODER_CMD
;
661 memset(&enc
->raw
, 0, sizeof(enc
->raw
));
663 case V4L2_ENC_CMD_START
:
667 return cx18_start_capture(id
);
669 case V4L2_ENC_CMD_STOP
:
670 enc
->flags
&= V4L2_ENC_CMD_STOP_AT_GOP_END
;
673 cx18_stop_capture(id
, enc
->flags
& V4L2_ENC_CMD_STOP_AT_GOP_END
);
676 case V4L2_ENC_CMD_PAUSE
:
680 if (!atomic_read(&cx
->capturing
))
682 if (test_and_set_bit(CX18_F_I_ENC_PAUSED
, &cx
->i_flags
))
685 cx18_vapi(cx
, CX18_CPU_CAPTURE_PAUSE
, 1, cx18_find_handle(cx
));
688 case V4L2_ENC_CMD_RESUME
:
692 if (!atomic_read(&cx
->capturing
))
694 if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED
, &cx
->i_flags
))
696 cx18_vapi(cx
, CX18_CPU_CAPTURE_RESUME
, 1, cx18_find_handle(cx
));
705 case VIDIOC_LOG_STATUS
:
707 struct v4l2_input vidin
;
708 struct v4l2_audio audin
;
711 CX18_INFO("================= START STATUS CARD #%d =================\n", cx
->num
);
712 if (cx
->hw_flags
& CX18_HW_TVEEPROM
) {
715 cx18_read_eeprom(cx
, &tv
);
717 cx18_call_i2c_clients(cx
, VIDIOC_LOG_STATUS
, NULL
);
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
) ?
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
];
730 if (s
->v4l2dev
== NULL
|| s
->buffers
== 0)
732 CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
734 (s
->buffers
- s
->q_free
.buffers
) * 100 / s
->buffers
,
735 (s
->buffers
* s
->buf_size
) / 1024, s
->buffers
);
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
);
750 static int cx18_v4l2_do_ioctl(struct inode
*inode
, struct file
*filp
,
751 unsigned int cmd
, void *arg
)
753 struct cx18_open_id
*id
= (struct cx18_open_id
*)filp
->private_data
;
754 struct cx18
*cx
= id
->cx
;
763 case VIDIOC_S_FREQUENCY
:
766 case VIDIOC_S_EXT_CTRLS
:
767 ret
= v4l2_prio_check(&cx
->prio
, &id
->prio
);
773 case VIDIOC_DBG_G_REGISTER
:
774 case VIDIOC_DBG_S_REGISTER
:
775 case VIDIOC_G_CHIP_IDENT
:
776 case VIDIOC_INT_S_AUDIO_ROUTING
:
777 case VIDIOC_INT_RESET
:
778 if (cx18_debug
& CX18_DBGFLG_IOCTL
) {
779 printk(KERN_INFO
"cx18%d ioctl: ", cx
->num
);
780 v4l_printk_ioctl(cmd
);
782 return cx18_debug_ioctls(filp
, cmd
, arg
);
784 case VIDIOC_G_PRIORITY
:
785 case VIDIOC_S_PRIORITY
:
786 case VIDIOC_QUERYCAP
:
787 case VIDIOC_ENUMINPUT
:
793 case VIDIOC_ENUM_FMT
:
797 case VIDIOC_G_FREQUENCY
:
798 case VIDIOC_S_FREQUENCY
:
804 case VIDIOC_ENUMAUDIO
:
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
);
816 return cx18_v4l2_ioctls(cx
, filp
, cmd
, arg
);
818 case VIDIOC_QUERYMENU
:
819 case VIDIOC_QUERYCTRL
:
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
) {
826 printk(KERN_INFO
"cx18%d ioctl: ", cx
->num
);
827 v4l_printk_ioctl(cmd
);
829 return cx18_control_ioctls(cx
, cmd
, arg
);
831 case 0x00005401: /* Handle isatty() calls */
834 return v4l_compat_translate_ioctl(inode
, filp
, cmd
, arg
,
840 int cx18_v4l2_ioctl(struct inode
*inode
, struct file
*filp
, unsigned int cmd
,
843 struct cx18_open_id
*id
= (struct cx18_open_id
*)filp
->private_data
;
844 struct cx18
*cx
= id
->cx
;
847 mutex_lock(&cx
->serialize_lock
);
848 res
= video_usercopy(inode
, filp
, cmd
, arg
, cx18_v4l2_do_ioctl
);
849 mutex_unlock(&cx
->serialize_lock
);