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_AUDIO_MUTE,
55 V4L2_CID_MPEG_VIDEO_ENCODING,
56 V4L2_CID_MPEG_VIDEO_ASPECT,
57 V4L2_CID_MPEG_VIDEO_B_FRAMES,
58 V4L2_CID_MPEG_VIDEO_GOP_SIZE,
59 V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
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_VIDEO_MUTE,
65 V4L2_CID_MPEG_VIDEO_MUTE_YUV,
66 V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
67 V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
68 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
69 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
70 V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
71 V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
72 V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
73 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
74 V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
75 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
76 V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
77 V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
82 /* Map the control ID to the correct field in the cx2341x_mpeg_params
83 struct. Return -EINVAL if the ID is unknown, else return 0. */
84 static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
85 struct v4l2_ext_control *ctrl)
88 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
89 ctrl->value = params->audio_sampling_freq;
91 case V4L2_CID_MPEG_AUDIO_ENCODING:
92 ctrl->value = params->audio_encoding;
94 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
95 ctrl->value = params->audio_l2_bitrate;
97 case V4L2_CID_MPEG_AUDIO_MODE:
98 ctrl->value = params->audio_mode;
100 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
101 ctrl->value = params->audio_mode_extension;
103 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
104 ctrl->value = params->audio_emphasis;
106 case V4L2_CID_MPEG_AUDIO_CRC:
107 ctrl->value = params->audio_crc;
109 case V4L2_CID_MPEG_AUDIO_MUTE:
110 ctrl->value = params->audio_mute;
112 case V4L2_CID_MPEG_VIDEO_ENCODING:
113 ctrl->value = params->video_encoding;
115 case V4L2_CID_MPEG_VIDEO_ASPECT:
116 ctrl->value = params->video_aspect;
118 case V4L2_CID_MPEG_VIDEO_B_FRAMES:
119 ctrl->value = params->video_b_frames;
121 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
122 ctrl->value = params->video_gop_size;
124 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
125 ctrl->value = params->video_gop_closure;
127 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
128 ctrl->value = params->video_bitrate_mode;
130 case V4L2_CID_MPEG_VIDEO_BITRATE:
131 ctrl->value = params->video_bitrate;
133 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
134 ctrl->value = params->video_bitrate_peak;
136 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
137 ctrl->value = params->video_temporal_decimation;
139 case V4L2_CID_MPEG_VIDEO_MUTE:
140 ctrl->value = params->video_mute;
142 case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
143 ctrl->value = params->video_mute_yuv;
145 case V4L2_CID_MPEG_STREAM_TYPE:
146 ctrl->value = params->stream_type;
148 case V4L2_CID_MPEG_STREAM_VBI_FMT:
149 ctrl->value = params->stream_vbi_fmt;
151 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
152 ctrl->value = params->video_spatial_filter_mode;
154 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
155 ctrl->value = params->video_spatial_filter;
157 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
158 ctrl->value = params->video_luma_spatial_filter_type;
160 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
161 ctrl->value = params->video_chroma_spatial_filter_type;
163 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
164 ctrl->value = params->video_temporal_filter_mode;
166 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
167 ctrl->value = params->video_temporal_filter;
169 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
170 ctrl->value = params->video_median_filter_type;
172 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
173 ctrl->value = params->video_luma_median_filter_top;
175 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
176 ctrl->value = params->video_luma_median_filter_bottom;
178 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
179 ctrl->value = params->video_chroma_median_filter_top;
181 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
182 ctrl->value = params->video_chroma_median_filter_bottom;
184 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
185 ctrl->value = params->stream_insert_nav_packets;
193 /* Map the control ID to the correct field in the cx2341x_mpeg_params
194 struct. Return -EINVAL if the ID is unknown, else return 0. */
195 static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
196 struct v4l2_ext_control *ctrl)
199 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
200 params->audio_sampling_freq = ctrl->value;
202 case V4L2_CID_MPEG_AUDIO_ENCODING:
203 params->audio_encoding = ctrl->value;
205 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
206 params->audio_l2_bitrate = ctrl->value;
208 case V4L2_CID_MPEG_AUDIO_MODE:
209 params->audio_mode = ctrl->value;
211 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
212 params->audio_mode_extension = ctrl->value;
214 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
215 params->audio_emphasis = ctrl->value;
217 case V4L2_CID_MPEG_AUDIO_CRC:
218 params->audio_crc = ctrl->value;
220 case V4L2_CID_MPEG_AUDIO_MUTE:
221 params->audio_mute = ctrl->value;
223 case V4L2_CID_MPEG_VIDEO_ASPECT:
224 params->video_aspect = ctrl->value;
226 case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
227 int b = ctrl->value + 1;
228 int gop = params->video_gop_size;
229 params->video_b_frames = ctrl->value;
230 params->video_gop_size = b * ((gop + b - 1) / b);
231 /* Max GOP size = 34 */
232 while (params->video_gop_size > 34)
233 params->video_gop_size -= b;
236 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
237 int b = params->video_b_frames + 1;
238 int gop = ctrl->value;
239 params->video_gop_size = b * ((gop + b - 1) / b);
240 /* Max GOP size = 34 */
241 while (params->video_gop_size > 34)
242 params->video_gop_size -= b;
243 ctrl->value = params->video_gop_size;
246 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
247 params->video_gop_closure = ctrl->value;
249 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
250 /* MPEG-1 only allows CBR */
251 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
252 ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
254 params->video_bitrate_mode = ctrl->value;
256 case V4L2_CID_MPEG_VIDEO_BITRATE:
257 params->video_bitrate = ctrl->value;
259 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
260 params->video_bitrate_peak = ctrl->value;
262 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
263 params->video_temporal_decimation = ctrl->value;
265 case V4L2_CID_MPEG_VIDEO_MUTE:
266 params->video_mute = (ctrl->value != 0);
268 case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
269 params->video_mute_yuv = ctrl->value;
271 case V4L2_CID_MPEG_STREAM_TYPE:
272 params->stream_type = ctrl->value;
273 params->video_encoding =
274 (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
275 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
276 V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
277 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
278 /* MPEG-1 implies CBR */
279 params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
282 case V4L2_CID_MPEG_STREAM_VBI_FMT:
283 params->stream_vbi_fmt = ctrl->value;
285 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
286 params->video_spatial_filter_mode = ctrl->value;
288 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
289 params->video_spatial_filter = ctrl->value;
291 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
292 params->video_luma_spatial_filter_type = ctrl->value;
294 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
295 params->video_chroma_spatial_filter_type = ctrl->value;
297 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
298 params->video_temporal_filter_mode = ctrl->value;
300 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
301 params->video_temporal_filter = ctrl->value;
303 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
304 params->video_median_filter_type = ctrl->value;
306 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
307 params->video_luma_median_filter_top = ctrl->value;
309 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
310 params->video_luma_median_filter_bottom = ctrl->value;
312 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
313 params->video_chroma_median_filter_top = ctrl->value;
315 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
316 params->video_chroma_median_filter_bottom = ctrl->value;
318 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
319 params->stream_insert_nav_packets = ctrl->value;
327 static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
334 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
335 name = "Spatial Filter Mode";
337 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
338 name = "Spatial Filter";
340 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
341 name = "Spatial Luma Filter Type";
343 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
344 name = "Spatial Chroma Filter Type";
346 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
347 name = "Temporal Filter Mode";
349 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
350 name = "Temporal Filter";
352 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
353 name = "Median Filter Type";
355 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
356 name = "Median Luma Filter Maximum";
358 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
359 name = "Median Luma Filter Minimum";
361 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
362 name = "Median Chroma Filter Maximum";
364 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
365 name = "Median Chroma Filter Minimum";
367 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
368 name = "Insert Navigation Packets";
372 return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
375 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
376 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
377 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
378 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
379 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
380 qctrl->type = V4L2_CTRL_TYPE_MENU;
384 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
385 qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
391 qctrl->type = V4L2_CTRL_TYPE_INTEGER;
395 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
396 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
397 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
398 qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
401 qctrl->minimum = min;
402 qctrl->maximum = max;
404 qctrl->default_value = def;
405 qctrl->reserved[0] = qctrl->reserved[1] = 0;
406 snprintf(qctrl->name, sizeof(qctrl->name), name);
410 int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
415 case V4L2_CID_MPEG_AUDIO_ENCODING:
416 return v4l2_ctrl_query_fill(qctrl,
417 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
418 V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
419 V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
421 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
422 return v4l2_ctrl_query_fill(qctrl,
423 V4L2_MPEG_AUDIO_L2_BITRATE_192K,
424 V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
425 V4L2_MPEG_AUDIO_L2_BITRATE_224K);
427 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
428 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
431 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
432 err = v4l2_ctrl_query_fill_std(qctrl);
433 if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
434 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
437 case V4L2_CID_MPEG_VIDEO_ENCODING:
438 /* this setting is read-only for the cx2341x since the
439 V4L2_CID_MPEG_STREAM_TYPE really determines the
441 err = v4l2_ctrl_query_fill_std(qctrl);
443 qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
446 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
447 err = v4l2_ctrl_query_fill_std(qctrl);
448 if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
449 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
452 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
453 err = v4l2_ctrl_query_fill_std(qctrl);
454 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
455 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
458 case V4L2_CID_MPEG_STREAM_VBI_FMT:
459 if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
460 return v4l2_ctrl_query_fill_std(qctrl);
461 return cx2341x_ctrl_query_fill(qctrl,
462 V4L2_MPEG_STREAM_VBI_FMT_NONE,
463 V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
464 V4L2_MPEG_STREAM_VBI_FMT_NONE);
466 /* CX23415/6 specific */
467 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
468 return cx2341x_ctrl_query_fill(qctrl,
469 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
470 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
471 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
473 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
474 cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
475 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
476 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
477 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
480 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
481 cx2341x_ctrl_query_fill(qctrl,
482 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
483 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
484 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
485 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
486 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
489 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
490 cx2341x_ctrl_query_fill(qctrl,
491 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
492 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
493 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
494 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
495 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
498 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
499 return cx2341x_ctrl_query_fill(qctrl,
500 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
501 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
502 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
504 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
505 cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
506 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
507 if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
508 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
511 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
512 return cx2341x_ctrl_query_fill(qctrl,
513 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
514 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
515 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
517 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
518 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
519 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
520 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
521 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
524 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
525 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
526 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
527 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
528 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
531 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
532 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
533 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
534 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
535 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
538 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
539 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
540 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
541 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
542 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
545 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
546 return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
549 return v4l2_ctrl_query_fill_std(qctrl);
554 const char **cx2341x_ctrl_get_menu(u32 id)
556 static const char *mpeg_stream_type[] = {
557 "MPEG-2 Program Stream",
559 "MPEG-1 System Stream",
560 "MPEG-2 DVD-compatible Stream",
561 "MPEG-1 VCD-compatible Stream",
562 "MPEG-2 SVCD-compatible Stream",
566 static const char *cx2341x_video_spatial_filter_mode_menu[] = {
572 static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
577 "2D Symmetric non-separable",
581 static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
587 static const char *cx2341x_video_temporal_filter_mode_menu[] = {
593 static const char *cx2341x_video_median_filter_type_menu[] = {
597 "Horizontal/Vertical",
603 case V4L2_CID_MPEG_STREAM_TYPE:
604 return mpeg_stream_type;
605 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
606 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
608 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
609 return cx2341x_video_spatial_filter_mode_menu;
610 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
611 return cx2341x_video_luma_spatial_filter_type_menu;
612 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
613 return cx2341x_video_chroma_spatial_filter_type_menu;
614 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
615 return cx2341x_video_temporal_filter_mode_menu;
616 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
617 return cx2341x_video_median_filter_type_menu;
619 return v4l2_ctrl_get_menu(id);
623 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
625 params->audio_properties = (params->audio_sampling_freq << 0) |
626 ((3 - params->audio_encoding) << 2) |
627 ((1 + params->audio_l2_bitrate) << 4) |
628 (params->audio_mode << 8) |
629 (params->audio_mode_extension << 10) |
630 (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
632 params->audio_emphasis) << 12) |
633 (params->audio_crc << 14);
636 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
637 struct v4l2_ext_controls *ctrls, unsigned int cmd)
642 if (cmd == VIDIOC_G_EXT_CTRLS) {
643 for (i = 0; i < ctrls->count; i++) {
644 struct v4l2_ext_control *ctrl = ctrls->controls + i;
646 err = cx2341x_get_ctrl(params, ctrl);
648 ctrls->error_idx = i;
654 for (i = 0; i < ctrls->count; i++) {
655 struct v4l2_ext_control *ctrl = ctrls->controls + i;
656 struct v4l2_queryctrl qctrl;
657 const char **menu_items = NULL;
660 err = cx2341x_ctrl_query(params, &qctrl);
663 if (qctrl.type == V4L2_CTRL_TYPE_MENU)
664 menu_items = cx2341x_ctrl_get_menu(qctrl.id);
665 err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
668 err = cx2341x_set_ctrl(params, ctrl);
672 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
673 params->video_bitrate_peak < params->video_bitrate) {
675 ctrls->error_idx = ctrls->count;
678 ctrls->error_idx = i;
681 cx2341x_calc_audio_properties(params);
686 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
688 static struct cx2341x_mpeg_params default_params = {
691 .port = CX2341X_PORT_MEMORY,
697 .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
698 .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
699 .stream_insert_nav_packets = 0,
702 .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
703 .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
704 .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
705 .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
706 .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
707 .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
708 .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
712 .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
713 .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
715 .video_gop_size = 12,
716 .video_gop_closure = 1,
717 .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
718 .video_bitrate = 6000000,
719 .video_bitrate_peak = 8000000,
720 .video_temporal_decimation = 0,
722 .video_mute_yuv = 0x008080, /* YCbCr value for black */
724 /* encoding filters */
725 .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
726 .video_spatial_filter = 0,
727 .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
728 .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
729 .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
730 .video_temporal_filter = 8,
731 .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
732 .video_luma_median_filter_top = 255,
733 .video_luma_median_filter_bottom = 0,
734 .video_chroma_median_filter_top = 255,
735 .video_chroma_median_filter_bottom = 0,
739 cx2341x_calc_audio_properties(p);
742 static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
744 u32 data[CX2341X_MBOX_MAX_DATA];
748 va_start(vargs, args);
750 for (i = 0; i < args; i++) {
751 data[i] = va_arg(vargs, int);
754 return func(priv, cmd, args, 0, data);
757 int cx2341x_update(void *priv, cx2341x_mbox_func func,
758 const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
760 static int mpeg_stream_type[] = {
770 u16 temporal = new->video_temporal_filter;
772 cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
774 if (old == NULL || old->is_50hz != new->is_50hz) {
775 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
779 if (old == NULL || old->width != new->width || old->height != new->height ||
780 old->video_encoding != new->video_encoding) {
784 if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
788 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
792 if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
793 /* Adjust temporal filter if necessary. The problem with the temporal
794 filter is that it works well with full resolution capturing, but
795 not when the capture window is scaled (the filter introduces
796 a ghosting effect). So if the capture window is scaled, then
797 force the filter to 0.
799 For full resolution the filter really improves the video
800 quality, especially if the original video quality is suboptimal. */
804 if (old == NULL || old->stream_type != new->stream_type) {
805 err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
808 if (old == NULL || old->video_aspect != new->video_aspect) {
809 err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
812 if (old == NULL || old->video_b_frames != new->video_b_frames ||
813 old->video_gop_size != new->video_gop_size) {
814 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
815 new->video_gop_size, new->video_b_frames + 1);
818 if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
819 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
822 if (old == NULL || old->audio_properties != new->audio_properties) {
823 err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
826 if (old == NULL || old->audio_mute != new->audio_mute) {
827 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
830 if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
831 old->video_bitrate != new->video_bitrate ||
832 old->video_bitrate_peak != new->video_bitrate_peak) {
833 err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
834 new->video_bitrate_mode, new->video_bitrate,
835 new->video_bitrate_peak / 400, 0, 0);
838 if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
839 old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
840 old->video_median_filter_type != new->video_median_filter_type) {
841 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
842 new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
843 new->video_median_filter_type);
847 old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
848 old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
849 old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
850 old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
851 err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
852 new->video_luma_median_filter_bottom,
853 new->video_luma_median_filter_top,
854 new->video_chroma_median_filter_bottom,
855 new->video_chroma_median_filter_top);
859 old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
860 old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
861 err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
862 new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
866 old->video_spatial_filter != new->video_spatial_filter ||
867 old->video_temporal_filter != temporal) {
868 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
869 new->video_spatial_filter, temporal);
872 if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
873 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
874 new->video_temporal_decimation);
877 if (old == NULL || old->video_mute != new->video_mute ||
878 (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
879 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
882 if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
883 err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
889 static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
891 const char **menu = cx2341x_ctrl_get_menu(id);
892 struct v4l2_ext_control ctrl;
897 if (cx2341x_get_ctrl(p, &ctrl))
899 while (ctrl.value-- && *menu) menu++;
908 void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
910 int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
911 int temporal = p->video_temporal_filter;
914 printk(KERN_INFO "%s: Stream: %s",
916 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
917 if (p->stream_insert_nav_packets)
918 printk(" (with navigation packets)");
920 printk(KERN_INFO "%s: VBI Format: %s\n",
922 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
925 printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n",
927 p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
928 p->is_50hz ? 25 : 30,
929 (p->video_mute) ? " (muted)" : "");
930 printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
932 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
933 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
934 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
936 if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
937 printk(", Peak %d", p->video_bitrate_peak);
940 printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
942 p->video_gop_size, p->video_b_frames,
943 p->video_gop_closure ? "" : "No ");
944 if (p->video_temporal_decimation) {
945 printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
946 prefix, p->video_temporal_decimation);
950 printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s",
952 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
953 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
954 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
955 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
956 p->audio_mute ? " (muted)" : "");
957 if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
959 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
962 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
963 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
965 /* Encoding filters */
966 printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
968 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
969 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
970 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
971 p->video_spatial_filter);
972 if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
975 printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
977 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
979 printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
981 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
982 p->video_luma_median_filter_bottom,
983 p->video_luma_median_filter_top,
984 p->video_chroma_median_filter_bottom,
985 p->video_chroma_median_filter_top);
988 EXPORT_SYMBOL(cx2341x_fill_defaults);
989 EXPORT_SYMBOL(cx2341x_ctrl_query);
990 EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
991 EXPORT_SYMBOL(cx2341x_ext_ctrls);
992 EXPORT_SYMBOL(cx2341x_update);
993 EXPORT_SYMBOL(cx2341x_log_status);
994 EXPORT_SYMBOL(cx2341x_mpeg_ctrls);