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");
40 module_param(debug, int, 0644);
41 MODULE_PARM_DESC(debug, "Debug level (0-1)");
43 const u32 cx2341x_mpeg_ctrls[] = {
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)
85 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
86 ctrl->value = params->audio_sampling_freq;
88 case V4L2_CID_MPEG_AUDIO_ENCODING:
89 ctrl->value = params->audio_encoding;
91 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
92 ctrl->value = params->audio_l2_bitrate;
94 case V4L2_CID_MPEG_AUDIO_MODE:
95 ctrl->value = params->audio_mode;
97 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
98 ctrl->value = params->audio_mode_extension;
100 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
101 ctrl->value = params->audio_emphasis;
103 case V4L2_CID_MPEG_AUDIO_CRC:
104 ctrl->value = params->audio_crc;
106 case V4L2_CID_MPEG_VIDEO_ENCODING:
107 ctrl->value = params->video_encoding;
109 case V4L2_CID_MPEG_VIDEO_ASPECT:
110 ctrl->value = params->video_aspect;
112 case V4L2_CID_MPEG_VIDEO_B_FRAMES:
113 ctrl->value = params->video_b_frames;
115 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
116 ctrl->value = params->video_gop_size;
118 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
119 ctrl->value = params->video_gop_closure;
121 case V4L2_CID_MPEG_VIDEO_PULLDOWN:
122 ctrl->value = params->video_pulldown;
124 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
125 ctrl->value = params->video_bitrate_mode;
127 case V4L2_CID_MPEG_VIDEO_BITRATE:
128 ctrl->value = params->video_bitrate;
130 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
131 ctrl->value = params->video_bitrate_peak;
133 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
134 ctrl->value = params->video_temporal_decimation;
136 case V4L2_CID_MPEG_STREAM_TYPE:
137 ctrl->value = params->stream_type;
139 case V4L2_CID_MPEG_STREAM_VBI_FMT:
140 ctrl->value = params->stream_vbi_fmt;
142 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
143 ctrl->value = params->video_spatial_filter_mode;
145 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
146 ctrl->value = params->video_spatial_filter;
148 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
149 ctrl->value = params->video_luma_spatial_filter_type;
151 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
152 ctrl->value = params->video_chroma_spatial_filter_type;
154 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
155 ctrl->value = params->video_temporal_filter_mode;
157 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
158 ctrl->value = params->video_temporal_filter;
160 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
161 ctrl->value = params->video_median_filter_type;
163 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
164 ctrl->value = params->video_luma_median_filter_top;
166 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
167 ctrl->value = params->video_luma_median_filter_bottom;
169 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
170 ctrl->value = params->video_chroma_median_filter_top;
172 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
173 ctrl->value = params->video_chroma_median_filter_bottom;
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)
187 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
188 params->audio_sampling_freq = ctrl->value;
190 case V4L2_CID_MPEG_AUDIO_ENCODING:
191 params->audio_encoding = ctrl->value;
193 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
194 params->audio_l2_bitrate = ctrl->value;
196 case V4L2_CID_MPEG_AUDIO_MODE:
197 params->audio_mode = ctrl->value;
199 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
200 params->audio_mode_extension = ctrl->value;
202 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
203 params->audio_emphasis = ctrl->value;
205 case V4L2_CID_MPEG_AUDIO_CRC:
206 params->audio_crc = ctrl->value;
208 case V4L2_CID_MPEG_VIDEO_ASPECT:
209 params->video_aspect = ctrl->value;
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;
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;
231 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
232 params->video_gop_closure = ctrl->value;
234 case V4L2_CID_MPEG_VIDEO_PULLDOWN:
235 params->video_pulldown = ctrl->value;
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)
242 params->video_bitrate_mode = ctrl->value;
244 case V4L2_CID_MPEG_VIDEO_BITRATE:
245 params->video_bitrate = ctrl->value;
247 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
248 params->video_bitrate_peak = ctrl->value;
250 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
251 params->video_temporal_decimation = ctrl->value;
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;
264 case V4L2_CID_MPEG_STREAM_VBI_FMT:
265 params->stream_vbi_fmt = ctrl->value;
267 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
268 params->video_spatial_filter_mode = ctrl->value;
270 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
271 params->video_spatial_filter = ctrl->value;
273 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
274 params->video_luma_spatial_filter_type = ctrl->value;
276 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
277 params->video_chroma_spatial_filter_type = ctrl->value;
279 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
280 params->video_temporal_filter_mode = ctrl->value;
282 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
283 params->video_temporal_filter = ctrl->value;
285 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
286 params->video_median_filter_type = ctrl->value;
288 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
289 params->video_luma_median_filter_top = ctrl->value;
291 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
292 params->video_luma_median_filter_bottom = ctrl->value;
294 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
295 params->video_chroma_median_filter_top = ctrl->value;
297 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
298 params->video_chroma_median_filter_bottom = ctrl->value;
306 static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
313 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
314 name = "Spatial Filter Mode";
316 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
317 name = "Spatial Filter";
319 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
320 name = "Spatial Luma Filter Type";
322 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
323 name = "Spatial Chroma Filter Type";
325 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
326 name = "Temporal Filter Mode";
328 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
329 name = "Temporal Filter";
331 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
332 name = "Median Filter Type";
334 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
335 name = "Median Luma Filter Maximum";
337 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
338 name = "Median Luma Filter Minimum";
340 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
341 name = "Median Chroma Filter Maximum";
343 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
344 name = "Median Chroma Filter Minimum";
348 return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
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;
361 qctrl->type = V4L2_CTRL_TYPE_INTEGER;
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;
371 qctrl->minimum = min;
372 qctrl->maximum = max;
374 qctrl->default_value = def;
375 qctrl->reserved[0] = qctrl->reserved[1] = 0;
376 snprintf(qctrl->name, sizeof(qctrl->name), name);
380 int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
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:
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;
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
411 err = v4l2_ctrl_query_fill_std(qctrl);
413 qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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",
533 static const char *cx2341x_video_spatial_filter_mode_menu[] = {
539 static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
544 "2D Symmetric non-separable",
548 static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
554 static const char *cx2341x_video_temporal_filter_mode_menu[] = {
560 static const char *cx2341x_video_median_filter_type_menu[] = {
564 "Horizontal/Vertical",
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:
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;
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)
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);
615 ctrls->error_idx = i;
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;
627 err = cx2341x_ctrl_query(params, &qctrl);
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);
635 err = cx2341x_set_ctrl(params, ctrl);
639 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
640 params->video_bitrate_peak < params->video_bitrate) {
642 ctrls->error_idx = ctrls->count;
645 ctrls->error_idx = i;
648 cx2341x_calc_audio_properties(params);
653 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
655 static struct cx2341x_mpeg_params default_params = {
658 .port = CX2341X_PORT_MEMORY,
664 .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
665 .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
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,
677 .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
678 .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
680 .video_gop_size = 12,
681 .video_gop_closure = 1,
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,
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];
712 va_start(vargs, args);
714 for (i = 0; i < args; i++) {
715 data[i] = va_arg(vargs, int);
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[] = {
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);
743 if (old == NULL || old->width != new->width || old->height != new->height ||
744 old->video_encoding != new->video_encoding) {
749 if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
753 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
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]);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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;
855 if (cx2341x_get_ctrl(p, &ctrl))
857 while (ctrl.value-- && *menu) menu++;
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;
871 printk(KERN_INFO "%s: Stream: %s\n",
873 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
874 printk(KERN_INFO "%s: VBI Format: %s\n",
876 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
879 printk(KERN_INFO "%s: Video: %dx%d, %d fps\n",
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",
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),
889 if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
890 printk(", Peak %d", p->video_bitrate_peak);
893 printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
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);
904 printk(KERN_INFO "%s: Audio: %s, %s, %s, %s",
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) {
912 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
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",
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",
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",
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);