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,
78 EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
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(const 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, int busy,
195 struct v4l2_ext_control *ctrl)
198 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
201 params->audio_sampling_freq = ctrl->value;
203 case V4L2_CID_MPEG_AUDIO_ENCODING:
204 params->audio_encoding = ctrl->value;
206 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
209 params->audio_l2_bitrate = ctrl->value;
211 case V4L2_CID_MPEG_AUDIO_MODE:
212 params->audio_mode = ctrl->value;
214 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
215 params->audio_mode_extension = ctrl->value;
217 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
218 params->audio_emphasis = ctrl->value;
220 case V4L2_CID_MPEG_AUDIO_CRC:
221 params->audio_crc = ctrl->value;
223 case V4L2_CID_MPEG_AUDIO_MUTE:
224 params->audio_mute = ctrl->value;
226 case V4L2_CID_MPEG_VIDEO_ASPECT:
227 params->video_aspect = ctrl->value;
229 case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
230 int b = ctrl->value + 1;
231 int gop = params->video_gop_size;
232 params->video_b_frames = ctrl->value;
233 params->video_gop_size = b * ((gop + b - 1) / b);
234 /* Max GOP size = 34 */
235 while (params->video_gop_size > 34)
236 params->video_gop_size -= b;
239 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
240 int b = params->video_b_frames + 1;
241 int gop = ctrl->value;
242 params->video_gop_size = b * ((gop + b - 1) / b);
243 /* Max GOP size = 34 */
244 while (params->video_gop_size > 34)
245 params->video_gop_size -= b;
246 ctrl->value = params->video_gop_size;
249 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
250 params->video_gop_closure = ctrl->value;
252 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
255 /* MPEG-1 only allows CBR */
256 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
257 ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
259 params->video_bitrate_mode = ctrl->value;
261 case V4L2_CID_MPEG_VIDEO_BITRATE:
264 params->video_bitrate = ctrl->value;
266 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
269 params->video_bitrate_peak = ctrl->value;
271 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
272 params->video_temporal_decimation = ctrl->value;
274 case V4L2_CID_MPEG_VIDEO_MUTE:
275 params->video_mute = (ctrl->value != 0);
277 case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
278 params->video_mute_yuv = ctrl->value;
280 case V4L2_CID_MPEG_STREAM_TYPE:
283 params->stream_type = ctrl->value;
284 params->video_encoding =
285 (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
286 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
287 V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
288 V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
289 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
290 /* MPEG-1 implies CBR */
291 params->video_bitrate_mode =
292 V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
294 case V4L2_CID_MPEG_STREAM_VBI_FMT:
295 params->stream_vbi_fmt = ctrl->value;
297 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
298 params->video_spatial_filter_mode = ctrl->value;
300 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
301 params->video_spatial_filter = ctrl->value;
303 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
304 params->video_luma_spatial_filter_type = ctrl->value;
306 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
307 params->video_chroma_spatial_filter_type = ctrl->value;
309 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
310 params->video_temporal_filter_mode = ctrl->value;
312 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
313 params->video_temporal_filter = ctrl->value;
315 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
316 params->video_median_filter_type = ctrl->value;
318 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
319 params->video_luma_median_filter_top = ctrl->value;
321 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
322 params->video_luma_median_filter_bottom = ctrl->value;
324 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
325 params->video_chroma_median_filter_top = ctrl->value;
327 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
328 params->video_chroma_median_filter_bottom = ctrl->value;
330 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
331 params->stream_insert_nav_packets = ctrl->value;
339 static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
340 s32 min, s32 max, s32 step, s32 def)
347 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
348 name = "Spatial Filter Mode";
350 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
351 name = "Spatial Filter";
353 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
354 name = "Spatial Luma Filter Type";
356 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
357 name = "Spatial Chroma Filter Type";
359 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
360 name = "Temporal Filter Mode";
362 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
363 name = "Temporal Filter";
365 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
366 name = "Median Filter Type";
368 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
369 name = "Median Luma Filter Maximum";
371 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
372 name = "Median Luma Filter Minimum";
374 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
375 name = "Median Chroma Filter Maximum";
377 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
378 name = "Median Chroma Filter Minimum";
380 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
381 name = "Insert Navigation Packets";
385 return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
388 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
389 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
390 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
391 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
392 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
393 qctrl->type = V4L2_CTRL_TYPE_MENU;
397 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
398 qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
404 qctrl->type = V4L2_CTRL_TYPE_INTEGER;
408 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
409 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
410 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
411 qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
414 qctrl->minimum = min;
415 qctrl->maximum = max;
417 qctrl->default_value = def;
418 qctrl->reserved[0] = qctrl->reserved[1] = 0;
419 snprintf(qctrl->name, sizeof(qctrl->name), name);
423 int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
424 struct v4l2_queryctrl *qctrl)
429 case V4L2_CID_MPEG_AUDIO_ENCODING:
430 return v4l2_ctrl_query_fill(qctrl,
431 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
432 V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
433 V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
435 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
436 return v4l2_ctrl_query_fill(qctrl,
437 V4L2_MPEG_AUDIO_L2_BITRATE_192K,
438 V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
439 V4L2_MPEG_AUDIO_L2_BITRATE_224K);
441 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
442 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
445 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
446 err = v4l2_ctrl_query_fill_std(qctrl);
448 params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
449 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
452 case V4L2_CID_MPEG_VIDEO_ENCODING:
453 /* this setting is read-only for the cx2341x since the
454 V4L2_CID_MPEG_STREAM_TYPE really determines the
456 err = v4l2_ctrl_query_fill_std(qctrl);
458 qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
461 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
462 err = v4l2_ctrl_query_fill_std(qctrl);
464 params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
465 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
468 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
469 err = v4l2_ctrl_query_fill_std(qctrl);
471 params->video_bitrate_mode ==
472 V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
473 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
476 case V4L2_CID_MPEG_STREAM_VBI_FMT:
477 if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
478 return v4l2_ctrl_query_fill_std(qctrl);
479 return cx2341x_ctrl_query_fill(qctrl,
480 V4L2_MPEG_STREAM_VBI_FMT_NONE,
481 V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
482 V4L2_MPEG_STREAM_VBI_FMT_NONE);
484 /* CX23415/6 specific */
485 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
486 return cx2341x_ctrl_query_fill(qctrl,
487 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
488 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
489 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
491 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
492 cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
493 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
494 if (params->video_spatial_filter_mode ==
495 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
496 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
499 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
500 cx2341x_ctrl_query_fill(qctrl,
501 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
502 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
504 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
505 if (params->video_spatial_filter_mode ==
506 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
507 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
510 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
511 cx2341x_ctrl_query_fill(qctrl,
512 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
513 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
515 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
516 if (params->video_spatial_filter_mode ==
517 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
518 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
521 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
522 return cx2341x_ctrl_query_fill(qctrl,
523 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
524 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
525 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
527 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
528 cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
529 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
530 if (params->video_temporal_filter_mode ==
531 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
532 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
535 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
536 return cx2341x_ctrl_query_fill(qctrl,
537 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
538 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
539 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
541 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
542 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
543 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
544 if (params->video_median_filter_type ==
545 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
546 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
549 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
550 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
551 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
552 if (params->video_median_filter_type ==
553 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
554 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
557 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
558 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
559 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
560 if (params->video_median_filter_type ==
561 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
562 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
565 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
566 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
567 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
568 if (params->video_median_filter_type ==
569 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
570 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
573 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
574 return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
577 return v4l2_ctrl_query_fill_std(qctrl);
581 EXPORT_SYMBOL(cx2341x_ctrl_query);
583 const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
585 static const char *mpeg_stream_type_without_ts[] = {
586 "MPEG-2 Program Stream",
588 "MPEG-1 System Stream",
589 "MPEG-2 DVD-compatible Stream",
590 "MPEG-1 VCD-compatible Stream",
591 "MPEG-2 SVCD-compatible Stream",
595 static const char *mpeg_stream_type_with_ts[] = {
596 "MPEG-2 Program Stream",
597 "MPEG-2 Transport Stream",
598 "MPEG-1 System Stream",
599 "MPEG-2 DVD-compatible Stream",
600 "MPEG-1 VCD-compatible Stream",
601 "MPEG-2 SVCD-compatible Stream",
605 static const char *cx2341x_video_spatial_filter_mode_menu[] = {
611 static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
616 "2D Symmetric non-separable",
620 static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
626 static const char *cx2341x_video_temporal_filter_mode_menu[] = {
632 static const char *cx2341x_video_median_filter_type_menu[] = {
636 "Horizontal/Vertical",
642 case V4L2_CID_MPEG_STREAM_TYPE:
643 return (p->capabilities & CX2341X_CAP_HAS_TS) ?
644 mpeg_stream_type_with_ts : mpeg_stream_type_without_ts;
645 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
646 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
648 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
649 return cx2341x_video_spatial_filter_mode_menu;
650 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
651 return cx2341x_video_luma_spatial_filter_type_menu;
652 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
653 return cx2341x_video_chroma_spatial_filter_type_menu;
654 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
655 return cx2341x_video_temporal_filter_mode_menu;
656 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
657 return cx2341x_video_median_filter_type_menu;
659 return v4l2_ctrl_get_menu(id);
662 EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
664 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
666 params->audio_properties = (params->audio_sampling_freq << 0) |
667 ((3 - params->audio_encoding) << 2) |
668 ((1 + params->audio_l2_bitrate) << 4) |
669 (params->audio_mode << 8) |
670 (params->audio_mode_extension << 10) |
671 (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
672 ? 3 : params->audio_emphasis) << 12) |
673 (params->audio_crc << 14);
676 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
677 struct v4l2_ext_controls *ctrls, unsigned int cmd)
682 if (cmd == VIDIOC_G_EXT_CTRLS) {
683 for (i = 0; i < ctrls->count; i++) {
684 struct v4l2_ext_control *ctrl = ctrls->controls + i;
686 err = cx2341x_get_ctrl(params, ctrl);
688 ctrls->error_idx = i;
694 for (i = 0; i < ctrls->count; i++) {
695 struct v4l2_ext_control *ctrl = ctrls->controls + i;
696 struct v4l2_queryctrl qctrl;
697 const char **menu_items = NULL;
700 err = cx2341x_ctrl_query(params, &qctrl);
703 if (qctrl.type == V4L2_CTRL_TYPE_MENU)
704 menu_items = cx2341x_ctrl_get_menu(params, qctrl.id);
705 err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
708 err = cx2341x_set_ctrl(params, busy, ctrl);
713 params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
714 params->video_bitrate_peak < params->video_bitrate) {
716 ctrls->error_idx = ctrls->count;
719 ctrls->error_idx = i;
721 cx2341x_calc_audio_properties(params);
724 EXPORT_SYMBOL(cx2341x_ext_ctrls);
726 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
728 static struct cx2341x_mpeg_params default_params = {
731 .port = CX2341X_PORT_MEMORY,
737 .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
738 .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
739 .stream_insert_nav_packets = 0,
742 .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
743 .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
744 .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
745 .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
746 .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
747 .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
748 .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
752 .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
753 .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
755 .video_gop_size = 12,
756 .video_gop_closure = 1,
757 .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
758 .video_bitrate = 6000000,
759 .video_bitrate_peak = 8000000,
760 .video_temporal_decimation = 0,
762 .video_mute_yuv = 0x008080, /* YCbCr value for black */
764 /* encoding filters */
765 .video_spatial_filter_mode =
766 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
767 .video_spatial_filter = 0,
768 .video_luma_spatial_filter_type =
769 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
770 .video_chroma_spatial_filter_type =
771 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
772 .video_temporal_filter_mode =
773 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
774 .video_temporal_filter = 8,
775 .video_median_filter_type =
776 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
777 .video_luma_median_filter_top = 255,
778 .video_luma_median_filter_bottom = 0,
779 .video_chroma_median_filter_top = 255,
780 .video_chroma_median_filter_bottom = 0,
784 cx2341x_calc_audio_properties(p);
786 EXPORT_SYMBOL(cx2341x_fill_defaults);
788 static int cx2341x_api(void *priv, cx2341x_mbox_func func,
789 u32 cmd, int args, ...)
791 u32 data[CX2341X_MBOX_MAX_DATA];
795 va_start(vargs, args);
797 for (i = 0; i < args; i++)
798 data[i] = va_arg(vargs, int);
800 return func(priv, cmd, args, 0, data);
803 #define NEQ(field) (old->field != new->field)
805 int cx2341x_update(void *priv, cx2341x_mbox_func func,
806 const struct cx2341x_mpeg_params *old,
807 const struct cx2341x_mpeg_params *new)
809 static int mpeg_stream_type[] = {
819 int force = (old == NULL);
820 u16 temporal = new->video_temporal_filter;
822 cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
824 if (force || NEQ(is_50hz)) {
825 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
830 if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
834 if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
838 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
843 if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
844 /* Adjust temporal filter if necessary. The problem with the
845 temporal filter is that it works well with full resolution
846 capturing, but not when the capture window is scaled (the
847 filter introduces a ghosting effect). So if the capture
848 window is scaled, then force the filter to 0.
850 For full resolution the filter really improves the video
851 quality, especially if the original video quality is
856 if (force || NEQ(stream_type)) {
857 err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
858 mpeg_stream_type[new->stream_type]);
861 if (force || NEQ(video_aspect)) {
862 err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
863 1 + new->video_aspect);
866 if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
867 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
868 new->video_gop_size, new->video_b_frames + 1);
871 if (force || NEQ(video_gop_closure)) {
872 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
873 new->video_gop_closure);
876 if (force || NEQ(audio_properties)) {
877 err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
878 1, new->audio_properties);
881 if (force || NEQ(audio_mute)) {
882 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
886 if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
887 NEQ(video_bitrate_peak)) {
888 err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
889 new->video_bitrate_mode, new->video_bitrate,
890 new->video_bitrate_peak / 400, 0, 0);
893 if (force || NEQ(video_spatial_filter_mode) ||
894 NEQ(video_temporal_filter_mode) ||
895 NEQ(video_median_filter_type)) {
896 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
897 2, new->video_spatial_filter_mode |
898 (new->video_temporal_filter_mode << 1),
899 new->video_median_filter_type);
902 if (force || NEQ(video_luma_median_filter_bottom) ||
903 NEQ(video_luma_median_filter_top) ||
904 NEQ(video_chroma_median_filter_bottom) ||
905 NEQ(video_chroma_median_filter_top)) {
906 err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
907 new->video_luma_median_filter_bottom,
908 new->video_luma_median_filter_top,
909 new->video_chroma_median_filter_bottom,
910 new->video_chroma_median_filter_top);
913 if (force || NEQ(video_luma_spatial_filter_type) ||
914 NEQ(video_chroma_spatial_filter_type)) {
915 err = cx2341x_api(priv, func,
916 CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
917 2, new->video_luma_spatial_filter_type,
918 new->video_chroma_spatial_filter_type);
921 if (force || NEQ(video_spatial_filter) ||
922 old->video_temporal_filter != temporal) {
923 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
924 2, new->video_spatial_filter, temporal);
927 if (force || NEQ(video_temporal_decimation)) {
928 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
929 1, new->video_temporal_decimation);
932 if (force || NEQ(video_mute) ||
933 (new->video_mute && NEQ(video_mute_yuv))) {
934 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
935 new->video_mute | (new->video_mute_yuv << 8));
938 if (force || NEQ(stream_insert_nav_packets)) {
939 err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
940 7, new->stream_insert_nav_packets);
945 EXPORT_SYMBOL(cx2341x_update);
947 static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
949 const char **menu = cx2341x_ctrl_get_menu(p, id);
950 struct v4l2_ext_control ctrl;
955 if (cx2341x_get_ctrl(p, &ctrl))
957 while (ctrl.value-- && *menu) menu++;
966 void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
968 int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
969 int temporal = p->video_temporal_filter;
972 printk(KERN_INFO "%s: Stream: %s",
974 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
975 if (p->stream_insert_nav_packets)
976 printk(" (with navigation packets)");
978 printk(KERN_INFO "%s: VBI Format: %s\n",
980 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
983 printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n",
985 p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
986 p->is_50hz ? 25 : 30,
987 (p->video_mute) ? " (muted)" : "");
988 printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
990 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
991 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
992 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
994 if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
995 printk(", Peak %d", p->video_bitrate_peak);
998 "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
1000 p->video_gop_size, p->video_b_frames,
1001 p->video_gop_closure ? "" : "No ");
1002 if (p->video_temporal_decimation)
1003 printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
1004 prefix, p->video_temporal_decimation);
1007 printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s",
1009 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
1010 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
1011 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
1012 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
1013 p->audio_mute ? " (muted)" : "");
1014 if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
1015 printk(", %s", cx2341x_menu_item(p,
1016 V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
1017 printk(", %s, %s\n",
1018 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
1019 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
1021 /* Encoding filters */
1022 printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
1024 cx2341x_menu_item(p,
1025 V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
1026 cx2341x_menu_item(p,
1027 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
1028 cx2341x_menu_item(p,
1029 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
1030 p->video_spatial_filter);
1032 if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480))
1035 printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
1037 cx2341x_menu_item(p,
1038 V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
1041 "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
1043 cx2341x_menu_item(p,
1044 V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
1045 p->video_luma_median_filter_bottom,
1046 p->video_luma_median_filter_top,
1047 p->video_chroma_median_filter_bottom,
1048 p->video_chroma_median_filter_top);
1050 EXPORT_SYMBOL(cx2341x_log_status);