diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2007-04-27 11:31:25 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2007-04-27 14:43:50 -0400 |
commit | 1a0adaf37c30e89e44d1470ef604a930999a5826 (patch) | |
tree | 6e6d6e823f44abdb2ed3847e00406a75bc968cef /drivers/media/video/ivtv/ivtv-controls.c | |
parent | ac52ea3c3c04403d10acf0253180ec6f51977142 (diff) |
V4L/DVB (5345): ivtv driver for Conexant cx23416/cx23415 MPEG encoder/decoder
It took three core maintainers, over four years of work, eight new i2c
modules, eleven new V4L2 ioctls, three new DVB video ioctls, a Sliced
VBI API, a new MPEG encoder API, an enhanced DVB video MPEG decoding
API, major YUV/OSD contributions from Ian and John, web/wiki/svn/trac
support from Axel Thimm, (hardware) support from Hauppauge, support and
assistance from the v4l-dvb people and the many, many users of ivtv to
finally make it possible to merge this driver into the kernel.
Thank you all!
Signed-off-by: Kevin Thayer <nufan_wfk@yahoo.com>
Signed-off-by: Chris Kennedy <c@groovy.org>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: John P Harvey <john.p.harvey@btinternet.com>
Signed-off-by: Ian Armstrong <ian@iarmst.demon.co.uk>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/ivtv/ivtv-controls.c')
-rw-r--r-- | drivers/media/video/ivtv/ivtv-controls.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c new file mode 100644 index 000000000000..7a876c3e5b19 --- /dev/null +++ b/drivers/media/video/ivtv/ivtv-controls.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | ioctl control functions | ||
3 | Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> | ||
4 | Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include "ivtv-driver.h" | ||
22 | #include "ivtv-cards.h" | ||
23 | #include "ivtv-ioctl.h" | ||
24 | #include "ivtv-audio.h" | ||
25 | #include "ivtv-i2c.h" | ||
26 | #include "ivtv-mailbox.h" | ||
27 | #include "ivtv-controls.h" | ||
28 | |||
29 | static const u32 user_ctrls[] = { | ||
30 | V4L2_CID_USER_CLASS, | ||
31 | V4L2_CID_BRIGHTNESS, | ||
32 | V4L2_CID_CONTRAST, | ||
33 | V4L2_CID_SATURATION, | ||
34 | V4L2_CID_HUE, | ||
35 | V4L2_CID_AUDIO_VOLUME, | ||
36 | V4L2_CID_AUDIO_BALANCE, | ||
37 | V4L2_CID_AUDIO_BASS, | ||
38 | V4L2_CID_AUDIO_TREBLE, | ||
39 | V4L2_CID_AUDIO_MUTE, | ||
40 | V4L2_CID_AUDIO_LOUDNESS, | ||
41 | 0 | ||
42 | }; | ||
43 | |||
44 | static const u32 *ctrl_classes[] = { | ||
45 | user_ctrls, | ||
46 | cx2341x_mpeg_ctrls, | ||
47 | NULL | ||
48 | }; | ||
49 | |||
50 | static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl) | ||
51 | { | ||
52 | const char *name; | ||
53 | |||
54 | IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); | ||
55 | |||
56 | qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); | ||
57 | if (qctrl->id == 0) | ||
58 | return -EINVAL; | ||
59 | |||
60 | switch (qctrl->id) { | ||
61 | /* Standard V4L2 controls */ | ||
62 | case V4L2_CID_BRIGHTNESS: | ||
63 | case V4L2_CID_HUE: | ||
64 | case V4L2_CID_SATURATION: | ||
65 | case V4L2_CID_CONTRAST: | ||
66 | if (itv->video_dec_func(itv, VIDIOC_QUERYCTRL, qctrl)) | ||
67 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
68 | return 0; | ||
69 | |||
70 | case V4L2_CID_AUDIO_VOLUME: | ||
71 | case V4L2_CID_AUDIO_MUTE: | ||
72 | case V4L2_CID_AUDIO_BALANCE: | ||
73 | case V4L2_CID_AUDIO_BASS: | ||
74 | case V4L2_CID_AUDIO_TREBLE: | ||
75 | case V4L2_CID_AUDIO_LOUDNESS: | ||
76 | if (ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) | ||
77 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
78 | return 0; | ||
79 | |||
80 | default: | ||
81 | if (cx2341x_ctrl_query(&itv->params, qctrl)) | ||
82 | qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; | ||
83 | return 0; | ||
84 | } | ||
85 | strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); | ||
86 | qctrl->name[sizeof(qctrl->name) - 1] = 0; | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu) | ||
91 | { | ||
92 | struct v4l2_queryctrl qctrl; | ||
93 | |||
94 | qctrl.id = qmenu->id; | ||
95 | ivtv_queryctrl(itv, &qctrl); | ||
96 | return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); | ||
97 | } | ||
98 | |||
99 | static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) | ||
100 | { | ||
101 | s32 v = vctrl->value; | ||
102 | |||
103 | IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); | ||
104 | |||
105 | switch (vctrl->id) { | ||
106 | /* Standard V4L2 controls */ | ||
107 | case V4L2_CID_BRIGHTNESS: | ||
108 | case V4L2_CID_HUE: | ||
109 | case V4L2_CID_SATURATION: | ||
110 | case V4L2_CID_CONTRAST: | ||
111 | return itv->video_dec_func(itv, VIDIOC_S_CTRL, vctrl); | ||
112 | |||
113 | case V4L2_CID_AUDIO_VOLUME: | ||
114 | case V4L2_CID_AUDIO_MUTE: | ||
115 | case V4L2_CID_AUDIO_BALANCE: | ||
116 | case V4L2_CID_AUDIO_BASS: | ||
117 | case V4L2_CID_AUDIO_TREBLE: | ||
118 | case V4L2_CID_AUDIO_LOUDNESS: | ||
119 | return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); | ||
120 | |||
121 | default: | ||
122 | IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl) | ||
129 | { | ||
130 | IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); | ||
131 | |||
132 | switch (vctrl->id) { | ||
133 | /* Standard V4L2 controls */ | ||
134 | case V4L2_CID_BRIGHTNESS: | ||
135 | case V4L2_CID_HUE: | ||
136 | case V4L2_CID_SATURATION: | ||
137 | case V4L2_CID_CONTRAST: | ||
138 | return itv->video_dec_func(itv, VIDIOC_G_CTRL, vctrl); | ||
139 | |||
140 | case V4L2_CID_AUDIO_VOLUME: | ||
141 | case V4L2_CID_AUDIO_MUTE: | ||
142 | case V4L2_CID_AUDIO_BALANCE: | ||
143 | case V4L2_CID_AUDIO_BASS: | ||
144 | case V4L2_CID_AUDIO_TREBLE: | ||
145 | case V4L2_CID_AUDIO_LOUDNESS: | ||
146 | return ivtv_i2c_hw(itv, itv->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); | ||
147 | default: | ||
148 | IVTV_DEBUG_IOCTL("invalid control %x\n", vctrl->id); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt) | ||
155 | { | ||
156 | if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) | ||
157 | return -EINVAL; | ||
158 | if (atomic_read(&itv->capturing) > 0) | ||
159 | return -EBUSY; | ||
160 | |||
161 | /* First try to allocate sliced VBI buffers if needed. */ | ||
162 | if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) { | ||
163 | int i; | ||
164 | |||
165 | for (i = 0; i < IVTV_VBI_FRAMES; i++) { | ||
166 | /* Yuck, hardcoded. Needs to be a define */ | ||
167 | itv->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); | ||
168 | if (itv->vbi.sliced_mpeg_data[i] == NULL) { | ||
169 | while (--i >= 0) { | ||
170 | kfree(itv->vbi.sliced_mpeg_data[i]); | ||
171 | itv->vbi.sliced_mpeg_data[i] = NULL; | ||
172 | } | ||
173 | return -ENOMEM; | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | itv->vbi.insert_mpeg = fmt; | ||
179 | |||
180 | if (itv->vbi.insert_mpeg == 0) { | ||
181 | return 0; | ||
182 | } | ||
183 | /* Need sliced data for mpeg insertion */ | ||
184 | if (get_service_set(itv->vbi.sliced_in) == 0) { | ||
185 | if (itv->is_60hz) | ||
186 | itv->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; | ||
187 | else | ||
188 | itv->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; | ||
189 | expand_service_set(itv->vbi.sliced_in, itv->is_50hz); | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg) | ||
195 | { | ||
196 | struct v4l2_control ctrl; | ||
197 | |||
198 | switch (cmd) { | ||
199 | case VIDIOC_QUERYMENU: | ||
200 | IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); | ||
201 | return ivtv_querymenu(itv, arg); | ||
202 | |||
203 | case VIDIOC_QUERYCTRL: | ||
204 | return ivtv_queryctrl(itv, arg); | ||
205 | |||
206 | case VIDIOC_S_CTRL: | ||
207 | return ivtv_s_ctrl(itv, arg); | ||
208 | |||
209 | case VIDIOC_G_CTRL: | ||
210 | return ivtv_g_ctrl(itv, arg); | ||
211 | |||
212 | case VIDIOC_S_EXT_CTRLS: | ||
213 | { | ||
214 | struct v4l2_ext_controls *c = arg; | ||
215 | |||
216 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
217 | int i; | ||
218 | int err = 0; | ||
219 | |||
220 | for (i = 0; i < c->count; i++) { | ||
221 | ctrl.id = c->controls[i].id; | ||
222 | ctrl.value = c->controls[i].value; | ||
223 | err = ivtv_s_ctrl(itv, &ctrl); | ||
224 | c->controls[i].value = ctrl.value; | ||
225 | if (err) { | ||
226 | c->error_idx = i; | ||
227 | break; | ||
228 | } | ||
229 | } | ||
230 | return err; | ||
231 | } | ||
232 | IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); | ||
233 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { | ||
234 | struct cx2341x_mpeg_params p = itv->params; | ||
235 | int err = cx2341x_ext_ctrls(&p, arg, cmd); | ||
236 | |||
237 | if (err) | ||
238 | return err; | ||
239 | |||
240 | if (p.video_encoding != itv->params.video_encoding) { | ||
241 | int is_mpeg1 = p.video_encoding == | ||
242 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | ||
243 | struct v4l2_format fmt; | ||
244 | |||
245 | /* fix videodecoder resolution */ | ||
246 | fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
247 | fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1); | ||
248 | fmt.fmt.pix.height = itv->params.height; | ||
249 | itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt); | ||
250 | } | ||
251 | err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p); | ||
252 | if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) { | ||
253 | err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt); | ||
254 | } | ||
255 | itv->params = p; | ||
256 | itv->dualwatch_stereo_mode = p.audio_properties & 0x0300; | ||
257 | ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03); | ||
258 | return err; | ||
259 | } | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | case VIDIOC_G_EXT_CTRLS: | ||
264 | { | ||
265 | struct v4l2_ext_controls *c = arg; | ||
266 | |||
267 | if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { | ||
268 | int i; | ||
269 | int err = 0; | ||
270 | |||
271 | for (i = 0; i < c->count; i++) { | ||
272 | ctrl.id = c->controls[i].id; | ||
273 | ctrl.value = c->controls[i].value; | ||
274 | err = ivtv_g_ctrl(itv, &ctrl); | ||
275 | c->controls[i].value = ctrl.value; | ||
276 | if (err) { | ||
277 | c->error_idx = i; | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | return err; | ||
282 | } | ||
283 | IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); | ||
284 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
285 | return cx2341x_ext_ctrls(&itv->params, arg, cmd); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | case VIDIOC_TRY_EXT_CTRLS: | ||
290 | { | ||
291 | struct v4l2_ext_controls *c = arg; | ||
292 | |||
293 | IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); | ||
294 | if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) | ||
295 | return cx2341x_ext_ctrls(&itv->params, arg, cmd); | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | default: | ||
300 | return -EINVAL; | ||
301 | } | ||
302 | return 0; | ||
303 | } | ||