• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/errno.h>
24 #include <linux/kernel.h>
25 #include <linux/init.h>
26 #include <linux/types.h>
27 #include <linux/videodev2.h>
28 
29 #include <media/tuner.h>
30 #include <media/cx2341x.h>
31 #include <media/v4l2-common.h>
32 
33 MODULE_DESCRIPTION("cx23415/6 driver");
34 MODULE_AUTHOR("Hans Verkuil");
35 MODULE_LICENSE("GPL");
36 
37 static int debug;
38 module_param(debug, int, 0644);
39 MODULE_PARM_DESC(debug, "Debug level (0-1)");
40 
41 const u32 cx2341x_mpeg_ctrls[] = {
42 	V4L2_CID_MPEG_CLASS,
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,
76 	0
77 };
78 EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
79 
80 static const struct cx2341x_mpeg_params default_params = {
81 	/* misc */
82 	.capabilities = 0,
83 	.port = CX2341X_PORT_MEMORY,
84 	.width = 720,
85 	.height = 480,
86 	.is_50hz = 0,
87 
88 	/* stream */
89 	.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
90 	.stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
91 	.stream_insert_nav_packets = 0,
92 
93 	/* audio */
94 	.audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
95 	.audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
96 	.audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
97 	.audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
98 	.audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
99 	.audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
100 	.audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
101 	.audio_mute = 0,
102 
103 	/* video */
104 	.video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
105 	.video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
106 	.video_b_frames = 2,
107 	.video_gop_size = 12,
108 	.video_gop_closure = 1,
109 	.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
110 	.video_bitrate = 6000000,
111 	.video_bitrate_peak = 8000000,
112 	.video_temporal_decimation = 0,
113 	.video_mute = 0,
114 	.video_mute_yuv = 0x008080,  /* YCbCr value for black */
115 
116 	/* encoding filters */
117 	.video_spatial_filter_mode =
118 		V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
119 	.video_spatial_filter = 0,
120 	.video_luma_spatial_filter_type =
121 		V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
122 	.video_chroma_spatial_filter_type =
123 		V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
124 	.video_temporal_filter_mode =
125 		V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
126 	.video_temporal_filter = 8,
127 	.video_median_filter_type =
128 		V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
129 	.video_luma_median_filter_top = 255,
130 	.video_luma_median_filter_bottom = 0,
131 	.video_chroma_median_filter_top = 255,
132 	.video_chroma_median_filter_bottom = 0,
133 };
134 
135 
136 /* Map the control ID to the correct field in the cx2341x_mpeg_params
137    struct. Return -EINVAL if the ID is unknown, else return 0. */
cx2341x_get_ctrl(const struct cx2341x_mpeg_params * params,struct v4l2_ext_control * ctrl)138 static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params,
139 		struct v4l2_ext_control *ctrl)
140 {
141 	switch (ctrl->id) {
142 	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
143 		ctrl->value = params->audio_sampling_freq;
144 		break;
145 	case V4L2_CID_MPEG_AUDIO_ENCODING:
146 		ctrl->value = params->audio_encoding;
147 		break;
148 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
149 		ctrl->value = params->audio_l2_bitrate;
150 		break;
151 	case V4L2_CID_MPEG_AUDIO_MODE:
152 		ctrl->value = params->audio_mode;
153 		break;
154 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
155 		ctrl->value = params->audio_mode_extension;
156 		break;
157 	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
158 		ctrl->value = params->audio_emphasis;
159 		break;
160 	case V4L2_CID_MPEG_AUDIO_CRC:
161 		ctrl->value = params->audio_crc;
162 		break;
163 	case V4L2_CID_MPEG_AUDIO_MUTE:
164 		ctrl->value = params->audio_mute;
165 		break;
166 	case V4L2_CID_MPEG_VIDEO_ENCODING:
167 		ctrl->value = params->video_encoding;
168 		break;
169 	case V4L2_CID_MPEG_VIDEO_ASPECT:
170 		ctrl->value = params->video_aspect;
171 		break;
172 	case V4L2_CID_MPEG_VIDEO_B_FRAMES:
173 		ctrl->value = params->video_b_frames;
174 		break;
175 	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
176 		ctrl->value = params->video_gop_size;
177 		break;
178 	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
179 		ctrl->value = params->video_gop_closure;
180 		break;
181 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
182 		ctrl->value = params->video_bitrate_mode;
183 		break;
184 	case V4L2_CID_MPEG_VIDEO_BITRATE:
185 		ctrl->value = params->video_bitrate;
186 		break;
187 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
188 		ctrl->value = params->video_bitrate_peak;
189 		break;
190 	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
191 		ctrl->value = params->video_temporal_decimation;
192 		break;
193 	case V4L2_CID_MPEG_VIDEO_MUTE:
194 		ctrl->value = params->video_mute;
195 		break;
196 	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
197 		ctrl->value = params->video_mute_yuv;
198 		break;
199 	case V4L2_CID_MPEG_STREAM_TYPE:
200 		ctrl->value = params->stream_type;
201 		break;
202 	case V4L2_CID_MPEG_STREAM_VBI_FMT:
203 		ctrl->value = params->stream_vbi_fmt;
204 		break;
205 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
206 		ctrl->value = params->video_spatial_filter_mode;
207 		break;
208 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
209 		ctrl->value = params->video_spatial_filter;
210 		break;
211 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
212 		ctrl->value = params->video_luma_spatial_filter_type;
213 		break;
214 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
215 		ctrl->value = params->video_chroma_spatial_filter_type;
216 		break;
217 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
218 		ctrl->value = params->video_temporal_filter_mode;
219 		break;
220 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
221 		ctrl->value = params->video_temporal_filter;
222 		break;
223 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
224 		ctrl->value = params->video_median_filter_type;
225 		break;
226 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
227 		ctrl->value = params->video_luma_median_filter_top;
228 		break;
229 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
230 		ctrl->value = params->video_luma_median_filter_bottom;
231 		break;
232 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
233 		ctrl->value = params->video_chroma_median_filter_top;
234 		break;
235 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
236 		ctrl->value = params->video_chroma_median_filter_bottom;
237 		break;
238 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
239 		ctrl->value = params->stream_insert_nav_packets;
240 		break;
241 	default:
242 		return -EINVAL;
243 	}
244 	return 0;
245 }
246 
247 /* Map the control ID to the correct field in the cx2341x_mpeg_params
248    struct. Return -EINVAL if the ID is unknown, else return 0. */
cx2341x_set_ctrl(struct cx2341x_mpeg_params * params,int busy,struct v4l2_ext_control * ctrl)249 static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
250 		struct v4l2_ext_control *ctrl)
251 {
252 	switch (ctrl->id) {
253 	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
254 		if (busy)
255 			return -EBUSY;
256 		params->audio_sampling_freq = ctrl->value;
257 		break;
258 	case V4L2_CID_MPEG_AUDIO_ENCODING:
259 		params->audio_encoding = ctrl->value;
260 		break;
261 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
262 		if (busy)
263 			return -EBUSY;
264 		params->audio_l2_bitrate = ctrl->value;
265 		break;
266 	case V4L2_CID_MPEG_AUDIO_MODE:
267 		params->audio_mode = ctrl->value;
268 		break;
269 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
270 		params->audio_mode_extension = ctrl->value;
271 		break;
272 	case V4L2_CID_MPEG_AUDIO_EMPHASIS:
273 		params->audio_emphasis = ctrl->value;
274 		break;
275 	case V4L2_CID_MPEG_AUDIO_CRC:
276 		params->audio_crc = ctrl->value;
277 		break;
278 	case V4L2_CID_MPEG_AUDIO_MUTE:
279 		params->audio_mute = ctrl->value;
280 		break;
281 	case V4L2_CID_MPEG_VIDEO_ASPECT:
282 		params->video_aspect = ctrl->value;
283 		break;
284 	case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
285 		int b = ctrl->value + 1;
286 		int gop = params->video_gop_size;
287 		params->video_b_frames = ctrl->value;
288 		params->video_gop_size = b * ((gop + b - 1) / b);
289 		/* Max GOP size = 34 */
290 		while (params->video_gop_size > 34)
291 			params->video_gop_size -= b;
292 		break;
293 	}
294 	case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
295 		int b = params->video_b_frames + 1;
296 		int gop = ctrl->value;
297 		params->video_gop_size = b * ((gop + b - 1) / b);
298 		/* Max GOP size = 34 */
299 		while (params->video_gop_size > 34)
300 			params->video_gop_size -= b;
301 		ctrl->value = params->video_gop_size;
302 		break;
303 	}
304 	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
305 		params->video_gop_closure = ctrl->value;
306 		break;
307 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
308 		if (busy)
309 			return -EBUSY;
310 		/* MPEG-1 only allows CBR */
311 		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
312 		    ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
313 			return -EINVAL;
314 		params->video_bitrate_mode = ctrl->value;
315 		break;
316 	case V4L2_CID_MPEG_VIDEO_BITRATE:
317 		if (busy)
318 			return -EBUSY;
319 		params->video_bitrate = ctrl->value;
320 		break;
321 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
322 		if (busy)
323 			return -EBUSY;
324 		params->video_bitrate_peak = ctrl->value;
325 		break;
326 	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
327 		params->video_temporal_decimation = ctrl->value;
328 		break;
329 	case V4L2_CID_MPEG_VIDEO_MUTE:
330 		params->video_mute = (ctrl->value != 0);
331 		break;
332 	case V4L2_CID_MPEG_VIDEO_MUTE_YUV:
333 		params->video_mute_yuv = ctrl->value;
334 		break;
335 	case V4L2_CID_MPEG_STREAM_TYPE:
336 		if (busy)
337 			return -EBUSY;
338 		params->stream_type = ctrl->value;
339 		params->video_encoding =
340 		    (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
341 		     params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
342 			V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
343 			V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
344 		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
345 			/* MPEG-1 implies CBR */
346 			params->video_bitrate_mode =
347 				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
348 		break;
349 	case V4L2_CID_MPEG_STREAM_VBI_FMT:
350 		params->stream_vbi_fmt = ctrl->value;
351 		break;
352 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
353 		params->video_spatial_filter_mode = ctrl->value;
354 		break;
355 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
356 		params->video_spatial_filter = ctrl->value;
357 		break;
358 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
359 		params->video_luma_spatial_filter_type = ctrl->value;
360 		break;
361 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
362 		params->video_chroma_spatial_filter_type = ctrl->value;
363 		break;
364 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
365 		params->video_temporal_filter_mode = ctrl->value;
366 		break;
367 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
368 		params->video_temporal_filter = ctrl->value;
369 		break;
370 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
371 		params->video_median_filter_type = ctrl->value;
372 		break;
373 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
374 		params->video_luma_median_filter_top = ctrl->value;
375 		break;
376 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
377 		params->video_luma_median_filter_bottom = ctrl->value;
378 		break;
379 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
380 		params->video_chroma_median_filter_top = ctrl->value;
381 		break;
382 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
383 		params->video_chroma_median_filter_bottom = ctrl->value;
384 		break;
385 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
386 		params->stream_insert_nav_packets = ctrl->value;
387 		break;
388 	default:
389 		return -EINVAL;
390 	}
391 	return 0;
392 }
393 
cx2341x_ctrl_query_fill(struct v4l2_queryctrl * qctrl,s32 min,s32 max,s32 step,s32 def)394 static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
395 				   s32 min, s32 max, s32 step, s32 def)
396 {
397 	const char *name;
398 
399 	qctrl->flags = 0;
400 	switch (qctrl->id) {
401 	/* MPEG controls */
402 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
403 		name = "Spatial Filter Mode";
404 		break;
405 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
406 		name = "Spatial Filter";
407 		break;
408 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
409 		name = "Spatial Luma Filter Type";
410 		break;
411 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
412 		name = "Spatial Chroma Filter Type";
413 		break;
414 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
415 		name = "Temporal Filter Mode";
416 		break;
417 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
418 		name = "Temporal Filter";
419 		break;
420 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
421 		name = "Median Filter Type";
422 		break;
423 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
424 		name = "Median Luma Filter Maximum";
425 		break;
426 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
427 		name = "Median Luma Filter Minimum";
428 		break;
429 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
430 		name = "Median Chroma Filter Maximum";
431 		break;
432 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
433 		name = "Median Chroma Filter Minimum";
434 		break;
435 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
436 		name = "Insert Navigation Packets";
437 		break;
438 
439 	default:
440 		return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
441 	}
442 	switch (qctrl->id) {
443 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
444 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
445 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
446 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
447 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
448 		qctrl->type = V4L2_CTRL_TYPE_MENU;
449 		min = 0;
450 		step = 1;
451 		break;
452 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
453 		qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
454 		min = 0;
455 		max = 1;
456 		step = 1;
457 		break;
458 	default:
459 		qctrl->type = V4L2_CTRL_TYPE_INTEGER;
460 		break;
461 	}
462 	switch (qctrl->id) {
463 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
464 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
465 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
466 		qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
467 		break;
468 	}
469 	qctrl->minimum = min;
470 	qctrl->maximum = max;
471 	qctrl->step = step;
472 	qctrl->default_value = def;
473 	qctrl->reserved[0] = qctrl->reserved[1] = 0;
474 	snprintf(qctrl->name, sizeof(qctrl->name), name);
475 	return 0;
476 }
477 
cx2341x_ctrl_query(const struct cx2341x_mpeg_params * params,struct v4l2_queryctrl * qctrl)478 int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
479 		       struct v4l2_queryctrl *qctrl)
480 {
481 	int err;
482 
483 	switch (qctrl->id) {
484 	case V4L2_CID_MPEG_AUDIO_ENCODING:
485 		return v4l2_ctrl_query_fill(qctrl,
486 				V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
487 				V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
488 				default_params.audio_encoding);
489 
490 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
491 		return v4l2_ctrl_query_fill(qctrl,
492 				V4L2_MPEG_AUDIO_L2_BITRATE_192K,
493 				V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
494 				default_params.audio_l2_bitrate);
495 
496 	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
497 	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
498 		return -EINVAL;
499 
500 	case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
501 		err = v4l2_ctrl_query_fill_std(qctrl);
502 		if (err == 0 &&
503 		    params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
504 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
505 		return err;
506 
507 	case V4L2_CID_MPEG_VIDEO_ENCODING:
508 		/* this setting is read-only for the cx2341x since the
509 		   V4L2_CID_MPEG_STREAM_TYPE really determines the
510 		   MPEG-1/2 setting */
511 		err = v4l2_ctrl_query_fill(qctrl,
512 					   V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
513 					   V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
514 					   V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
515 		if (err == 0)
516 			qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
517 		return err;
518 
519 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
520 		err = v4l2_ctrl_query_fill_std(qctrl);
521 		if (err == 0 &&
522 		    params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
523 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
524 		return err;
525 
526 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
527 		err = v4l2_ctrl_query_fill_std(qctrl);
528 		if (err == 0 &&
529 		    params->video_bitrate_mode ==
530 				V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
531 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
532 		return err;
533 
534 	case V4L2_CID_MPEG_STREAM_VBI_FMT:
535 		if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
536 			return v4l2_ctrl_query_fill_std(qctrl);
537 		return cx2341x_ctrl_query_fill(qctrl,
538 				V4L2_MPEG_STREAM_VBI_FMT_NONE,
539 				V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
540 				default_params.stream_vbi_fmt);
541 
542 	case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
543 		return v4l2_ctrl_query_fill(qctrl, 1, 34, 1,
544 				params->is_50hz ? 12 : 15);
545 
546 	/* CX23415/6 specific */
547 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
548 		return cx2341x_ctrl_query_fill(qctrl,
549 			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
550 			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
551 			default_params.video_spatial_filter_mode);
552 
553 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
554 		cx2341x_ctrl_query_fill(qctrl, 0, 15, 1,
555 				default_params.video_spatial_filter);
556 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
557 		if (params->video_spatial_filter_mode ==
558 			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
559 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
560 		return 0;
561 
562 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
563 		cx2341x_ctrl_query_fill(qctrl,
564 			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
565 			V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
566 			1,
567 			default_params.video_luma_spatial_filter_type);
568 		if (params->video_spatial_filter_mode ==
569 			    V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
570 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
571 		return 0;
572 
573 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
574 		cx2341x_ctrl_query_fill(qctrl,
575 		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
576 		    V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
577 		    1,
578 		    default_params.video_chroma_spatial_filter_type);
579 		if (params->video_spatial_filter_mode ==
580 			V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
581 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
582 		return 0;
583 
584 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
585 		return cx2341x_ctrl_query_fill(qctrl,
586 			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
587 			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
588 			default_params.video_temporal_filter_mode);
589 
590 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
591 		cx2341x_ctrl_query_fill(qctrl, 0, 31, 1,
592 				default_params.video_temporal_filter);
593 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
594 		if (params->video_temporal_filter_mode ==
595 			V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
596 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
597 		return 0;
598 
599 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
600 		return cx2341x_ctrl_query_fill(qctrl,
601 			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
602 			V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
603 			default_params.video_median_filter_type);
604 
605 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
606 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
607 				default_params.video_luma_median_filter_top);
608 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
609 		if (params->video_median_filter_type ==
610 				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
611 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
612 		return 0;
613 
614 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
615 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
616 				default_params.video_luma_median_filter_bottom);
617 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
618 		if (params->video_median_filter_type ==
619 				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
620 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
621 		return 0;
622 
623 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
624 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
625 				default_params.video_chroma_median_filter_top);
626 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
627 		if (params->video_median_filter_type ==
628 				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
629 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
630 		return 0;
631 
632 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
633 		cx2341x_ctrl_query_fill(qctrl, 0, 255, 1,
634 			default_params.video_chroma_median_filter_bottom);
635 		qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
636 		if (params->video_median_filter_type ==
637 				V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
638 			qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
639 		return 0;
640 
641 	case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
642 		return cx2341x_ctrl_query_fill(qctrl, 0, 1, 1,
643 				default_params.stream_insert_nav_packets);
644 
645 	default:
646 		return v4l2_ctrl_query_fill_std(qctrl);
647 
648 	}
649 }
650 EXPORT_SYMBOL(cx2341x_ctrl_query);
651 
cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params * p,u32 id)652 const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
653 {
654 	static const char *mpeg_stream_type_without_ts[] = {
655 		"MPEG-2 Program Stream",
656 		"",
657 		"MPEG-1 System Stream",
658 		"MPEG-2 DVD-compatible Stream",
659 		"MPEG-1 VCD-compatible Stream",
660 		"MPEG-2 SVCD-compatible Stream",
661 		NULL
662 	};
663 
664 	static const char *mpeg_stream_type_with_ts[] = {
665 		"MPEG-2 Program Stream",
666 		"MPEG-2 Transport Stream",
667 		"MPEG-1 System Stream",
668 		"MPEG-2 DVD-compatible Stream",
669 		"MPEG-1 VCD-compatible Stream",
670 		"MPEG-2 SVCD-compatible Stream",
671 		NULL
672 	};
673 
674 	static const char *cx2341x_video_spatial_filter_mode_menu[] = {
675 		"Manual",
676 		"Auto",
677 		NULL
678 	};
679 
680 	static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
681 		"Off",
682 		"1D Horizontal",
683 		"1D Vertical",
684 		"2D H/V Separable",
685 		"2D Symmetric non-separable",
686 		NULL
687 	};
688 
689 	static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
690 		"Off",
691 		"1D Horizontal",
692 		NULL
693 	};
694 
695 	static const char *cx2341x_video_temporal_filter_mode_menu[] = {
696 		"Manual",
697 		"Auto",
698 		NULL
699 	};
700 
701 	static const char *cx2341x_video_median_filter_type_menu[] = {
702 		"Off",
703 		"Horizontal",
704 		"Vertical",
705 		"Horizontal/Vertical",
706 		"Diagonal",
707 		NULL
708 	};
709 
710 	switch (id) {
711 	case V4L2_CID_MPEG_STREAM_TYPE:
712 		return (p->capabilities & CX2341X_CAP_HAS_TS) ?
713 			mpeg_stream_type_with_ts : mpeg_stream_type_without_ts;
714 	case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
715 	case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
716 		return NULL;
717 	case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
718 		return cx2341x_video_spatial_filter_mode_menu;
719 	case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
720 		return cx2341x_video_luma_spatial_filter_type_menu;
721 	case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
722 		return cx2341x_video_chroma_spatial_filter_type_menu;
723 	case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
724 		return cx2341x_video_temporal_filter_mode_menu;
725 	case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
726 		return cx2341x_video_median_filter_type_menu;
727 	default:
728 		return v4l2_ctrl_get_menu(id);
729 	}
730 }
731 EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
732 
cx2341x_calc_audio_properties(struct cx2341x_mpeg_params * params)733 static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
734 {
735 	params->audio_properties = (params->audio_sampling_freq << 0) |
736 		((3 - params->audio_encoding) << 2) |
737 		((1 + params->audio_l2_bitrate) << 4) |
738 		(params->audio_mode << 8) |
739 		(params->audio_mode_extension << 10) |
740 		(((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
741 		  ? 3 : params->audio_emphasis) << 12) |
742 		(params->audio_crc << 14);
743 }
744 
cx2341x_ext_ctrls(struct cx2341x_mpeg_params * params,int busy,struct v4l2_ext_controls * ctrls,unsigned int cmd)745 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
746 		  struct v4l2_ext_controls *ctrls, unsigned int cmd)
747 {
748 	int err = 0;
749 	int i;
750 
751 	if (cmd == VIDIOC_G_EXT_CTRLS) {
752 		for (i = 0; i < ctrls->count; i++) {
753 			struct v4l2_ext_control *ctrl = ctrls->controls + i;
754 
755 			err = cx2341x_get_ctrl(params, ctrl);
756 			if (err) {
757 				ctrls->error_idx = i;
758 				break;
759 			}
760 		}
761 		return err;
762 	}
763 	for (i = 0; i < ctrls->count; i++) {
764 		struct v4l2_ext_control *ctrl = ctrls->controls + i;
765 		struct v4l2_queryctrl qctrl;
766 		const char **menu_items = NULL;
767 
768 		qctrl.id = ctrl->id;
769 		err = cx2341x_ctrl_query(params, &qctrl);
770 		if (err)
771 			break;
772 		if (qctrl.type == V4L2_CTRL_TYPE_MENU)
773 			menu_items = cx2341x_ctrl_get_menu(params, qctrl.id);
774 		err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
775 		if (err)
776 			break;
777 		err = cx2341x_set_ctrl(params, busy, ctrl);
778 		if (err)
779 			break;
780 	}
781 	if (err == 0 &&
782 	    params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
783 	    params->video_bitrate_peak < params->video_bitrate) {
784 		err = -ERANGE;
785 		ctrls->error_idx = ctrls->count;
786 	}
787 	if (err)
788 		ctrls->error_idx = i;
789 	else
790 		cx2341x_calc_audio_properties(params);
791 	return err;
792 }
793 EXPORT_SYMBOL(cx2341x_ext_ctrls);
794 
cx2341x_fill_defaults(struct cx2341x_mpeg_params * p)795 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
796 {
797 	*p = default_params;
798 	cx2341x_calc_audio_properties(p);
799 }
800 EXPORT_SYMBOL(cx2341x_fill_defaults);
801 
cx2341x_api(void * priv,cx2341x_mbox_func func,u32 cmd,int args,...)802 static int cx2341x_api(void *priv, cx2341x_mbox_func func,
803 		       u32 cmd, int args, ...)
804 {
805 	u32 data[CX2341X_MBOX_MAX_DATA];
806 	va_list vargs;
807 	int i;
808 
809 	va_start(vargs, args);
810 
811 	for (i = 0; i < args; i++)
812 		data[i] = va_arg(vargs, int);
813 	va_end(vargs);
814 	return func(priv, cmd, args, 0, data);
815 }
816 
817 #define NEQ(field) (old->field != new->field)
818 
cx2341x_update(void * priv,cx2341x_mbox_func func,const struct cx2341x_mpeg_params * old,const struct cx2341x_mpeg_params * new)819 int cx2341x_update(void *priv, cx2341x_mbox_func func,
820 		   const struct cx2341x_mpeg_params *old,
821 		   const struct cx2341x_mpeg_params *new)
822 {
823 	static int mpeg_stream_type[] = {
824 		0,	/* MPEG-2 PS */
825 		1,	/* MPEG-2 TS */
826 		2,	/* MPEG-1 SS */
827 		14,	/* DVD */
828 		11,	/* VCD */
829 		12,	/* SVCD */
830 	};
831 
832 	int err = 0;
833 	int force = (old == NULL);
834 	u16 temporal = new->video_temporal_filter;
835 
836 	cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
837 
838 	if (force || NEQ(is_50hz)) {
839 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1,
840 				  new->is_50hz);
841 		if (err) return err;
842 	}
843 
844 	if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) {
845 		u16 w = new->width;
846 		u16 h = new->height;
847 
848 		if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
849 			w /= 2;
850 			h /= 2;
851 		}
852 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2,
853 				  h, w);
854 		if (err) return err;
855 	}
856 
857 	if (new->width != 720 || new->height != (new->is_50hz ? 576 : 480)) {
858 		/* Adjust temporal filter if necessary. The problem with the
859 		   temporal filter is that it works well with full resolution
860 		   capturing, but not when the capture window is scaled (the
861 		   filter introduces a ghosting effect). So if the capture
862 		   window is scaled, then force the filter to 0.
863 
864 		   For full resolution the filter really improves the video
865 		   quality, especially if the original video quality is
866 		   suboptimal. */
867 		temporal = 0;
868 	}
869 
870 	if (force || NEQ(stream_type)) {
871 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1,
872 				  mpeg_stream_type[new->stream_type]);
873 		if (err) return err;
874 	}
875 	if (force || NEQ(video_aspect)) {
876 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1,
877 				  1 + new->video_aspect);
878 		if (err) return err;
879 	}
880 	if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) {
881 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
882 				new->video_gop_size, new->video_b_frames + 1);
883 		if (err) return err;
884 	}
885 	if (force || NEQ(video_gop_closure)) {
886 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1,
887 				  new->video_gop_closure);
888 		if (err) return err;
889 	}
890 	if (force || NEQ(audio_properties)) {
891 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES,
892 				  1, new->audio_properties);
893 		if (err) return err;
894 	}
895 	if (force || NEQ(audio_mute)) {
896 		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1,
897 				  new->audio_mute);
898 		if (err) return err;
899 	}
900 	if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) ||
901 						NEQ(video_bitrate_peak)) {
902 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
903 				new->video_bitrate_mode, new->video_bitrate,
904 				new->video_bitrate_peak / 400, 0, 0);
905 		if (err) return err;
906 	}
907 	if (force || NEQ(video_spatial_filter_mode) ||
908 		     NEQ(video_temporal_filter_mode) ||
909 		     NEQ(video_median_filter_type)) {
910 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE,
911 				  2, new->video_spatial_filter_mode |
912 					(new->video_temporal_filter_mode << 1),
913 				new->video_median_filter_type);
914 		if (err) return err;
915 	}
916 	if (force || NEQ(video_luma_median_filter_bottom) ||
917 		     NEQ(video_luma_median_filter_top) ||
918 		     NEQ(video_chroma_median_filter_bottom) ||
919 		     NEQ(video_chroma_median_filter_top)) {
920 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
921 				new->video_luma_median_filter_bottom,
922 				new->video_luma_median_filter_top,
923 				new->video_chroma_median_filter_bottom,
924 				new->video_chroma_median_filter_top);
925 		if (err) return err;
926 	}
927 	if (force || NEQ(video_luma_spatial_filter_type) ||
928 		     NEQ(video_chroma_spatial_filter_type)) {
929 		err = cx2341x_api(priv, func,
930 				  CX2341X_ENC_SET_SPATIAL_FILTER_TYPE,
931 				  2, new->video_luma_spatial_filter_type,
932 				  new->video_chroma_spatial_filter_type);
933 		if (err) return err;
934 	}
935 	if (force || NEQ(video_spatial_filter) ||
936 		     old->video_temporal_filter != temporal) {
937 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS,
938 				  2, new->video_spatial_filter, temporal);
939 		if (err) return err;
940 	}
941 	if (force || NEQ(video_temporal_decimation)) {
942 		err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE,
943 				  1, new->video_temporal_decimation);
944 		if (err) return err;
945 	}
946 	if (force || NEQ(video_mute) ||
947 		(new->video_mute && NEQ(video_mute_yuv))) {
948 		err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1,
949 				new->video_mute | (new->video_mute_yuv << 8));
950 		if (err) return err;
951 	}
952 	if (force || NEQ(stream_insert_nav_packets)) {
953 		err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2,
954 				7, new->stream_insert_nav_packets);
955 		if (err) return err;
956 	}
957 	return 0;
958 }
959 EXPORT_SYMBOL(cx2341x_update);
960 
cx2341x_menu_item(const struct cx2341x_mpeg_params * p,u32 id)961 static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
962 {
963 	const char **menu = cx2341x_ctrl_get_menu(p, id);
964 	struct v4l2_ext_control ctrl;
965 
966 	if (menu == NULL)
967 		goto invalid;
968 	ctrl.id = id;
969 	if (cx2341x_get_ctrl(p, &ctrl))
970 		goto invalid;
971 	while (ctrl.value-- && *menu) menu++;
972 	if (*menu == NULL)
973 		goto invalid;
974 	return *menu;
975 
976 invalid:
977 	return "<invalid>";
978 }
979 
cx2341x_log_status(const struct cx2341x_mpeg_params * p,const char * prefix)980 void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
981 {
982 	int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
983 	int temporal = p->video_temporal_filter;
984 
985 	/* Stream */
986 	printk(KERN_INFO "%s: Stream: %s",
987 		prefix,
988 		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
989 	if (p->stream_insert_nav_packets)
990 		printk(" (with navigation packets)");
991 	printk("\n");
992 	printk(KERN_INFO "%s: VBI Format: %s\n",
993 		prefix,
994 		cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
995 
996 	/* Video */
997 	printk(KERN_INFO "%s: Video:  %dx%d, %d fps%s\n",
998 		prefix,
999 		p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
1000 		p->is_50hz ? 25 : 30,
1001 		(p->video_mute) ? " (muted)" : "");
1002 	printk(KERN_INFO "%s: Video:  %s, %s, %s, %d",
1003 		prefix,
1004 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
1005 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
1006 		cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
1007 		p->video_bitrate);
1008 	if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
1009 		printk(", Peak %d", p->video_bitrate_peak);
1010 	printk("\n");
1011 	printk(KERN_INFO
1012 		"%s: Video:  GOP Size %d, %d B-Frames, %sGOP Closure\n",
1013 		prefix,
1014 		p->video_gop_size, p->video_b_frames,
1015 		p->video_gop_closure ? "" : "No ");
1016 	if (p->video_temporal_decimation)
1017 		printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
1018 			prefix, p->video_temporal_decimation);
1019 
1020 	/* Audio */
1021 	printk(KERN_INFO "%s: Audio:  %s, %s, %s, %s%s",
1022 		prefix,
1023 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
1024 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
1025 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
1026 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE),
1027 		p->audio_mute ? " (muted)" : "");
1028 	if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
1029 		printk(", %s", cx2341x_menu_item(p,
1030 				V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
1031 	printk(", %s, %s\n",
1032 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
1033 		cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
1034 
1035 	/* Encoding filters */
1036 	printk(KERN_INFO "%s: Spatial Filter:  %s, Luma %s, Chroma %s, %d\n",
1037 		prefix,
1038 		cx2341x_menu_item(p,
1039 		    V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
1040 		cx2341x_menu_item(p,
1041 		    V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
1042 		cx2341x_menu_item(p,
1043 		    V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
1044 		p->video_spatial_filter);
1045 
1046 	if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480))
1047 		temporal = 0;
1048 
1049 	printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
1050 		prefix,
1051 		cx2341x_menu_item(p,
1052 			V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
1053 		temporal);
1054 	printk(KERN_INFO
1055 		"%s: Median Filter:   %s, Luma [%d, %d], Chroma [%d, %d]\n",
1056 		prefix,
1057 		cx2341x_menu_item(p,
1058 			V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
1059 		p->video_luma_median_filter_bottom,
1060 		p->video_luma_median_filter_top,
1061 		p->video_chroma_median_filter_bottom,
1062 		p->video_chroma_median_filter_top);
1063 }
1064 EXPORT_SYMBOL(cx2341x_log_status);
1065 
1066 /*
1067  * Local variables:
1068  * c-basic-offset: 8
1069  * End:
1070  */
1071 
1072