1/*
2 * cx2341x - generic code for cx23415/6 based devices
3 *
4 * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
5 *
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.
10 *
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.
15 *
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.
19 */
20
21
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
30#include <media/tuner.h>
31#include <media/cx2341x.h>
32#include <media/v4l2-common.h>
33
34MODULE_DESCRIPTION("cx23415/6 driver");
35MODULE_AUTHOR("Hans Verkuil");
36MODULE_LICENSE("GPL");
37
38static int debug = 0;
39module_param(debug, int, 0644);
40MODULE_PARM_DESC(debug, "Debug level (0-1)");
41
42const u32 cx2341x_mpeg_ctrls[] = {
43	V4L2_CID_MPEG_CLASS,
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,
77	0
78};
79
80
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. */
83static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
84		struct v4l2_ext_control *ctrl)
85{
86	switch (ctrl->id) {
87	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
88		ctrl->value = params->audio_sampling_freq;
89		break;
90	case V4L2_CID_MPEG_AUDIO_ENCODING:
91		ctrl->value = params->audio_encoding;
92		break;
93	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
94		ctrl->value = params->audio_l2_bitrate;
95		break;
96	case V4L2_CID_MPEG_AUDIO_MODE:
97		ctrl->value = params->audio_mode;
98		break;
99	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
100		ctrl->value = params->audio_mode_extension;
101		break;
102	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
103		ctrl->value = params->audio_emphasis;
104		break;
105	case V4L2_CID_MPEG_AUDIO_CRC:
106		ctrl->value = params->audio_crc;
107		break;
108	case V4L2_CID_MPEG_AUDIO_MUTE:
109		ctrl->value = params->audio_mute;
110		break;
111	case V4L2_CID_MPEG_VIDEO_ENCODING:
112		ctrl->value = params->video_encoding;
113		break;
114	case V4L2_CID_MPEG_VIDEO_ASPECT:
115		ctrl->value = params->video_aspect;
116		break;
117	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
118		ctrl->value = params->video_b_frames;
119		break;
120	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
121		ctrl->value = params->video_gop_size;
122		break;
123	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
124		ctrl->value = params->video_gop_closure;
125		break;
126	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
127		ctrl->value = params->video_bitrate_mode;
128		break;
129	case V4L2_CID_MPEG_VIDEO_BITRATE:
130		ctrl->value = params->video_bitrate;
131		break;
132	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
133		ctrl->value = params->video_bitrate_peak;
134		break;
135	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
136		ctrl->value = params->video_temporal_decimation;
137		break;
138	case V4L2_CID_MPEG_VIDEO_MUTE:
139		ctrl->value = params->video_mute;
140		break;
141	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
142		ctrl->value = params->video_mute_yuv;
143		break;
144	case V4L2_CID_MPEG_STREAM_TYPE:
145		ctrl->value = params->stream_type;
146		break;
147	case V4L2_CID_MPEG_STREAM_VBI_FMT:
148		ctrl->value = params->stream_vbi_fmt;
149		break;
150	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
151		ctrl->value = params->video_spatial_filter_mode;
152		break;
153	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
154		ctrl->value = params->video_spatial_filter;
155		break;
156	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
157		ctrl->value = params->video_luma_spatial_filter_type;
158		break;
159	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
160		ctrl->value = params->video_chroma_spatial_filter_type;
161		break;
162	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
163		ctrl->value = params->video_temporal_filter_mode;
164		break;
165	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
166		ctrl->value = params->video_temporal_filter;
167		break;
168	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
169		ctrl->value = params->video_median_filter_type;
170		break;
171	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
172		ctrl->value = params->video_luma_median_filter_top;
173		break;
174	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
175		ctrl->value = params->video_luma_median_filter_bottom;
176		break;
177	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
178		ctrl->value = params->video_chroma_median_filter_top;
179		break;
180	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
181		ctrl->value = params->video_chroma_median_filter_bottom;
182		break;
183	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
184		ctrl->value = params->stream_insert_nav_packets;
185		break;
186	default:
187		return -EINVAL;
188	}
189	return 0;
190}
191
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. */
194static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
195		struct v4l2_ext_control *ctrl)
196{
197	switch (ctrl->id) {
198	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
199		params->audio_sampling_freq = ctrl->value;
200		break;
201	case V4L2_CID_MPEG_AUDIO_ENCODING:
202		params->audio_encoding = ctrl->value;
203		break;
204	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
205		params->audio_l2_bitrate = ctrl->value;
206		break;
207	case V4L2_CID_MPEG_AUDIO_MODE:
208		params->audio_mode = ctrl->value;
209		break;
210	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
211		params->audio_mode_extension = ctrl->value;
212		break;
213	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
214		params->audio_emphasis = ctrl->value;
215		break;
216	case V4L2_CID_MPEG_AUDIO_CRC:
217		params->audio_crc = ctrl->value;
218		break;
219	case V4L2_CID_MPEG_AUDIO_MUTE:
220		params->audio_mute = ctrl->value;
221		break;
222	case V4L2_CID_MPEG_VIDEO_ASPECT:
223		params->video_aspect = ctrl->value;
224		break;
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;
233		break;
234	}
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;
243		break;
244	}
245	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
246		params->video_gop_closure = ctrl->value;
247		break;
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)
252			return -EINVAL;
253		params->video_bitrate_mode = ctrl->value;
254		break;
255	case V4L2_CID_MPEG_VIDEO_BITRATE:
256		params->video_bitrate = ctrl->value;
257		break;
258	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
259		params->video_bitrate_peak = ctrl->value;
260		break;
261	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
262		params->video_temporal_decimation = ctrl->value;
263		break;
264	case V4L2_CID_MPEG_VIDEO_MUTE:
265		params->video_mute = (ctrl->value != 0);
266		break;
267	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
268		params->video_mute_yuv = ctrl->value;
269		break;
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;
279		}
280		break;
281	case V4L2_CID_MPEG_STREAM_VBI_FMT:
282		params->stream_vbi_fmt = ctrl->value;
283		break;
284	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
285		params->video_spatial_filter_mode = ctrl->value;
286		break;
287	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
288		params->video_spatial_filter = ctrl->value;
289		break;
290	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
291		params->video_luma_spatial_filter_type = ctrl->value;
292		break;
293	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
294		params->video_chroma_spatial_filter_type = ctrl->value;
295		break;
296	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
297		params->video_temporal_filter_mode = ctrl->value;
298		break;
299	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
300		params->video_temporal_filter = ctrl->value;
301		break;
302	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
303		params->video_median_filter_type = ctrl->value;
304		break;
305	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
306		params->video_luma_median_filter_top = ctrl->value;
307		break;
308	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
309		params->video_luma_median_filter_bottom = ctrl->value;
310		break;
311	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
312		params->video_chroma_median_filter_top = ctrl->value;
313		break;
314	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
315		params->video_chroma_median_filter_bottom = ctrl->value;
316		break;
317	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
318		params->stream_insert_nav_packets = ctrl->value;
319		break;
320	default:
321		return -EINVAL;
322	}
323	return 0;
324}
325
326static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
327{
328	const char *name;
329
330	qctrl->flags = 0;
331	switch (qctrl->id) {
332	/* MPEG controls */
333	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
334		name = "Spatial Filter Mode";
335		break;
336	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
337		name = "Spatial Filter";
338		break;
339	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
340		name = "Spatial Luma Filter Type";
341		break;
342	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
343		name = "Spatial Chroma Filter Type";
344		break;
345	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
346		name = "Temporal Filter Mode";
347		break;
348	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
349		name = "Temporal Filter";
350		break;
351	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
352		name = "Median Filter Type";
353		break;
354	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
355		name = "Median Luma Filter Maximum";
356		break;
357	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
358		name = "Median Luma Filter Minimum";
359		break;
360	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
361		name = "Median Chroma Filter Maximum";
362		break;
363	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
364		name = "Median Chroma Filter Minimum";
365		break;
366	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
367		name = "Insert Navigation Packets";
368		break;
369
370	default:
371		return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
372	}
373	switch (qctrl->id) {
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;
380		min = 0;
381		step = 1;
382		break;
383	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
384		qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
385		min = 0;
386		max = 1;
387		step = 1;
388		break;
389	default:
390		qctrl->type = V4L2_CTRL_TYPE_INTEGER;
391		break;
392	}
393	switch (qctrl->id) {
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;
398		break;
399	}
400	qctrl->minimum = min;
401	qctrl->maximum = max;
402	qctrl->step = step;
403	qctrl->default_value = def;
404	qctrl->reserved[0] = qctrl->reserved[1] = 0;
405	snprintf(qctrl->name, sizeof(qctrl->name), name);
406	return 0;
407}
408
409int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
410{
411	int err;
412
413	switch (qctrl->id) {
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);
419
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);
425
426	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
427	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
428		return -EINVAL;
429
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;
434		return err;
435
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
439		   MPEG-1/2 setting */
440		err = v4l2_ctrl_query_fill_std(qctrl);
441		if (err == 0)
442			qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
443		return err;
444
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;
449		return err;
450
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;
455		return err;
456
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);
464
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);
471
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;
477		return 0;
478
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;
486		return 0;
487
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;
495		return 0;
496
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);
502
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;
508		return 0;
509
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);
515
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;
521		return 0;
522
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;
528		return 0;
529
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;
535		return 0;
536
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;
542		return 0;
543
544	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
545		return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1, 0);
546
547	default:
548		return v4l2_ctrl_query_fill_std(qctrl);
549
550	}
551}
552
553const char **cx2341x_ctrl_get_menu(u32 id)
554{
555	static const char *mpeg_stream_type[] = {
556		"MPEG-2 Program Stream",
557		"",
558		"MPEG-1 System Stream",
559		"MPEG-2 DVD-compatible Stream",
560		"MPEG-1 VCD-compatible Stream",
561		"MPEG-2 SVCD-compatible Stream",
562		NULL
563	};
564
565	static const char *cx2341x_video_spatial_filter_mode_menu[] = {
566		"Manual",
567		"Auto",
568		NULL
569	};
570
571	static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
572		"Off",
573		"1D Horizontal",
574		"1D Vertical",
575		"2D H/V Separable",
576		"2D Symmetric non-separable",
577		NULL
578	};
579
580	static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
581		"Off",
582		"1D Horizontal",
583		NULL
584	};
585
586	static const char *cx2341x_video_temporal_filter_mode_menu[] = {
587		"Manual",
588		"Auto",
589		NULL
590	};
591
592	static const char *cx2341x_video_median_filter_type_menu[] = {
593		"Off",
594		"Horizontal",
595		"Vertical",
596		"Horizontal/Vertical",
597		"Diagonal",
598		NULL
599	};
600
601	switch (id) {
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:
606		return NULL;
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;
617	default:
618		return v4l2_ctrl_get_menu(id);
619	}
620}
621
622static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
623{
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) ?
630		  3 :
631		  params->audio_emphasis) << 12) |
632		(params->audio_crc << 14);
633}
634
635int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
636		  struct v4l2_ext_controls *ctrls, unsigned int cmd)
637{
638	int err = 0;
639	int i;
640
641	if (cmd == VIDIOC_G_EXT_CTRLS) {
642		for (i = 0; i < ctrls->count; i++) {
643			struct v4l2_ext_control *ctrl = ctrls->controls + i;
644
645			err = cx2341x_get_ctrl(params, ctrl);
646			if (err) {
647				ctrls->error_idx = i;
648				break;
649			}
650		}
651		return err;
652	}
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;
657
658		qctrl.id = ctrl->id;
659		err = cx2341x_ctrl_query(params, &qctrl);
660		if (err)
661			break;
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);
665		if (err)
666			break;
667		err = cx2341x_set_ctrl(params, ctrl);
668		if (err)
669			break;
670	}
671	if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
672			params->video_bitrate_peak < params->video_bitrate) {
673		err = -ERANGE;
674		ctrls->error_idx = ctrls->count;
675	}
676	if (err) {
677		ctrls->error_idx = i;
678	}
679	else {
680		cx2341x_calc_audio_properties(params);
681	}
682	return err;
683}
684
685void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
686{
687	static struct cx2341x_mpeg_params default_params = {
688	/* misc */
689	.capabilities = 0,
690	.port = CX2341X_PORT_MEMORY,
691	.width = 720,
692	.height = 480,
693	.is_50hz = 0,
694
695	/* stream */
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,
699
700	/* audio */
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,
708	.audio_mute = 0,
709
710	/* video */
711	.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
712	.video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
713	.video_b_frames = 2,
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,
720	.video_mute = 0,
721	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
722
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,
735	};
736
737	*p = default_params;
738	cx2341x_calc_audio_properties(p);
739}
740
741static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
742{
743	u32 data[CX2341X_MBOX_MAX_DATA];
744	va_list vargs;
745	int i;
746
747	va_start(vargs, args);
748
749	for (i = 0; i < args; i++) {
750		data[i] = va_arg(vargs, int);
751	}
752	va_end(vargs);
753	return func(priv, cmd, args, 0, data);
754}
755
756int cx2341x_update(void *priv, cx2341x_mbox_func func,
757		const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
758{
759	static int mpeg_stream_type[] = {
760		0,	/* MPEG-2 PS */
761		1,	/* MPEG-2 TS */
762		2,	/* MPEG-1 SS */
763		14,	/* DVD */
764		11,	/* VCD */
765		12,	/* SVCD */
766	};
767
768	int err = 0;
769	u16 temporal = new->video_temporal_filter;
770
771	cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
772
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);
775		if (err) return err;
776	}
777
778	if (old == NULL || old->width != new->width || old->height != new->height ||
779			old->video_encoding != new->video_encoding) {
780		u16 w = new->width;
781		u16 h = new->height;
782
783		if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
784			w /= 2;
785			h /= 2;
786		}
787		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
788		if (err) return err;
789	}
790
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.
797
798		   For full resolution the filter really improves the video
799		   quality, especially if the original video quality is suboptimal. */
800		temporal = 0;
801	}
802
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]);
805		if (err) return err;
806	}
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);
809		if (err) return err;
810	}
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);
815		if (err) return err;
816	}
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);
819		if (err) return err;
820	}
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);
823		if (err) return err;
824	}
825	if (old == NULL || old->audio_mute != new->audio_mute) {
826		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute);
827		if (err) return err;
828	}
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);
835		if (err) return err;
836	}
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);
843		if (err) return err;
844	}
845	if (old == NULL ||
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);
855		if (err) return err;
856	}
857	if (old == NULL ||
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);
862		if (err) return err;
863	}
864	if (old == NULL ||
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);
869		if (err) return err;
870	}
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);
874		if (err) return err;
875	}
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));
879		if (err) return err;
880	}
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);
883		if (err) return err;
884	}
885	return 0;
886}
887
888static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
889{
890	const char **menu = cx2341x_ctrl_get_menu(id);
891	struct v4l2_ext_control ctrl;
892
893	if (menu == NULL)
894		goto invalid;
895	ctrl.id = id;
896	if (cx2341x_get_ctrl(p, &ctrl))
897		goto invalid;
898	while (ctrl.value-- && *menu) menu++;
899	if (*menu == NULL)
900		goto invalid;
901	return *menu;
902
903invalid:
904	return "<invalid>";
905}
906
907void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
908{
909	int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
910	int temporal = p->video_temporal_filter;
911
912	/* Stream */
913	printk(KERN_INFO "%s: Stream: %s",
914		prefix,
915		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
916	if (p->stream_insert_nav_packets)
917		printk(" (with navigation packets)");
918	printk("\n");
919	printk(KERN_INFO "%s: VBI Format: %s\n",
920		prefix,
921		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
922
923	/* Video */
924	printk(KERN_INFO "%s: Video:  %dx%d, %d fps%s\n",
925		prefix,
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",
930		prefix,
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),
934		p->video_bitrate);
935	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
936		printk(", Peak %d", p->video_bitrate_peak);
937	}
938	printk("\n");
939	printk(KERN_INFO "%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
940		prefix,
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);
946	}
947
948	/* Audio */
949	printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s%s",
950		prefix,
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) {
957		printk(", %s",
958			cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
959	}
960	printk(", %s, %s\n",
961		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
962		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
963
964	/* Encoding filters */
965	printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
966		prefix,
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)) {
972		temporal = 0;
973	}
974	printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
975		prefix,
976		cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
977		temporal);
978	printk(KERN_INFO "%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
979		prefix,
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);
985}
986
987EXPORT_SYMBOL(cx2341x_fill_defaults);
988EXPORT_SYMBOL(cx2341x_ctrl_query);
989EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
990EXPORT_SYMBOL(cx2341x_ext_ctrls);
991EXPORT_SYMBOL(cx2341x_update);
992EXPORT_SYMBOL(cx2341x_log_status);
993EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
994
995/*
996 * Local variables:
997 * c-basic-offset: 8
998 * End:
999 */
1000