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>
30 #include <media/tuner.h>
31 #include <media/cx2341x.h>
32 #include <media/v4l2-common.h>
34 MODULE_DESCRIPTION("cx23415/6 driver");
35 MODULE_AUTHOR("Hans Verkuil");
36 MODULE_LICENSE("GPL");
39 module_param(debug, int, 0644);
40 MODULE_PARM_DESC(debug, "Debug level (0-1)");
42 const u32 cx2341x_mpeg_ctrls[] = {
44 V4L2_CID_MPEG_STREAM_TYPE,
45 V4L2_CID_MPEG_STREAM_VBI_FMT,
46 V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
47 V4L2_CID_MPEG_AUDIO_ENCODING,
48 V4L2_CID_MPEG_AUDIO_L2_BITRATE,
49 V4L2_CID_MPEG_AUDIO_MODE,
50 V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
51 V4L2_CID_MPEG_AUDIO_EMPHASIS,
52 V4L2_CID_MPEG_AUDIO_CRC,
53 V4L2_CID_MPEG_AUDIO_MUTE,
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_BITRATE_MODE,
60 V4L2_CID_MPEG_VIDEO_BITRATE,
61 V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
62 V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
63 V4L2_CID_MPEG_VIDEO_MUTE,
64 V4L2_CID_MPEG_VIDEO_MUTE_YUV,
65 V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
66 V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
67 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
68 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
69 V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
70 V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
71 V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
72 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
73 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
74 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
75 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
76 V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
81 /* Map the control ID to the correct field in the cx2341x_mpeg_params
82 struct. Return -EINVAL if the ID is unknown, else return 0. */
83 static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
84 struct v4l2_ext_control *ctrl)
87 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
88 ctrl->value = params->audio_sampling_freq;
90 case V4L2_CID_MPEG_AUDIO_ENCODING:
91 ctrl->value = params->audio_encoding;
93 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
94 ctrl->value = params->audio_l2_bitrate;
96 case V4L2_CID_MPEG_AUDIO_MODE:
97 ctrl->value = params->audio_mode;
99 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
100 ctrl->value = params->audio_mode_extension;
102 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
103 ctrl->value = params->audio_emphasis;
105 case V4L2_CID_MPEG_AUDIO_CRC:
106 ctrl->value = params->audio_crc;
108 case V4L2_CID_MPEG_AUDIO_MUTE:
109 ctrl->value = params->audio_mute;
111 case V4L2_CID_MPEG_VIDEO_ENCODING:
112 ctrl->value = params->video_encoding;
114 case V4L2_CID_MPEG_VIDEO_ASPECT:
115 ctrl->value = params->video_aspect;
117 case V4L2_CID_MPEG_VIDEO_B_FRAMES:
118 ctrl->value = params->video_b_frames;
120 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
121 ctrl->value = params->video_gop_size;
123 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
124 ctrl->value = params->video_gop_closure;
126 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
127 ctrl->value = params->video_bitrate_mode;
129 case V4L2_CID_MPEG_VIDEO_BITRATE:
130 ctrl->value = params->video_bitrate;
132 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
133 ctrl->value = params->video_bitrate_peak;
135 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
136 ctrl->value = params->video_temporal_decimation;
138 case V4L2_CID_MPEG_VIDEO_MUTE:
139 ctrl->value = params->video_mute;
141 case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
142 ctrl->value = params->video_mute_yuv;
144 case V4L2_CID_MPEG_STREAM_TYPE:
145 ctrl->value = params->stream_type;
147 case V4L2_CID_MPEG_STREAM_VBI_FMT:
148 ctrl->value = params->stream_vbi_fmt;
150 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
151 ctrl->value = params->video_spatial_filter_mode;
153 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
154 ctrl->value = params->video_spatial_filter;
156 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
157 ctrl->value = params->video_luma_spatial_filter_type;
159 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
160 ctrl->value = params->video_chroma_spatial_filter_type;
162 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
163 ctrl->value = params->video_temporal_filter_mode;
165 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
166 ctrl->value = params->video_temporal_filter;
168 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
169 ctrl->value = params->video_median_filter_type;
171 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
172 ctrl->value = params->video_luma_median_filter_top;
174 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
175 ctrl->value = params->video_luma_median_filter_bottom;
177 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
178 ctrl->value = params->video_chroma_median_filter_top;
180 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
181 ctrl->value = params->video_chroma_median_filter_bottom;
183 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
184 ctrl->value = params->stream_insert_nav_packets;
192 /* Map the control ID to the correct field in the cx2341x_mpeg_params
193 struct. Return -EINVAL if the ID is unknown, else return 0. */
194 static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
195 struct v4l2_ext_control *ctrl)
198 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
199 params->audio_sampling_freq = ctrl->value;
201 case V4L2_CID_MPEG_AUDIO_ENCODING:
202 params->audio_encoding = ctrl->value;
204 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
205 params->audio_l2_bitrate = ctrl->value;
207 case V4L2_CID_MPEG_AUDIO_MODE:
208 params->audio_mode = ctrl->value;
210 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
211 params->audio_mode_extension = ctrl->value;
213 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
214 params->audio_emphasis = ctrl->value;
216 case V4L2_CID_MPEG_AUDIO_CRC:
217 params->audio_crc = ctrl->value;
219 case V4L2_CID_MPEG_AUDIO_MUTE:
220 params->audio_mute = ctrl->value;
222 case V4L2_CID_MPEG_VIDEO_ASPECT:
223 params->video_aspect = ctrl->value;
225 case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
226 int b = ctrl->value + 1;
227 int gop = params->video_gop_size;
228 params->video_b_frames = ctrl->value;
229 params->video_gop_size = b * ((gop + b - 1) / b);
230 /* Max GOP size = 34 */
231 while (params->video_gop_size > 34)
232 params->video_gop_size -= b;
235 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
236 int b = params->video_b_frames + 1;
237 int gop = ctrl->value;
238 params->video_gop_size = b * ((gop + b - 1) / b);
239 /* Max GOP size = 34 */
240 while (params->video_gop_size > 34)
241 params->video_gop_size -= b;
242 ctrl->value = params->video_gop_size;
245 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
246 params->video_gop_closure = ctrl->value;
248 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
249 /* MPEG-1 only allows CBR */
250 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
251 ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
253 params->video_bitrate_mode = ctrl->value;
255 case V4L2_CID_MPEG_VIDEO_BITRATE:
256 params->video_bitrate = ctrl->value;
258 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
259 params->video_bitrate_peak = ctrl->value;
261 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
262 params->video_temporal_decimation = ctrl->value;
264 case V4L2_CID_MPEG_VIDEO_MUTE:
265 params->video_mute = (ctrl->value != 0);
267 case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
268 params->video_mute_yuv = ctrl->value;
270 case V4L2_CID_MPEG_STREAM_TYPE:
271 params->stream_type = ctrl->value;
272 params->video_encoding =
273 (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
274 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
275 V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
276 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
277 /* MPEG-1 implies CBR */
278 params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
281 case V4L2_CID_MPEG_STREAM_VBI_FMT:
282 params->stream_vbi_fmt = ctrl->value;
284 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
285 params->video_spatial_filter_mode = ctrl->value;
287 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
288 params->video_spatial_filter = ctrl->value;
290 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
291 params->video_luma_spatial_filter_type = ctrl->value;
293 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
294 params->video_chroma_spatial_filter_type = ctrl->value;
296 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
297 params->video_temporal_filter_mode = ctrl->value;
299 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
300 params->video_temporal_filter = ctrl->value;
302 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
303 params->video_median_filter_type = ctrl->value;
305 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
306 params->video_luma_median_filter_top = ctrl->value;
308 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
309 params->video_luma_median_filter_bottom = ctrl->value;
311 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
312 params->video_chroma_median_filter_top = ctrl->value;
314 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
315 params->video_chroma_median_filter_bottom = ctrl->value;
317 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
318 params->stream_insert_nav_packets = ctrl->value;
326 static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
333 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
334 name = "Spatial Filter Mode";
336 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
337 name = "Spatial Filter";
339 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
340 name = "Spatial Luma Filter Type";
342 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
343 name = "Spatial Chroma Filter Type";
345 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
346 name = "Temporal Filter Mode";
348 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
349 name = "Temporal Filter";
351 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
352 name = "Median Filter Type";
354 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
355 name = "Median Luma Filter Maximum";
357 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
358 name = "Median Luma Filter Minimum";
360 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
361 name = "Median Chroma Filter Maximum";
363 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
364 name = "Median Chroma Filter Minimum";
366 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
367 name = "Insert Navigation Packets";
371 return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
374 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
375 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
376 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
377 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
378 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
379 qctrl->type = V4L2_CTRL_TYPE_MENU;
383 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
384 qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
390 qctrl->type = V4L2_CTRL_TYPE_INTEGER;
394 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
395 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
396 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
397 qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
400 qctrl->minimum = min;
401 qctrl->maximum = max;
403 qctrl->default_value = def;
404 qctrl->reserved[0] = qctrl->reserved[1] = 0;
405 snprintf(qctrl->name, sizeof(qctrl->name), name);
409 int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
414 case V4L2_CID_MPEG_AUDIO_ENCODING:
415 return v4l2_ctrl_query_fill(qctrl,
416 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
417 V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
418 V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
420 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
421 return v4l2_ctrl_query_fill(qctrl,
422 V4L2_MPEG_AUDIO_L2_BITRATE_192K,
423 V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
424 V4L2_MPEG_AUDIO_L2_BITRATE_224K);
426 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
427 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
430 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
431 err = v4l2_ctrl_query_fill_std(qctrl);
432 if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
433 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
436 case V4L2_CID_MPEG_VIDEO_ENCODING:
437 /* this setting is read-only for the cx2341x since the
438 V4L2_CID_MPEG_STREAM_TYPE really determines the
440 err = v4l2_ctrl_query_fill_std(qctrl);
442 qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
445 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
446 err = v4l2_ctrl_query_fill_std(qctrl);
447 if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
448 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
451 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
452 err = v4l2_ctrl_query_fill_std(qctrl);
453 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
454 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
457 case V4L2_CID_MPEG_STREAM_VBI_FMT:
458 if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
459 return v4l2_ctrl_query_fill_std(qctrl);
460 return cx2341x_ctrl_query_fill(qctrl,
461 V4L2_MPEG_STREAM_VBI_FMT_NONE,
462 V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
463 V4L2_MPEG_STREAM_VBI_FMT_NONE);
465 /* CX23415/6 specific */
466 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
467 return cx2341x_ctrl_query_fill(qctrl,
468 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
469 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
470 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
472 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
473 cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
474 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
475 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
476 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
479 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
480 cx2341x_ctrl_query_fill(qctrl,
481 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
482 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
483 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
484 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
485 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
488 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
489 cx2341x_ctrl_query_fill(qctrl,
490 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
491 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
492 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
493 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
494 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
497 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
498 return cx2341x_ctrl_query_fill(qctrl,
499 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
500 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
501 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
503 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
504 cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
505 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
506 if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
507 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
510 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
511 return cx2341x_ctrl_query_fill(qctrl,
512 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
513 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
514 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
516 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
517 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
518 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
519 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
520 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
523 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
524 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
525 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
526 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
527 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
530 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
531 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
532 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
533 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
534 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
537 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
538 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
539 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
540 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
541 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
544 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
545 return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
548 return v4l2_ctrl_query_fill_std(qctrl);
553 const char **cx2341x_ctrl_get_menu(u32 id)
555 static const char *mpeg_stream_type[] = {
556 "MPEG-2 Program Stream",
558 "MPEG-1 System Stream",
559 "MPEG-2 DVD-compatible Stream",
560 "MPEG-1 VCD-compatible Stream",
561 "MPEG-2 SVCD-compatible Stream",
565 static const char *cx2341x_video_spatial_filter_mode_menu[] = {
571 static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
576 "2D Symmetric non-separable",
580 static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
586 static const char *cx2341x_video_temporal_filter_mode_menu[] = {
592 static const char *cx2341x_video_median_filter_type_menu[] = {
596 "Horizontal/Vertical",
602 case V4L2_CID_MPEG_STREAM_TYPE:
603 return mpeg_stream_type;
604 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
605 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
607 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
608 return cx2341x_video_spatial_filter_mode_menu;
609 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
610 return cx2341x_video_luma_spatial_filter_type_menu;
611 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
612 return cx2341x_video_chroma_spatial_filter_type_menu;
613 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
614 return cx2341x_video_temporal_filter_mode_menu;
615 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
616 return cx2341x_video_median_filter_type_menu;
618 return v4l2_ctrl_get_menu(id);
622 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
624 params->audio_properties = (params->audio_sampling_freq << 0) |
625 ((3 - params->audio_encoding) << 2) |
626 ((1 + params->audio_l2_bitrate) << 4) |
627 (params->audio_mode << 8) |
628 (params->audio_mode_extension << 10) |
629 (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
631 params->audio_emphasis) << 12) |
632 (params->audio_crc << 14);
635 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
636 struct v4l2_ext_controls *ctrls, unsigned int cmd)
641 if (cmd == VIDIOC_G_EXT_CTRLS) {
642 for (i = 0; i < ctrls->count; i++) {
643 struct v4l2_ext_control *ctrl = ctrls->controls + i;
645 err = cx2341x_get_ctrl(params, ctrl);
647 ctrls->error_idx = i;
653 for (i = 0; i < ctrls->count; i++) {
654 struct v4l2_ext_control *ctrl = ctrls->controls + i;
655 struct v4l2_queryctrl qctrl;
656 const char **menu_items = NULL;
659 err = cx2341x_ctrl_query(params, &qctrl);
662 if (qctrl.type == V4L2_CTRL_TYPE_MENU)
663 menu_items = cx2341x_ctrl_get_menu(qctrl.id);
664 err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
667 err = cx2341x_set_ctrl(params, ctrl);
671 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
672 params->video_bitrate_peak < params->video_bitrate) {
674 ctrls->error_idx = ctrls->count;
677 ctrls->error_idx = i;
680 cx2341x_calc_audio_properties(params);
685 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
687 static struct cx2341x_mpeg_params default_params = {
690 .port = CX2341X_PORT_MEMORY,
696 .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
697 .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
698 .stream_insert_nav_packets = 0,
701 .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
702 .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
703 .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
704 .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
705 .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
706 .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
707 .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
711 .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
712 .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
714 .video_gop_size = 12,
715 .video_gop_closure = 1,
716 .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
717 .video_bitrate = 6000000,
718 .video_bitrate_peak = 8000000,
719 .video_temporal_decimation = 0,
721 .video_mute_yuv = 0x008080, /* YCbCr value for black */
723 /* encoding filters */
724 .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
725 .video_spatial_filter = 0,
726 .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
727 .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
728 .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
729 .video_temporal_filter = 8,
730 .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
731 .video_luma_median_filter_top = 255,
732 .video_luma_median_filter_bottom = 0,
733 .video_chroma_median_filter_top = 255,
734 .video_chroma_median_filter_bottom = 0,
738 cx2341x_calc_audio_properties(p);
741 static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
743 u32 data[CX2341X_MBOX_MAX_DATA];
747 va_start(vargs, args);
749 for (i = 0; i < args; i++) {
750 data[i] = va_arg(vargs, int);
753 return func(priv, cmd, args, 0, data);
756 int cx2341x_update(void *priv, cx2341x_mbox_func func,
757 const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
759 static int mpeg_stream_type[] = {
769 u16 temporal = new->video_temporal_filter;
771 cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
773 if (old == NULL || old->is_50hz != new->is_50hz) {
774 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
778 if (old == NULL || old->width != new->width || old->height != new->height ||
779 old->video_encoding != new->video_encoding) {
783 if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
787 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
791 if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
792 /* Adjust temporal filter if necessary. The problem with the temporal
793 filter is that it works well with full resolution capturing, but
794 not when the capture window is scaled (the filter introduces
795 a ghosting effect). So if the capture window is scaled, then
796 force the filter to 0.
798 For full resolution the filter really improves the video
799 quality, especially if the original video quality is suboptimal. */
803 if (old == NULL || old->stream_type != new->stream_type) {
804 err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
807 if (old == NULL || old->video_aspect != new->video_aspect) {
808 err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
811 if (old == NULL || old->video_b_frames != new->video_b_frames ||
812 old->video_gop_size != new->video_gop_size) {
813 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
814 new->video_gop_size, new->video_b_frames + 1);
817 if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
818 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
821 if (old == NULL || old->audio_properties != new->audio_properties) {
822 err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
825 if (old == NULL || old->audio_mute != new->audio_mute) {
826 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
829 if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
830 old->video_bitrate != new->video_bitrate ||
831 old->video_bitrate_peak != new->video_bitrate_peak) {
832 err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
833 new->video_bitrate_mode, new->video_bitrate,
834 new->video_bitrate_peak / 400, 0, 0);
837 if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
838 old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
839 old->video_median_filter_type != new->video_median_filter_type) {
840 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
841 new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
842 new->video_median_filter_type);
846 old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
847 old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
848 old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
849 old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
850 err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
851 new->video_luma_median_filter_bottom,
852 new->video_luma_median_filter_top,
853 new->video_chroma_median_filter_bottom,
854 new->video_chroma_median_filter_top);
858 old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
859 old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
860 err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
861 new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
865 old->video_spatial_filter != new->video_spatial_filter ||
866 old->video_temporal_filter != temporal) {
867 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
868 new->video_spatial_filter, temporal);
871 if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
872 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
873 new->video_temporal_decimation);
876 if (old == NULL || old->video_mute != new->video_mute ||
877 (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
878 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
881 if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
882 err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
888 static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
890 const char **menu = cx2341x_ctrl_get_menu(id);
891 struct v4l2_ext_control ctrl;
896 if (cx2341x_get_ctrl(p, &ctrl))
898 while (ctrl.value-- && *menu) menu++;
907 void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
909 int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
910 int temporal = p->video_temporal_filter;
913 printk(KERN_INFO "%s: Stream: %s",
915 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
916 if (p->stream_insert_nav_packets)
917 printk(" (with navigation packets)");
919 printk(KERN_INFO "%s: VBI Format: %s\n",
921 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
924 printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n",
926 p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
927 p->is_50hz ? 25 : 30,
928 (p->video_mute) ? " (muted)" : "");
929 printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
931 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
932 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
933 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
935 if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
936 printk(", Peak %d", p->video_bitrate_peak);
939 printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
941 p->video_gop_size, p->video_b_frames,
942 p->video_gop_closure ? "" : "No ");
943 if (p->video_temporal_decimation) {
944 printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
945 prefix, p->video_temporal_decimation);
949 printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s",
951 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
952 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
953 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
954 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
955 p->audio_mute ? " (muted)" : "");
956 if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
958 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
961 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
962 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
964 /* Encoding filters */
965 printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
967 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
968 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
969 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
970 p->video_spatial_filter);
971 if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
974 printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
976 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
978 printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
980 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
981 p->video_luma_median_filter_bottom,
982 p->video_luma_median_filter_top,
983 p->video_chroma_median_filter_bottom,
984 p->video_chroma_median_filter_top);
987 EXPORT_SYMBOL(cx2341x_fill_defaults);
988 EXPORT_SYMBOL(cx2341x_ctrl_query);
989 EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
990 EXPORT_SYMBOL(cx2341x_ext_ctrls);
991 EXPORT_SYMBOL(cx2341x_update);
992 EXPORT_SYMBOL(cx2341x_log_status);
993 EXPORT_SYMBOL(cx2341x_mpeg_ctrls);