[PATCH] lockdep: fix delayacct locking bug
[linux-2.6/verdex.git] / drivers / media / video / cx2341x.c
blob657e0b9691459c532803fec0b8a2d9cfc1a76494
1 /*
2 * cx2341x - generic code for cx23415/6 based devices
4 * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <linux/module.h>
23 #include <linux/moduleparam.h>
24 #include <linux/errno.h>
25 #include <linux/kernel.h>
26 #include <linux/init.h>
27 #include <linux/types.h>
28 #include <linux/videodev2.h>
29 #include <linux/i2c.h>
31 #include <media/tuner.h>
32 #include <media/cx2341x.h>
33 #include <media/v4l2-common.h>
35 MODULE_DESCRIPTION("cx23415/6 driver");
36 MODULE_AUTHOR("Hans Verkuil");
37 MODULE_LICENSE("GPL");
39 static int debug = 0;
40 module_param(debug, int, 0644);
41 MODULE_PARM_DESC(debug, "Debug level (0-1)");
43 const u32 cx2341x_mpeg_ctrls[] = {
44 V4L2_CID_MPEG_CLASS,
45 V4L2_CID_MPEG_STREAM_TYPE,
46 V4L2_CID_MPEG_STREAM_VBI_FMT,
47 V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
48 V4L2_CID_MPEG_AUDIO_ENCODING,
49 V4L2_CID_MPEG_AUDIO_L2_BITRATE,
50 V4L2_CID_MPEG_AUDIO_MODE,
51 V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
52 V4L2_CID_MPEG_AUDIO_EMPHASIS,
53 V4L2_CID_MPEG_AUDIO_CRC,
54 V4L2_CID_MPEG_VIDEO_ENCODING,
55 V4L2_CID_MPEG_VIDEO_ASPECT,
56 V4L2_CID_MPEG_VIDEO_B_FRAMES,
57 V4L2_CID_MPEG_VIDEO_GOP_SIZE,
58 V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
59 V4L2_CID_MPEG_VIDEO_PULLDOWN,
60 V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
61 V4L2_CID_MPEG_VIDEO_BITRATE,
62 V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
63 V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
64 V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
65 V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
66 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
67 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
68 V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
69 V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
70 V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
71 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
72 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
73 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
74 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
79 /* Map the control ID to the correct field in the cx2341x_mpeg_params
80 struct. Return -EINVAL if the ID is unknown, else return 0. */
81 static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
82 struct v4l2_ext_control *ctrl)
84 switch (ctrl->id) {
85 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
86 ctrl->value = params->audio_sampling_freq;
87 break;
88 case V4L2_CID_MPEG_AUDIO_ENCODING:
89 ctrl->value = params->audio_encoding;
90 break;
91 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
92 ctrl->value = params->audio_l2_bitrate;
93 break;
94 case V4L2_CID_MPEG_AUDIO_MODE:
95 ctrl->value = params->audio_mode;
96 break;
97 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
98 ctrl->value = params->audio_mode_extension;
99 break;
100 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
101 ctrl->value = params->audio_emphasis;
102 break;
103 case V4L2_CID_MPEG_AUDIO_CRC:
104 ctrl->value = params->audio_crc;
105 break;
106 case V4L2_CID_MPEG_VIDEO_ENCODING:
107 ctrl->value = params->video_encoding;
108 break;
109 case V4L2_CID_MPEG_VIDEO_ASPECT:
110 ctrl->value = params->video_aspect;
111 break;
112 case V4L2_CID_MPEG_VIDEO_B_FRAMES:
113 ctrl->value = params->video_b_frames;
114 break;
115 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
116 ctrl->value = params->video_gop_size;
117 break;
118 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
119 ctrl->value = params->video_gop_closure;
120 break;
121 case V4L2_CID_MPEG_VIDEO_PULLDOWN:
122 ctrl->value = params->video_pulldown;
123 break;
124 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
125 ctrl->value = params->video_bitrate_mode;
126 break;
127 case V4L2_CID_MPEG_VIDEO_BITRATE:
128 ctrl->value = params->video_bitrate;
129 break;
130 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
131 ctrl->value = params->video_bitrate_peak;
132 break;
133 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
134 ctrl->value = params->video_temporal_decimation;
135 break;
136 case V4L2_CID_MPEG_STREAM_TYPE:
137 ctrl->value = params->stream_type;
138 break;
139 case V4L2_CID_MPEG_STREAM_VBI_FMT:
140 ctrl->value = params->stream_vbi_fmt;
141 break;
142 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
143 ctrl->value = params->video_spatial_filter_mode;
144 break;
145 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
146 ctrl->value = params->video_spatial_filter;
147 break;
148 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
149 ctrl->value = params->video_luma_spatial_filter_type;
150 break;
151 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
152 ctrl->value = params->video_chroma_spatial_filter_type;
153 break;
154 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
155 ctrl->value = params->video_temporal_filter_mode;
156 break;
157 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
158 ctrl->value = params->video_temporal_filter;
159 break;
160 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
161 ctrl->value = params->video_median_filter_type;
162 break;
163 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
164 ctrl->value = params->video_luma_median_filter_top;
165 break;
166 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
167 ctrl->value = params->video_luma_median_filter_bottom;
168 break;
169 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
170 ctrl->value = params->video_chroma_median_filter_top;
171 break;
172 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
173 ctrl->value = params->video_chroma_median_filter_bottom;
174 break;
175 default:
176 return -EINVAL;
178 return 0;
181 /* Map the control ID to the correct field in the cx2341x_mpeg_params
182 struct. Return -EINVAL if the ID is unknown, else return 0. */
183 static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
184 struct v4l2_ext_control *ctrl)
186 switch (ctrl->id) {
187 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
188 params->audio_sampling_freq = ctrl->value;
189 break;
190 case V4L2_CID_MPEG_AUDIO_ENCODING:
191 params->audio_encoding = ctrl->value;
192 break;
193 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
194 params->audio_l2_bitrate = ctrl->value;
195 break;
196 case V4L2_CID_MPEG_AUDIO_MODE:
197 params->audio_mode = ctrl->value;
198 break;
199 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
200 params->audio_mode_extension = ctrl->value;
201 break;
202 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
203 params->audio_emphasis = ctrl->value;
204 break;
205 case V4L2_CID_MPEG_AUDIO_CRC:
206 params->audio_crc = ctrl->value;
207 break;
208 case V4L2_CID_MPEG_VIDEO_ASPECT:
209 params->video_aspect = ctrl->value;
210 break;
211 case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
212 int b = ctrl->value + 1;
213 int gop = params->video_gop_size;
214 params->video_b_frames = ctrl->value;
215 params->video_gop_size = b * ((gop + b - 1) / b);
216 /* Max GOP size = 34 */
217 while (params->video_gop_size > 34)
218 params->video_gop_size -= b;
219 break;
221 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
222 int b = params->video_b_frames + 1;
223 int gop = ctrl->value;
224 params->video_gop_size = b * ((gop + b - 1) / b);
225 /* Max GOP size = 34 */
226 while (params->video_gop_size > 34)
227 params->video_gop_size -= b;
228 ctrl->value = params->video_gop_size;
229 break;
231 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
232 params->video_gop_closure = ctrl->value;
233 break;
234 case V4L2_CID_MPEG_VIDEO_PULLDOWN:
235 params->video_pulldown = ctrl->value;
236 break;
237 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
238 /* MPEG-1 only allows CBR */
239 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
240 ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
241 return -EINVAL;
242 params->video_bitrate_mode = ctrl->value;
243 break;
244 case V4L2_CID_MPEG_VIDEO_BITRATE:
245 params->video_bitrate = ctrl->value;
246 break;
247 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
248 params->video_bitrate_peak = ctrl->value;
249 break;
250 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
251 params->video_temporal_decimation = ctrl->value;
252 break;
253 case V4L2_CID_MPEG_STREAM_TYPE:
254 params->stream_type = ctrl->value;
255 params->video_encoding =
256 (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
257 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
258 V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
259 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
260 /* MPEG-1 implies CBR */
261 params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
263 break;
264 case V4L2_CID_MPEG_STREAM_VBI_FMT:
265 params->stream_vbi_fmt = ctrl->value;
266 break;
267 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
268 params->video_spatial_filter_mode = ctrl->value;
269 break;
270 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
271 params->video_spatial_filter = ctrl->value;
272 break;
273 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
274 params->video_luma_spatial_filter_type = ctrl->value;
275 break;
276 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
277 params->video_chroma_spatial_filter_type = ctrl->value;
278 break;
279 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
280 params->video_temporal_filter_mode = ctrl->value;
281 break;
282 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
283 params->video_temporal_filter = ctrl->value;
284 break;
285 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
286 params->video_median_filter_type = ctrl->value;
287 break;
288 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
289 params->video_luma_median_filter_top = ctrl->value;
290 break;
291 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
292 params->video_luma_median_filter_bottom = ctrl->value;
293 break;
294 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
295 params->video_chroma_median_filter_top = ctrl->value;
296 break;
297 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
298 params->video_chroma_median_filter_bottom = ctrl->value;
299 break;
300 default:
301 return -EINVAL;
303 return 0;
306 static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
308 const char *name;
310 qctrl->flags = 0;
311 switch (qctrl->id) {
312 /* MPEG controls */
313 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
314 name = "Spatial Filter Mode";
315 break;
316 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
317 name = "Spatial Filter";
318 break;
319 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
320 name = "Spatial Luma Filter Type";
321 break;
322 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
323 name = "Spatial Chroma Filter Type";
324 break;
325 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
326 name = "Temporal Filter Mode";
327 break;
328 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
329 name = "Temporal Filter";
330 break;
331 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
332 name = "Median Filter Type";
333 break;
334 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
335 name = "Median Luma Filter Maximum";
336 break;
337 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
338 name = "Median Luma Filter Minimum";
339 break;
340 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
341 name = "Median Chroma Filter Maximum";
342 break;
343 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
344 name = "Median Chroma Filter Minimum";
345 break;
347 default:
348 return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
350 switch (qctrl->id) {
351 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
352 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
353 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
354 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
355 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
356 qctrl->type = V4L2_CTRL_TYPE_MENU;
357 min = 0;
358 step = 1;
359 break;
360 default:
361 qctrl->type = V4L2_CTRL_TYPE_INTEGER;
362 break;
364 switch (qctrl->id) {
365 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
366 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
367 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
368 qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
369 break;
371 qctrl->minimum = min;
372 qctrl->maximum = max;
373 qctrl->step = step;
374 qctrl->default_value = def;
375 qctrl->reserved[0] = qctrl->reserved[1] = 0;
376 snprintf(qctrl->name, sizeof(qctrl->name), name);
377 return 0;
380 int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
382 int err;
384 switch (qctrl->id) {
385 case V4L2_CID_MPEG_AUDIO_ENCODING:
386 return v4l2_ctrl_query_fill(qctrl,
387 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
388 V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
389 V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
391 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
392 return v4l2_ctrl_query_fill(qctrl,
393 V4L2_MPEG_AUDIO_L2_BITRATE_192K,
394 V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
395 V4L2_MPEG_AUDIO_L2_BITRATE_224K);
397 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
398 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
399 return -EINVAL;
401 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
402 err = v4l2_ctrl_query_fill_std(qctrl);
403 if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
404 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
405 return err;
407 case V4L2_CID_MPEG_VIDEO_ENCODING:
408 /* this setting is read-only for the cx2341x since the
409 V4L2_CID_MPEG_STREAM_TYPE really determines the
410 MPEG-1/2 setting */
411 err = v4l2_ctrl_query_fill_std(qctrl);
412 if (err == 0)
413 qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
414 return err;
416 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
417 err = v4l2_ctrl_query_fill_std(qctrl);
418 if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
419 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
420 return err;
422 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
423 err = v4l2_ctrl_query_fill_std(qctrl);
424 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
425 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
426 return err;
428 case V4L2_CID_MPEG_STREAM_VBI_FMT:
429 if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
430 return v4l2_ctrl_query_fill_std(qctrl);
431 return cx2341x_ctrl_query_fill(qctrl,
432 V4L2_MPEG_STREAM_VBI_FMT_NONE,
433 V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
434 V4L2_MPEG_STREAM_VBI_FMT_NONE);
436 /* CX23415/6 specific */
437 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
438 return cx2341x_ctrl_query_fill(qctrl,
439 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
440 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
441 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
443 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
444 cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
445 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
446 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
447 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
448 return 0;
450 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
451 cx2341x_ctrl_query_fill(qctrl,
452 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
453 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
454 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
455 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
456 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
457 return 0;
459 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
460 cx2341x_ctrl_query_fill(qctrl,
461 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
462 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
463 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
464 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
465 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
466 return 0;
468 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
469 return cx2341x_ctrl_query_fill(qctrl,
470 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
471 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
472 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
474 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
475 cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
476 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
477 if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
478 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
479 return 0;
481 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
482 return cx2341x_ctrl_query_fill(qctrl,
483 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
484 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
485 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
487 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
488 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
489 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
490 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
491 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
492 return 0;
494 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
495 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
496 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
497 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
498 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
499 return 0;
501 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
502 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
503 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
504 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
505 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
506 return 0;
508 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
509 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
510 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
511 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
512 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
513 return 0;
515 default:
516 return v4l2_ctrl_query_fill_std(qctrl);
521 const char **cx2341x_ctrl_get_menu(u32 id)
523 static const char *mpeg_stream_type[] = {
524 "MPEG-2 Program Stream",
526 "MPEG-1 System Stream",
527 "MPEG-2 DVD-compatible Stream",
528 "MPEG-1 VCD-compatible Stream",
529 "MPEG-2 SVCD-compatible Stream",
530 NULL
533 static const char *cx2341x_video_spatial_filter_mode_menu[] = {
534 "Manual",
535 "Auto",
536 NULL
539 static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
540 "Off",
541 "1D Horizontal",
542 "1D Vertical",
543 "2D H/V Separable",
544 "2D Symmetric non-separable",
545 NULL
548 static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
549 "Off",
550 "1D Horizontal",
551 NULL
554 static const char *cx2341x_video_temporal_filter_mode_menu[] = {
555 "Manual",
556 "Auto",
557 NULL
560 static const char *cx2341x_video_median_filter_type_menu[] = {
561 "Off",
562 "Horizontal",
563 "Vertical",
564 "Horizontal/Vertical",
565 "Diagonal",
566 NULL
569 switch (id) {
570 case V4L2_CID_MPEG_STREAM_TYPE:
571 return mpeg_stream_type;
572 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
573 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
574 return NULL;
575 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
576 return cx2341x_video_spatial_filter_mode_menu;
577 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
578 return cx2341x_video_luma_spatial_filter_type_menu;
579 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
580 return cx2341x_video_chroma_spatial_filter_type_menu;
581 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
582 return cx2341x_video_temporal_filter_mode_menu;
583 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
584 return cx2341x_video_median_filter_type_menu;
585 default:
586 return v4l2_ctrl_get_menu(id);
590 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
592 params->audio_properties = (params->audio_sampling_freq << 0) |
593 ((3 - params->audio_encoding) << 2) |
594 ((1 + params->audio_l2_bitrate) << 4) |
595 (params->audio_mode << 8) |
596 (params->audio_mode_extension << 10) |
597 (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
599 params->audio_emphasis) << 12) |
600 (params->audio_crc << 14);
603 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
604 struct v4l2_ext_controls *ctrls, unsigned int cmd)
606 int err = 0;
607 int i;
609 if (cmd == VIDIOC_G_EXT_CTRLS) {
610 for (i = 0; i < ctrls->count; i++) {
611 struct v4l2_ext_control *ctrl = ctrls->controls + i;
613 err = cx2341x_get_ctrl(params, ctrl);
614 if (err) {
615 ctrls->error_idx = i;
616 break;
619 return err;
621 for (i = 0; i < ctrls->count; i++) {
622 struct v4l2_ext_control *ctrl = ctrls->controls + i;
623 struct v4l2_queryctrl qctrl;
624 const char **menu_items = NULL;
626 qctrl.id = ctrl->id;
627 err = cx2341x_ctrl_query(params, &qctrl);
628 if (err)
629 break;
630 if (qctrl.type == V4L2_CTRL_TYPE_MENU)
631 menu_items = cx2341x_ctrl_get_menu(qctrl.id);
632 err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
633 if (err)
634 break;
635 err = cx2341x_set_ctrl(params, ctrl);
636 if (err)
637 break;
639 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
640 params->video_bitrate_peak < params->video_bitrate) {
641 err = -ERANGE;
642 ctrls->error_idx = ctrls->count;
644 if (err) {
645 ctrls->error_idx = i;
647 else {
648 cx2341x_calc_audio_properties(params);
650 return err;
653 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
655 static struct cx2341x_mpeg_params default_params = {
656 /* misc */
657 .capabilities = 0,
658 .port = CX2341X_PORT_MEMORY,
659 .width = 720,
660 .height = 480,
661 .is_50hz = 0,
663 /* stream */
664 .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
665 .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
667 /* audio */
668 .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
669 .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
670 .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
671 .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
672 .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
673 .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
674 .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
676 /* video */
677 .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
678 .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
679 .video_b_frames = 2,
680 .video_gop_size = 12,
681 .video_gop_closure = 1,
682 .video_pulldown = 0,
683 .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
684 .video_bitrate = 6000000,
685 .video_bitrate_peak = 8000000,
686 .video_temporal_decimation = 0,
688 /* encoding filters */
689 .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
690 .video_spatial_filter = 0,
691 .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
692 .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
693 .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
694 .video_temporal_filter = 8,
695 .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
696 .video_luma_median_filter_top = 255,
697 .video_luma_median_filter_bottom = 0,
698 .video_chroma_median_filter_top = 255,
699 .video_chroma_median_filter_bottom = 0,
702 *p = default_params;
703 cx2341x_calc_audio_properties(p);
706 static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
708 u32 data[CX2341X_MBOX_MAX_DATA];
709 va_list vargs;
710 int i;
712 va_start(vargs, args);
714 for (i = 0; i < args; i++) {
715 data[i] = va_arg(vargs, int);
717 va_end(vargs);
718 return func(priv, cmd, args, 0, data);
721 int cx2341x_update(void *priv, cx2341x_mbox_func func,
722 const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
724 static int mpeg_stream_type[] = {
725 0, /* MPEG-2 PS */
726 1, /* MPEG-2 TS */
727 2, /* MPEG-1 SS */
728 14, /* DVD */
729 11, /* VCD */
730 12, /* SVCD */
733 int err = 0;
734 u16 temporal = new->video_temporal_filter;
736 cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
738 if (old == NULL || old->is_50hz != new->is_50hz) {
739 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
740 if (err) return err;
743 if (old == NULL || old->width != new->width || old->height != new->height ||
744 old->video_encoding != new->video_encoding) {
745 int is_scaling;
746 u16 w = new->width;
747 u16 h = new->height;
749 if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
750 w /= 2;
751 h /= 2;
753 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
754 if (err) return err;
756 /* Adjust temporal filter if necessary. The problem with the temporal
757 filter is that it works well with full resolution capturing, but
758 not when the capture window is scaled (the filter introduces
759 a ghosting effect). So if the capture window changed, and there is
760 no updated filter value, then the filter is set depending on whether
761 the new window is full resolution or not.
763 For full resolution a setting of 8 really improves the video
764 quality, especially if the original video quality is suboptimal. */
765 is_scaling = new->width != 720 || new->height != (new->is_50hz ? 576 : 480);
766 if (old && old->video_temporal_filter == temporal) {
767 temporal = is_scaling ? 0 : 8;
771 if (old == NULL || old->stream_type != new->stream_type) {
772 err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
773 if (err) return err;
775 if (old == NULL || old->video_aspect != new->video_aspect) {
776 err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
777 if (err) return err;
779 if (old == NULL || old->video_b_frames != new->video_b_frames ||
780 old->video_gop_size != new->video_gop_size) {
781 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
782 new->video_gop_size, new->video_b_frames + 1);
783 if (err) return err;
785 if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
786 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
787 if (err) return err;
789 if (old == NULL || old->video_pulldown != new->video_pulldown) {
790 err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
791 if (err) return err;
793 if (old == NULL || old->audio_properties != new->audio_properties) {
794 err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
795 if (err) return err;
797 if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
798 old->video_bitrate != new->video_bitrate ||
799 old->video_bitrate_peak != new->video_bitrate_peak) {
800 err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
801 new->video_bitrate_mode, new->video_bitrate,
802 new->video_bitrate_peak / 400, 0, 0);
803 if (err) return err;
805 if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
806 old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
807 old->video_median_filter_type != new->video_median_filter_type) {
808 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
809 new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
810 new->video_median_filter_type);
811 if (err) return err;
813 if (old == NULL ||
814 old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
815 old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
816 old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
817 old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
818 err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
819 new->video_luma_median_filter_bottom,
820 new->video_luma_median_filter_top,
821 new->video_chroma_median_filter_bottom,
822 new->video_chroma_median_filter_top);
823 if (err) return err;
825 if (old == NULL ||
826 old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
827 old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
828 err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
829 new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
830 if (err) return err;
832 if (old == NULL ||
833 old->video_spatial_filter != new->video_spatial_filter ||
834 old->video_temporal_filter != temporal) {
835 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
836 new->video_spatial_filter, temporal);
837 if (err) return err;
839 if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
840 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
841 new->video_temporal_decimation);
842 if (err) return err;
844 return 0;
847 static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
849 const char **menu = cx2341x_ctrl_get_menu(id);
850 struct v4l2_ext_control ctrl;
852 if (menu == NULL)
853 goto invalid;
854 ctrl.id = id;
855 if (cx2341x_get_ctrl(p, &ctrl))
856 goto invalid;
857 while (ctrl.value-- && *menu) menu++;
858 if (*menu == NULL)
859 goto invalid;
860 return *menu;
862 invalid:
863 return "<invalid>";
866 void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
868 int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
870 /* Stream */
871 printk(KERN_INFO "%s: Stream: %s\n",
872 prefix,
873 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
874 printk(KERN_INFO "%s: VBI Format: %s\n",
875 prefix,
876 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
878 /* Video */
879 printk(KERN_INFO "%s: Video: %dx%d, %d fps\n",
880 prefix,
881 p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
882 p->is_50hz ? 25 : 30);
883 printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
884 prefix,
885 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
886 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
887 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
888 p->video_bitrate);
889 if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
890 printk(", Peak %d", p->video_bitrate_peak);
892 printk("\n");
893 printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
894 prefix,
895 p->video_gop_size, p->video_b_frames,
896 p->video_gop_closure ? "" : "No ",
897 p->video_pulldown ? "" : "No ");
898 if (p->video_temporal_decimation) {
899 printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
900 prefix, p->video_temporal_decimation);
903 /* Audio */
904 printk(KERN_INFO "%s: Audio: %s, %s, %s, %s",
905 prefix,
906 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
907 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
908 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
909 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
910 if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
911 printk(", %s",
912 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
914 printk(", %s, %s\n",
915 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
916 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
918 /* Encoding filters */
919 printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
920 prefix,
921 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
922 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
923 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
924 p->video_spatial_filter);
925 printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
926 prefix,
927 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
928 p->video_temporal_filter);
929 printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
930 prefix,
931 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
932 p->video_luma_median_filter_bottom,
933 p->video_luma_median_filter_top,
934 p->video_chroma_median_filter_bottom,
935 p->video_chroma_median_filter_top);
938 EXPORT_SYMBOL(cx2341x_fill_defaults);
939 EXPORT_SYMBOL(cx2341x_ctrl_query);
940 EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
941 EXPORT_SYMBOL(cx2341x_ext_ctrls);
942 EXPORT_SYMBOL(cx2341x_update);
943 EXPORT_SYMBOL(cx2341x_log_status);
944 EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
947 * Local variables:
948 * c-basic-offset: 8
949 * End: