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/errno.h>
24 #include <linux/kernel.h>
25 #include <linux/init.h>
26 #include <linux/types.h>
27 #include <linux/videodev2.h>
29 #include <media/tuner.h>
30 #include <media/cx2341x.h>
31 #include <media/v4l2-common.h>
33 MODULE_DESCRIPTION("cx23415/6 driver");
34 MODULE_AUTHOR("Hans Verkuil");
35 MODULE_LICENSE("GPL");
38 module_param(debug, int, 0644);
39 MODULE_PARM_DESC(debug, "Debug level (0-1)");
41 const u32 cx2341x_mpeg_ctrls[] = {
43 V4L2_CID_MPEG_STREAM_TYPE,
44 V4L2_CID_MPEG_STREAM_VBI_FMT,
45 V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
46 V4L2_CID_MPEG_AUDIO_ENCODING,
47 V4L2_CID_MPEG_AUDIO_L2_BITRATE,
48 V4L2_CID_MPEG_AUDIO_MODE,
49 V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
50 V4L2_CID_MPEG_AUDIO_EMPHASIS,
51 V4L2_CID_MPEG_AUDIO_CRC,
52 V4L2_CID_MPEG_AUDIO_MUTE,
53 V4L2_CID_MPEG_VIDEO_ENCODING,
54 V4L2_CID_MPEG_VIDEO_ASPECT,
55 V4L2_CID_MPEG_VIDEO_B_FRAMES,
56 V4L2_CID_MPEG_VIDEO_GOP_SIZE,
57 V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
58 V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
59 V4L2_CID_MPEG_VIDEO_BITRATE,
60 V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
61 V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
62 V4L2_CID_MPEG_VIDEO_MUTE,
63 V4L2_CID_MPEG_VIDEO_MUTE_YUV,
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,
75 V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
80 /* Map the control ID to the correct field in the cx2341x_mpeg_params
81 struct. Return -EINVAL if the ID is unknown, else return 0. */
82 static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
83 struct v4l2_ext_control *ctrl)
86 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
87 ctrl->value = params->audio_sampling_freq;
89 case V4L2_CID_MPEG_AUDIO_ENCODING:
90 ctrl->value = params->audio_encoding;
92 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
93 ctrl->value = params->audio_l2_bitrate;
95 case V4L2_CID_MPEG_AUDIO_MODE:
96 ctrl->value = params->audio_mode;
98 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
99 ctrl->value = params->audio_mode_extension;
101 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
102 ctrl->value = params->audio_emphasis;
104 case V4L2_CID_MPEG_AUDIO_CRC:
105 ctrl->value = params->audio_crc;
107 case V4L2_CID_MPEG_AUDIO_MUTE:
108 ctrl->value = params->audio_mute;
110 case V4L2_CID_MPEG_VIDEO_ENCODING:
111 ctrl->value = params->video_encoding;
113 case V4L2_CID_MPEG_VIDEO_ASPECT:
114 ctrl->value = params->video_aspect;
116 case V4L2_CID_MPEG_VIDEO_B_FRAMES:
117 ctrl->value = params->video_b_frames;
119 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
120 ctrl->value = params->video_gop_size;
122 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
123 ctrl->value = params->video_gop_closure;
125 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
126 ctrl->value = params->video_bitrate_mode;
128 case V4L2_CID_MPEG_VIDEO_BITRATE:
129 ctrl->value = params->video_bitrate;
131 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
132 ctrl->value = params->video_bitrate_peak;
134 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
135 ctrl->value = params->video_temporal_decimation;
137 case V4L2_CID_MPEG_VIDEO_MUTE:
138 ctrl->value = params->video_mute;
140 case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
141 ctrl->value = params->video_mute_yuv;
143 case V4L2_CID_MPEG_STREAM_TYPE:
144 ctrl->value = params->stream_type;
146 case V4L2_CID_MPEG_STREAM_VBI_FMT:
147 ctrl->value = params->stream_vbi_fmt;
149 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
150 ctrl->value = params->video_spatial_filter_mode;
152 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
153 ctrl->value = params->video_spatial_filter;
155 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
156 ctrl->value = params->video_luma_spatial_filter_type;
158 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
159 ctrl->value = params->video_chroma_spatial_filter_type;
161 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
162 ctrl->value = params->video_temporal_filter_mode;
164 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
165 ctrl->value = params->video_temporal_filter;
167 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
168 ctrl->value = params->video_median_filter_type;
170 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
171 ctrl->value = params->video_luma_median_filter_top;
173 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
174 ctrl->value = params->video_luma_median_filter_bottom;
176 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
177 ctrl->value = params->video_chroma_median_filter_top;
179 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
180 ctrl->value = params->video_chroma_median_filter_bottom;
182 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
183 ctrl->value = params->stream_insert_nav_packets;
191 /* Map the control ID to the correct field in the cx2341x_mpeg_params
192 struct. Return -EINVAL if the ID is unknown, else return 0. */
193 static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
194 struct v4l2_ext_control *ctrl)
197 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
198 params->audio_sampling_freq = ctrl->value;
200 case V4L2_CID_MPEG_AUDIO_ENCODING:
201 params->audio_encoding = ctrl->value;
203 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
204 params->audio_l2_bitrate = ctrl->value;
206 case V4L2_CID_MPEG_AUDIO_MODE:
207 params->audio_mode = ctrl->value;
209 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
210 params->audio_mode_extension = ctrl->value;
212 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
213 params->audio_emphasis = ctrl->value;
215 case V4L2_CID_MPEG_AUDIO_CRC:
216 params->audio_crc = ctrl->value;
218 case V4L2_CID_MPEG_AUDIO_MUTE:
219 params->audio_mute = ctrl->value;
221 case V4L2_CID_MPEG_VIDEO_ASPECT:
222 params->video_aspect = ctrl->value;
224 case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
225 int b = ctrl->value + 1;
226 int gop = params->video_gop_size;
227 params->video_b_frames = ctrl->value;
228 params->video_gop_size = b * ((gop + b - 1) / b);
229 /* Max GOP size = 34 */
230 while (params->video_gop_size > 34)
231 params->video_gop_size -= b;
234 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
235 int b = params->video_b_frames + 1;
236 int gop = ctrl->value;
237 params->video_gop_size = b * ((gop + b - 1) / b);
238 /* Max GOP size = 34 */
239 while (params->video_gop_size > 34)
240 params->video_gop_size -= b;
241 ctrl->value = params->video_gop_size;
244 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
245 params->video_gop_closure = ctrl->value;
247 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
248 /* MPEG-1 only allows CBR */
249 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
250 ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
252 params->video_bitrate_mode = ctrl->value;
254 case V4L2_CID_MPEG_VIDEO_BITRATE:
255 params->video_bitrate = ctrl->value;
257 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
258 params->video_bitrate_peak = ctrl->value;
260 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
261 params->video_temporal_decimation = ctrl->value;
263 case V4L2_CID_MPEG_VIDEO_MUTE:
264 params->video_mute = (ctrl->value != 0);
266 case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
267 params->video_mute_yuv = ctrl->value;
269 case V4L2_CID_MPEG_STREAM_TYPE:
270 params->stream_type = ctrl->value;
271 params->video_encoding =
272 (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
273 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
274 V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
275 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
276 /* MPEG-1 implies CBR */
277 params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
280 case V4L2_CID_MPEG_STREAM_VBI_FMT:
281 params->stream_vbi_fmt = ctrl->value;
283 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
284 params->video_spatial_filter_mode = ctrl->value;
286 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
287 params->video_spatial_filter = ctrl->value;
289 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
290 params->video_luma_spatial_filter_type = ctrl->value;
292 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
293 params->video_chroma_spatial_filter_type = ctrl->value;
295 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
296 params->video_temporal_filter_mode = ctrl->value;
298 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
299 params->video_temporal_filter = ctrl->value;
301 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
302 params->video_median_filter_type = ctrl->value;
304 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
305 params->video_luma_median_filter_top = ctrl->value;
307 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
308 params->video_luma_median_filter_bottom = ctrl->value;
310 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
311 params->video_chroma_median_filter_top = ctrl->value;
313 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
314 params->video_chroma_median_filter_bottom = ctrl->value;
316 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
317 params->stream_insert_nav_packets = ctrl->value;
325 static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
332 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
333 name = "Spatial Filter Mode";
335 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
336 name = "Spatial Filter";
338 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
339 name = "Spatial Luma Filter Type";
341 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
342 name = "Spatial Chroma Filter Type";
344 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
345 name = "Temporal Filter Mode";
347 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
348 name = "Temporal Filter";
350 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
351 name = "Median Filter Type";
353 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
354 name = "Median Luma Filter Maximum";
356 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
357 name = "Median Luma Filter Minimum";
359 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
360 name = "Median Chroma Filter Maximum";
362 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
363 name = "Median Chroma Filter Minimum";
365 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
366 name = "Insert Navigation Packets";
370 return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
373 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
374 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
375 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
376 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
377 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
378 qctrl->type = V4L2_CTRL_TYPE_MENU;
382 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
383 qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
389 qctrl->type = V4L2_CTRL_TYPE_INTEGER;
393 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
394 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
395 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
396 qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
399 qctrl->minimum = min;
400 qctrl->maximum = max;
402 qctrl->default_value = def;
403 qctrl->reserved[0] = qctrl->reserved[1] = 0;
404 snprintf(qctrl->name, sizeof(qctrl->name), name);
408 int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
413 case V4L2_CID_MPEG_AUDIO_ENCODING:
414 return v4l2_ctrl_query_fill(qctrl,
415 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
416 V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
417 V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
419 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
420 return v4l2_ctrl_query_fill(qctrl,
421 V4L2_MPEG_AUDIO_L2_BITRATE_192K,
422 V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
423 V4L2_MPEG_AUDIO_L2_BITRATE_224K);
425 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
426 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
429 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
430 err = v4l2_ctrl_query_fill_std(qctrl);
431 if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
432 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
435 case V4L2_CID_MPEG_VIDEO_ENCODING:
436 /* this setting is read-only for the cx2341x since the
437 V4L2_CID_MPEG_STREAM_TYPE really determines the
439 err = v4l2_ctrl_query_fill_std(qctrl);
441 qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
444 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
445 err = v4l2_ctrl_query_fill_std(qctrl);
446 if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
447 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
450 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
451 err = v4l2_ctrl_query_fill_std(qctrl);
452 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
453 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
456 case V4L2_CID_MPEG_STREAM_VBI_FMT:
457 if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
458 return v4l2_ctrl_query_fill_std(qctrl);
459 return cx2341x_ctrl_query_fill(qctrl,
460 V4L2_MPEG_STREAM_VBI_FMT_NONE,
461 V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
462 V4L2_MPEG_STREAM_VBI_FMT_NONE);
464 /* CX23415/6 specific */
465 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
466 return cx2341x_ctrl_query_fill(qctrl,
467 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
468 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
469 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
471 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
472 cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
473 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
474 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
475 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
478 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
479 cx2341x_ctrl_query_fill(qctrl,
480 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
481 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
482 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
483 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
484 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
487 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
488 cx2341x_ctrl_query_fill(qctrl,
489 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
490 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
491 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
492 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
493 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
496 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
497 return cx2341x_ctrl_query_fill(qctrl,
498 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
499 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
500 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
502 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
503 cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
504 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
505 if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
506 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
509 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
510 return cx2341x_ctrl_query_fill(qctrl,
511 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
512 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
513 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
515 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
516 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
517 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
518 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
519 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
522 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
523 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
524 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
525 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
526 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
529 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
530 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
531 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
532 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
533 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
536 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
537 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
538 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
539 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
540 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
543 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
544 return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
547 return v4l2_ctrl_query_fill_std(qctrl);
552 const char **cx2341x_ctrl_get_menu(u32 id)
554 static const char *mpeg_stream_type[] = {
555 "MPEG-2 Program Stream",
557 "MPEG-1 System Stream",
558 "MPEG-2 DVD-compatible Stream",
559 "MPEG-1 VCD-compatible Stream",
560 "MPEG-2 SVCD-compatible Stream",
564 static const char *cx2341x_video_spatial_filter_mode_menu[] = {
570 static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
575 "2D Symmetric non-separable",
579 static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
585 static const char *cx2341x_video_temporal_filter_mode_menu[] = {
591 static const char *cx2341x_video_median_filter_type_menu[] = {
595 "Horizontal/Vertical",
601 case V4L2_CID_MPEG_STREAM_TYPE:
602 return mpeg_stream_type;
603 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
604 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
606 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
607 return cx2341x_video_spatial_filter_mode_menu;
608 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
609 return cx2341x_video_luma_spatial_filter_type_menu;
610 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
611 return cx2341x_video_chroma_spatial_filter_type_menu;
612 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
613 return cx2341x_video_temporal_filter_mode_menu;
614 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
615 return cx2341x_video_median_filter_type_menu;
617 return v4l2_ctrl_get_menu(id);
621 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
623 params->audio_properties = (params->audio_sampling_freq << 0) |
624 ((3 - params->audio_encoding) << 2) |
625 ((1 + params->audio_l2_bitrate) << 4) |
626 (params->audio_mode << 8) |
627 (params->audio_mode_extension << 10) |
628 (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
630 params->audio_emphasis) << 12) |
631 (params->audio_crc << 14);
634 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
635 struct v4l2_ext_controls *ctrls, unsigned int cmd)
640 if (cmd == VIDIOC_G_EXT_CTRLS) {
641 for (i = 0; i < ctrls->count; i++) {
642 struct v4l2_ext_control *ctrl = ctrls->controls + i;
644 err = cx2341x_get_ctrl(params, ctrl);
646 ctrls->error_idx = i;
652 for (i = 0; i < ctrls->count; i++) {
653 struct v4l2_ext_control *ctrl = ctrls->controls + i;
654 struct v4l2_queryctrl qctrl;
655 const char **menu_items = NULL;
658 err = cx2341x_ctrl_query(params, &qctrl);
661 if (qctrl.type == V4L2_CTRL_TYPE_MENU)
662 menu_items = cx2341x_ctrl_get_menu(qctrl.id);
663 err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
666 err = cx2341x_set_ctrl(params, ctrl);
670 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
671 params->video_bitrate_peak < params->video_bitrate) {
673 ctrls->error_idx = ctrls->count;
676 ctrls->error_idx = i;
679 cx2341x_calc_audio_properties(params);
684 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
686 static struct cx2341x_mpeg_params default_params = {
689 .port = CX2341X_PORT_MEMORY,
695 .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
696 .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
697 .stream_insert_nav_packets = 0,
700 .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
701 .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
702 .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
703 .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
704 .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
705 .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
706 .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
710 .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
711 .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
713 .video_gop_size = 12,
714 .video_gop_closure = 1,
715 .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
716 .video_bitrate = 6000000,
717 .video_bitrate_peak = 8000000,
718 .video_temporal_decimation = 0,
720 .video_mute_yuv = 0x008080, /* YCbCr value for black */
722 /* encoding filters */
723 .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
724 .video_spatial_filter = 0,
725 .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
726 .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
727 .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
728 .video_temporal_filter = 8,
729 .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
730 .video_luma_median_filter_top = 255,
731 .video_luma_median_filter_bottom = 0,
732 .video_chroma_median_filter_top = 255,
733 .video_chroma_median_filter_bottom = 0,
737 cx2341x_calc_audio_properties(p);
740 static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
742 u32 data[CX2341X_MBOX_MAX_DATA];
746 va_start(vargs, args);
748 for (i = 0; i < args; i++) {
749 data[i] = va_arg(vargs, int);
752 return func(priv, cmd, args, 0, data);
755 int cx2341x_update(void *priv, cx2341x_mbox_func func,
756 const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
758 static int mpeg_stream_type[] = {
768 u16 temporal = new->video_temporal_filter;
770 cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
772 if (old == NULL || old->is_50hz != new->is_50hz) {
773 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
777 if (old == NULL || old->width != new->width || old->height != new->height ||
778 old->video_encoding != new->video_encoding) {
782 if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
786 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
790 if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
791 /* Adjust temporal filter if necessary. The problem with the temporal
792 filter is that it works well with full resolution capturing, but
793 not when the capture window is scaled (the filter introduces
794 a ghosting effect). So if the capture window is scaled, then
795 force the filter to 0.
797 For full resolution the filter really improves the video
798 quality, especially if the original video quality is suboptimal. */
802 if (old == NULL || old->stream_type != new->stream_type) {
803 err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
806 if (old == NULL || old->video_aspect != new->video_aspect) {
807 err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
810 if (old == NULL || old->video_b_frames != new->video_b_frames ||
811 old->video_gop_size != new->video_gop_size) {
812 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
813 new->video_gop_size, new->video_b_frames + 1);
816 if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
817 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
820 if (old == NULL || old->audio_properties != new->audio_properties) {
821 err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
824 if (old == NULL || old->audio_mute != new->audio_mute) {
825 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
828 if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
829 old->video_bitrate != new->video_bitrate ||
830 old->video_bitrate_peak != new->video_bitrate_peak) {
831 err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
832 new->video_bitrate_mode, new->video_bitrate,
833 new->video_bitrate_peak / 400, 0, 0);
836 if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
837 old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
838 old->video_median_filter_type != new->video_median_filter_type) {
839 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
840 new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
841 new->video_median_filter_type);
845 old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
846 old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
847 old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
848 old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
849 err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
850 new->video_luma_median_filter_bottom,
851 new->video_luma_median_filter_top,
852 new->video_chroma_median_filter_bottom,
853 new->video_chroma_median_filter_top);
857 old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
858 old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
859 err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
860 new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
864 old->video_spatial_filter != new->video_spatial_filter ||
865 old->video_temporal_filter != temporal) {
866 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
867 new->video_spatial_filter, temporal);
870 if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
871 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
872 new->video_temporal_decimation);
875 if (old == NULL || old->video_mute != new->video_mute ||
876 (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
877 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
880 if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
881 err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
887 static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
889 const char **menu = cx2341x_ctrl_get_menu(id);
890 struct v4l2_ext_control ctrl;
895 if (cx2341x_get_ctrl(p, &ctrl))
897 while (ctrl.value-- && *menu) menu++;
906 void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
908 int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
909 int temporal = p->video_temporal_filter;
912 printk(KERN_INFO "%s: Stream: %s",
914 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
915 if (p->stream_insert_nav_packets)
916 printk(" (with navigation packets)");
918 printk(KERN_INFO "%s: VBI Format: %s\n",
920 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
923 printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n",
925 p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
926 p->is_50hz ? 25 : 30,
927 (p->video_mute) ? " (muted)" : "");
928 printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
930 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
931 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
932 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
934 if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
935 printk(", Peak %d", p->video_bitrate_peak);
938 printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
940 p->video_gop_size, p->video_b_frames,
941 p->video_gop_closure ? "" : "No ");
942 if (p->video_temporal_decimation) {
943 printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
944 prefix, p->video_temporal_decimation);
948 printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s",
950 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
951 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
952 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
953 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
954 p->audio_mute ? " (muted)" : "");
955 if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
957 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
960 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
961 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
963 /* Encoding filters */
964 printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
966 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
967 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
968 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
969 p->video_spatial_filter);
970 if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
973 printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
975 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
977 printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
979 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
980 p->video_luma_median_filter_bottom,
981 p->video_luma_median_filter_top,
982 p->video_chroma_median_filter_bottom,
983 p->video_chroma_median_filter_top);
986 EXPORT_SYMBOL(cx2341x_fill_defaults);
987 EXPORT_SYMBOL(cx2341x_ctrl_query);
988 EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
989 EXPORT_SYMBOL(cx2341x_ext_ctrls);
990 EXPORT_SYMBOL(cx2341x_update);
991 EXPORT_SYMBOL(cx2341x_log_status);
992 EXPORT_SYMBOL(cx2341x_mpeg_ctrls);