2 * cx18 ioctl control functions
4 * Derived from ivtv-controls.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-av-core.h"
26 #include "cx18-cards.h"
27 #include "cx18-ioctl.h"
28 #include "cx18-audio.h"
30 #include "cx18-mailbox.h"
31 #include "cx18-controls.h"
33 static const u32 user_ctrls
[] = {
39 V4L2_CID_AUDIO_VOLUME
,
40 V4L2_CID_AUDIO_BALANCE
,
42 V4L2_CID_AUDIO_TREBLE
,
44 V4L2_CID_AUDIO_LOUDNESS
,
48 static const u32
*ctrl_classes
[] = {
54 static int cx18_queryctrl(struct cx18
*cx
, struct v4l2_queryctrl
*qctrl
)
58 CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl
->id
);
60 qctrl
->id
= v4l2_ctrl_next(ctrl_classes
, qctrl
->id
);
65 /* Standard V4L2 controls */
66 case V4L2_CID_BRIGHTNESS
:
68 case V4L2_CID_SATURATION
:
69 case V4L2_CID_CONTRAST
:
70 if (cx18_av_cmd(cx
, VIDIOC_QUERYCTRL
, qctrl
))
71 qctrl
->flags
|= V4L2_CTRL_FLAG_DISABLED
;
74 case V4L2_CID_AUDIO_VOLUME
:
75 case V4L2_CID_AUDIO_MUTE
:
76 case V4L2_CID_AUDIO_BALANCE
:
77 case V4L2_CID_AUDIO_BASS
:
78 case V4L2_CID_AUDIO_TREBLE
:
79 case V4L2_CID_AUDIO_LOUDNESS
:
80 if (cx18_i2c_hw(cx
, cx
->card
->hw_audio_ctrl
, VIDIOC_QUERYCTRL
, qctrl
))
81 qctrl
->flags
|= V4L2_CTRL_FLAG_DISABLED
;
85 if (cx2341x_ctrl_query(&cx
->params
, qctrl
))
86 qctrl
->flags
|= V4L2_CTRL_FLAG_DISABLED
;
89 strncpy(qctrl
->name
, name
, sizeof(qctrl
->name
) - 1);
90 qctrl
->name
[sizeof(qctrl
->name
) - 1] = 0;
94 static int cx18_querymenu(struct cx18
*cx
, struct v4l2_querymenu
*qmenu
)
96 struct v4l2_queryctrl qctrl
;
99 cx18_queryctrl(cx
, &qctrl
);
100 return v4l2_ctrl_query_menu(qmenu
, &qctrl
, cx2341x_ctrl_get_menu(qmenu
->id
));
103 static int cx18_s_ctrl(struct cx18
*cx
, struct v4l2_control
*vctrl
)
105 s32 v
= vctrl
->value
;
107 CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl
->id
, v
);
110 /* Standard V4L2 controls */
111 case V4L2_CID_BRIGHTNESS
:
113 case V4L2_CID_SATURATION
:
114 case V4L2_CID_CONTRAST
:
115 return cx18_av_cmd(cx
, VIDIOC_S_CTRL
, vctrl
);
117 case V4L2_CID_AUDIO_VOLUME
:
118 case V4L2_CID_AUDIO_MUTE
:
119 case V4L2_CID_AUDIO_BALANCE
:
120 case V4L2_CID_AUDIO_BASS
:
121 case V4L2_CID_AUDIO_TREBLE
:
122 case V4L2_CID_AUDIO_LOUDNESS
:
123 return cx18_i2c_hw(cx
, cx
->card
->hw_audio_ctrl
, VIDIOC_S_CTRL
, vctrl
);
126 CX18_DEBUG_IOCTL("invalid control %x\n", vctrl
->id
);
132 static int cx18_g_ctrl(struct cx18
*cx
, struct v4l2_control
*vctrl
)
134 CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl
->id
);
137 /* Standard V4L2 controls */
138 case V4L2_CID_BRIGHTNESS
:
140 case V4L2_CID_SATURATION
:
141 case V4L2_CID_CONTRAST
:
142 return cx18_av_cmd(cx
, VIDIOC_G_CTRL
, vctrl
);
144 case V4L2_CID_AUDIO_VOLUME
:
145 case V4L2_CID_AUDIO_MUTE
:
146 case V4L2_CID_AUDIO_BALANCE
:
147 case V4L2_CID_AUDIO_BASS
:
148 case V4L2_CID_AUDIO_TREBLE
:
149 case V4L2_CID_AUDIO_LOUDNESS
:
150 return cx18_i2c_hw(cx
, cx
->card
->hw_audio_ctrl
, VIDIOC_G_CTRL
, vctrl
);
152 CX18_DEBUG_IOCTL("invalid control %x\n", vctrl
->id
);
158 static int cx18_setup_vbi_fmt(struct cx18
*cx
, enum v4l2_mpeg_stream_vbi_fmt fmt
)
160 if (!(cx
->v4l2_cap
& V4L2_CAP_SLICED_VBI_CAPTURE
))
162 if (atomic_read(&cx
->ana_capturing
) > 0)
165 /* First try to allocate sliced VBI buffers if needed. */
166 if (fmt
&& cx
->vbi
.sliced_mpeg_data
[0] == NULL
) {
169 for (i
= 0; i
< CX18_VBI_FRAMES
; i
++) {
170 /* Yuck, hardcoded. Needs to be a define */
171 cx
->vbi
.sliced_mpeg_data
[i
] = kmalloc(2049, GFP_KERNEL
);
172 if (cx
->vbi
.sliced_mpeg_data
[i
] == NULL
) {
174 kfree(cx
->vbi
.sliced_mpeg_data
[i
]);
175 cx
->vbi
.sliced_mpeg_data
[i
] = NULL
;
182 cx
->vbi
.insert_mpeg
= fmt
;
184 if (cx
->vbi
.insert_mpeg
== 0)
186 /* Need sliced data for mpeg insertion */
187 if (cx18_get_service_set(cx
->vbi
.sliced_in
) == 0) {
189 cx
->vbi
.sliced_in
->service_set
= V4L2_SLICED_CAPTION_525
;
191 cx
->vbi
.sliced_in
->service_set
= V4L2_SLICED_WSS_625
;
192 cx18_expand_service_set(cx
->vbi
.sliced_in
, cx
->is_50hz
);
197 int cx18_control_ioctls(struct cx18
*cx
, unsigned int cmd
, void *arg
)
199 struct v4l2_control ctrl
;
202 case VIDIOC_QUERYMENU
:
203 CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
204 return cx18_querymenu(cx
, arg
);
206 case VIDIOC_QUERYCTRL
:
207 return cx18_queryctrl(cx
, arg
);
210 return cx18_s_ctrl(cx
, arg
);
213 return cx18_g_ctrl(cx
, arg
);
215 case VIDIOC_S_EXT_CTRLS
:
217 struct v4l2_ext_controls
*c
= arg
;
219 if (c
->ctrl_class
== V4L2_CTRL_CLASS_USER
) {
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
;
235 CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
236 if (c
->ctrl_class
== V4L2_CTRL_CLASS_MPEG
) {
237 struct cx2341x_mpeg_params p
= cx
->params
;
238 int err
= cx2341x_ext_ctrls(&p
, atomic_read(&cx
->ana_capturing
), arg
, cmd
);
243 if (p
.video_encoding
!= cx
->params
.video_encoding
) {
244 int is_mpeg1
= p
.video_encoding
==
245 V4L2_MPEG_VIDEO_ENCODING_MPEG_1
;
246 struct v4l2_format fmt
;
248 /* fix videodecoder resolution */
249 fmt
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
250 fmt
.fmt
.pix
.width
= cx
->params
.width
/ (is_mpeg1
? 2 : 1);
251 fmt
.fmt
.pix
.height
= cx
->params
.height
;
252 cx18_av_cmd(cx
, VIDIOC_S_FMT
, &fmt
);
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
);
258 cx
->dualwatch_stereo_mode
= p
.audio_properties
& 0x0300;
259 cx18_audio_set_audio_clock_freq(cx
, p
.audio_properties
& 0x03);
265 case VIDIOC_G_EXT_CTRLS
:
267 struct v4l2_ext_controls
*c
= arg
;
269 if (c
->ctrl_class
== V4L2_CTRL_CLASS_USER
) {
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
;
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
);
291 case VIDIOC_TRY_EXT_CTRLS
:
293 struct v4l2_ext_controls
*c
= arg
;
295 CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
296 if (c
->ctrl_class
== V4L2_CTRL_CLASS_MPEG
)
297 return cx2341x_ext_ctrls(&cx
->params
,
298 atomic_read(&cx
->ana_capturing
), arg
, cmd
);