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, int busy,
194 struct v4l2_ext_control *ctrl)
197 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:
208 params->audio_l2_bitrate = ctrl->value;
210 case V4L2_CID_MPEG_AUDIO_MODE:
211 params->audio_mode = ctrl->value;
213 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
214 params->audio_mode_extension = ctrl->value;
216 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
217 params->audio_emphasis = ctrl->value;
219 case V4L2_CID_MPEG_AUDIO_CRC:
220 params->audio_crc = ctrl->value;
222 case V4L2_CID_MPEG_AUDIO_MUTE:
223 params->audio_mute = ctrl->value;
225 case V4L2_CID_MPEG_VIDEO_ASPECT:
226 params->video_aspect = ctrl->value;
228 case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
229 int b = ctrl->value + 1;
230 int gop = params->video_gop_size;
231 params->video_b_frames = ctrl->value;
232 params->video_gop_size = b * ((gop + b - 1) / b);
233 /* Max GOP size = 34 */
234 while (params->video_gop_size > 34)
235 params->video_gop_size -= b;
238 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
239 int b = params->video_b_frames + 1;
240 int gop = ctrl->value;
241 params->video_gop_size = b * ((gop + b - 1) / b);
242 /* Max GOP size = 34 */
243 while (params->video_gop_size > 34)
244 params->video_gop_size -= b;
245 ctrl->value = params->video_gop_size;
248 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
249 params->video_gop_closure = ctrl->value;
251 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
254 /* MPEG-1 only allows CBR */
255 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
256 ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
258 params->video_bitrate_mode = ctrl->value;
260 case V4L2_CID_MPEG_VIDEO_BITRATE:
263 params->video_bitrate = ctrl->value;
265 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
268 params->video_bitrate_peak = ctrl->value;
270 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
271 params->video_temporal_decimation = ctrl->value;
273 case V4L2_CID_MPEG_VIDEO_MUTE:
274 params->video_mute = (ctrl->value != 0);
276 case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
277 params->video_mute_yuv = ctrl->value;
279 case V4L2_CID_MPEG_STREAM_TYPE:
282 params->stream_type = ctrl->value;
283 params->video_encoding =
284 (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
285 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
286 V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
287 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
288 /* MPEG-1 implies CBR */
289 params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
292 case V4L2_CID_MPEG_STREAM_VBI_FMT:
293 params->stream_vbi_fmt = ctrl->value;
295 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
296 params->video_spatial_filter_mode = ctrl->value;
298 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
299 params->video_spatial_filter = ctrl->value;
301 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
302 params->video_luma_spatial_filter_type = ctrl->value;
304 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
305 params->video_chroma_spatial_filter_type = ctrl->value;
307 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
308 params->video_temporal_filter_mode = ctrl->value;
310 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
311 params->video_temporal_filter = ctrl->value;
313 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
314 params->video_median_filter_type = ctrl->value;
316 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
317 params->video_luma_median_filter_top = ctrl->value;
319 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
320 params->video_luma_median_filter_bottom = ctrl->value;
322 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
323 params->video_chroma_median_filter_top = ctrl->value;
325 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
326 params->video_chroma_median_filter_bottom = ctrl->value;
328 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
329 params->stream_insert_nav_packets = ctrl->value;
337 static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
344 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
345 name = "Spatial Filter Mode";
347 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
348 name = "Spatial Filter";
350 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
351 name = "Spatial Luma Filter Type";
353 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
354 name = "Spatial Chroma Filter Type";
356 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
357 name = "Temporal Filter Mode";
359 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
360 name = "Temporal Filter";
362 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
363 name = "Median Filter Type";
365 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
366 name = "Median Luma Filter Maximum";
368 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
369 name = "Median Luma Filter Minimum";
371 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
372 name = "Median Chroma Filter Maximum";
374 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
375 name = "Median Chroma Filter Minimum";
377 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
378 name = "Insert Navigation Packets";
382 return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
385 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
386 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
387 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
388 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
389 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
390 qctrl->type = V4L2_CTRL_TYPE_MENU;
394 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
395 qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
401 qctrl->type = V4L2_CTRL_TYPE_INTEGER;
405 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
406 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
407 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
408 qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
411 qctrl->minimum = min;
412 qctrl->maximum = max;
414 qctrl->default_value = def;
415 qctrl->reserved[0] = qctrl->reserved[1] = 0;
416 snprintf(qctrl->name, sizeof(qctrl->name), name);
420 int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
425 case V4L2_CID_MPEG_AUDIO_ENCODING:
426 return v4l2_ctrl_query_fill(qctrl,
427 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
428 V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
429 V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
431 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
432 return v4l2_ctrl_query_fill(qctrl,
433 V4L2_MPEG_AUDIO_L2_BITRATE_192K,
434 V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
435 V4L2_MPEG_AUDIO_L2_BITRATE_224K);
437 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
438 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
441 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
442 err = v4l2_ctrl_query_fill_std(qctrl);
443 if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
444 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
447 case V4L2_CID_MPEG_VIDEO_ENCODING:
448 /* this setting is read-only for the cx2341x since the
449 V4L2_CID_MPEG_STREAM_TYPE really determines the
451 err = v4l2_ctrl_query_fill_std(qctrl);
453 qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
456 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
457 err = v4l2_ctrl_query_fill_std(qctrl);
458 if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
459 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
462 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
463 err = v4l2_ctrl_query_fill_std(qctrl);
464 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
465 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
468 case V4L2_CID_MPEG_STREAM_VBI_FMT:
469 if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
470 return v4l2_ctrl_query_fill_std(qctrl);
471 return cx2341x_ctrl_query_fill(qctrl,
472 V4L2_MPEG_STREAM_VBI_FMT_NONE,
473 V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
474 V4L2_MPEG_STREAM_VBI_FMT_NONE);
476 /* CX23415/6 specific */
477 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
478 return cx2341x_ctrl_query_fill(qctrl,
479 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
480 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
481 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
483 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
484 cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
485 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
486 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
487 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
490 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
491 cx2341x_ctrl_query_fill(qctrl,
492 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
493 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
494 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
495 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
496 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
499 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
500 cx2341x_ctrl_query_fill(qctrl,
501 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
502 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
503 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
504 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
505 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
508 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
509 return cx2341x_ctrl_query_fill(qctrl,
510 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
511 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
512 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
514 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
515 cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
516 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
517 if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
518 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
521 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
522 return cx2341x_ctrl_query_fill(qctrl,
523 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
524 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
525 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
527 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
528 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
529 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
530 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
531 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
534 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
535 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
536 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
537 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
538 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
541 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_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 == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
545 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
548 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
549 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
550 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
551 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
552 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
555 case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
556 return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
559 return v4l2_ctrl_query_fill_std(qctrl);
564 const char **cx2341x_ctrl_get_menu(u32 id)
566 static const char *mpeg_stream_type[] = {
567 "MPEG-2 Program Stream",
569 "MPEG-1 System Stream",
570 "MPEG-2 DVD-compatible Stream",
571 "MPEG-1 VCD-compatible Stream",
572 "MPEG-2 SVCD-compatible Stream",
576 static const char *cx2341x_video_spatial_filter_mode_menu[] = {
582 static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
587 "2D Symmetric non-separable",
591 static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
597 static const char *cx2341x_video_temporal_filter_mode_menu[] = {
603 static const char *cx2341x_video_median_filter_type_menu[] = {
607 "Horizontal/Vertical",
613 case V4L2_CID_MPEG_STREAM_TYPE:
614 return mpeg_stream_type;
615 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
616 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
618 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
619 return cx2341x_video_spatial_filter_mode_menu;
620 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
621 return cx2341x_video_luma_spatial_filter_type_menu;
622 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
623 return cx2341x_video_chroma_spatial_filter_type_menu;
624 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
625 return cx2341x_video_temporal_filter_mode_menu;
626 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
627 return cx2341x_video_median_filter_type_menu;
629 return v4l2_ctrl_get_menu(id);
633 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
635 params->audio_properties = (params->audio_sampling_freq << 0) |
636 ((3 - params->audio_encoding) << 2) |
637 ((1 + params->audio_l2_bitrate) << 4) |
638 (params->audio_mode << 8) |
639 (params->audio_mode_extension << 10) |
640 (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
642 params->audio_emphasis) << 12) |
643 (params->audio_crc << 14);
646 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
647 struct v4l2_ext_controls *ctrls, unsigned int cmd)
652 if (cmd == VIDIOC_G_EXT_CTRLS) {
653 for (i = 0; i < ctrls->count; i++) {
654 struct v4l2_ext_control *ctrl = ctrls->controls + i;
656 err = cx2341x_get_ctrl(params, ctrl);
658 ctrls->error_idx = i;
664 for (i = 0; i < ctrls->count; i++) {
665 struct v4l2_ext_control *ctrl = ctrls->controls + i;
666 struct v4l2_queryctrl qctrl;
667 const char **menu_items = NULL;
670 err = cx2341x_ctrl_query(params, &qctrl);
673 if (qctrl.type == V4L2_CTRL_TYPE_MENU)
674 menu_items = cx2341x_ctrl_get_menu(qctrl.id);
675 err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
678 err = cx2341x_set_ctrl(params, busy, ctrl);
682 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
683 params->video_bitrate_peak < params->video_bitrate) {
685 ctrls->error_idx = ctrls->count;
688 ctrls->error_idx = i;
691 cx2341x_calc_audio_properties(params);
696 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
698 static struct cx2341x_mpeg_params default_params = {
701 .port = CX2341X_PORT_MEMORY,
707 .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
708 .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
709 .stream_insert_nav_packets = 0,
712 .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
713 .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
714 .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
715 .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
716 .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
717 .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
718 .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
722 .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
723 .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
725 .video_gop_size = 12,
726 .video_gop_closure = 1,
727 .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
728 .video_bitrate = 6000000,
729 .video_bitrate_peak = 8000000,
730 .video_temporal_decimation = 0,
732 .video_mute_yuv = 0x008080, /* YCbCr value for black */
734 /* encoding filters */
735 .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
736 .video_spatial_filter = 0,
737 .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
738 .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
739 .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
740 .video_temporal_filter = 8,
741 .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
742 .video_luma_median_filter_top = 255,
743 .video_luma_median_filter_bottom = 0,
744 .video_chroma_median_filter_top = 255,
745 .video_chroma_median_filter_bottom = 0,
749 cx2341x_calc_audio_properties(p);
752 static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
754 u32 data[CX2341X_MBOX_MAX_DATA];
758 va_start(vargs, args);
760 for (i = 0; i < args; i++) {
761 data[i] = va_arg(vargs, int);
764 return func(priv, cmd, args, 0, data);
767 int cx2341x_update(void *priv, cx2341x_mbox_func func,
768 const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
770 static int mpeg_stream_type[] = {
780 u16 temporal = new->video_temporal_filter;
782 cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
784 if (old == NULL || old->is_50hz != new->is_50hz) {
785 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
789 if (old == NULL || old->width != new->width || old->height != new->height ||
790 old->video_encoding != new->video_encoding) {
794 if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
798 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
802 if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
803 /* Adjust temporal filter if necessary. The problem with the temporal
804 filter is that it works well with full resolution capturing, but
805 not when the capture window is scaled (the filter introduces
806 a ghosting effect). So if the capture window is scaled, then
807 force the filter to 0.
809 For full resolution the filter really improves the video
810 quality, especially if the original video quality is suboptimal. */
814 if (old == NULL || old->stream_type != new->stream_type) {
815 err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
818 if (old == NULL || old->video_aspect != new->video_aspect) {
819 err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
822 if (old == NULL || old->video_b_frames != new->video_b_frames ||
823 old->video_gop_size != new->video_gop_size) {
824 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
825 new->video_gop_size, new->video_b_frames + 1);
828 if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
829 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
832 if (old == NULL || old->audio_properties != new->audio_properties) {
833 err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
836 if (old == NULL || old->audio_mute != new->audio_mute) {
837 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
840 if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
841 old->video_bitrate != new->video_bitrate ||
842 old->video_bitrate_peak != new->video_bitrate_peak) {
843 err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
844 new->video_bitrate_mode, new->video_bitrate,
845 new->video_bitrate_peak / 400, 0, 0);
848 if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
849 old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
850 old->video_median_filter_type != new->video_median_filter_type) {
851 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
852 new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
853 new->video_median_filter_type);
857 old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
858 old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
859 old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
860 old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
861 err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
862 new->video_luma_median_filter_bottom,
863 new->video_luma_median_filter_top,
864 new->video_chroma_median_filter_bottom,
865 new->video_chroma_median_filter_top);
869 old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
870 old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
871 err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
872 new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
876 old->video_spatial_filter != new->video_spatial_filter ||
877 old->video_temporal_filter != temporal) {
878 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
879 new->video_spatial_filter, temporal);
882 if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
883 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
884 new->video_temporal_decimation);
887 if (old == NULL || old->video_mute != new->video_mute ||
888 (new->video_mute && old->video_mute_yuv != new->video_mute_yuv)) {
889 err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, new->video_mute | (new->video_mute_yuv << 8));
892 if (old == NULL || old->stream_insert_nav_packets != new->stream_insert_nav_packets) {
893 err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, 7, new->stream_insert_nav_packets);
899 static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
901 const char **menu = cx2341x_ctrl_get_menu(id);
902 struct v4l2_ext_control ctrl;
907 if (cx2341x_get_ctrl(p, &ctrl))
909 while (ctrl.value-- && *menu) menu++;
918 void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
920 int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
921 int temporal = p->video_temporal_filter;
924 printk(KERN_INFO "%s: Stream: %s",
926 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
927 if (p->stream_insert_nav_packets)
928 printk(" (with navigation packets)");
930 printk(KERN_INFO "%s: VBI Format: %s\n",
932 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
935 printk(KERN_INFO "%s: Video: %dx%d, %d fps%s\n",
937 p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
938 p->is_50hz ? 25 : 30,
939 (p->video_mute) ? " (muted)" : "");
940 printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
942 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
943 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
944 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
946 if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
947 printk(", Peak %d", p->video_bitrate_peak);
950 printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
952 p->video_gop_size, p->video_b_frames,
953 p->video_gop_closure ? "" : "No ");
954 if (p->video_temporal_decimation) {
955 printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
956 prefix, p->video_temporal_decimation);
960 printk(KERN_INFO "%s: Audio: %s, %s, %s, %s%s",
962 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
963 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
964 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
965 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
966 p->audio_mute ? " (muted)" : "");
967 if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
969 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
972 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
973 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
975 /* Encoding filters */
976 printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
978 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
979 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
980 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
981 p->video_spatial_filter);
982 if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480)) {
985 printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
987 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
989 printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
991 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
992 p->video_luma_median_filter_bottom,
993 p->video_luma_median_filter_top,
994 p->video_chroma_median_filter_bottom,
995 p->video_chroma_median_filter_top);
998 EXPORT_SYMBOL(cx2341x_fill_defaults);
999 EXPORT_SYMBOL(cx2341x_ctrl_query);
1000 EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
1001 EXPORT_SYMBOL(cx2341x_ext_ctrls);
1002 EXPORT_SYMBOL(cx2341x_update);
1003 EXPORT_SYMBOL(cx2341x_log_status);
1004 EXPORT_SYMBOL(cx2341x_mpeg_ctrls);