aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx2341x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx2341x.c')
-rw-r--r--drivers/media/video/cx2341x.c873
1 files changed, 873 insertions, 0 deletions
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
new file mode 100644
index 000000000000..f4d58d52e355
--- /dev/null
+++ b/drivers/media/video/cx2341x.c
@@ -0,0 +1,873 @@
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#include <linux/i2c.h>
30
31#include <media/tuner.h>
32#include <media/cx2341x.h>
33#include <media/v4l2-common.h>
34
35MODULE_DESCRIPTION("cx23415/6 driver");
36MODULE_AUTHOR("Hans Verkuil");
37MODULE_LICENSE("GPL");
38
39static int debug = 0;
40module_param(debug, int, 0644);
41MODULE_PARM_DESC(debug, "Debug level (0-1)");
42
43
44/* Map the control ID to the correct field in the cx2341x_mpeg_params
45 struct. Return -EINVAL if the ID is unknown, else return 0. */
46static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
47 struct v4l2_ext_control *ctrl)
48{
49 switch (ctrl->id) {
50 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
51 ctrl->value = params->audio_sampling_freq;
52 break;
53 case V4L2_CID_MPEG_AUDIO_ENCODING:
54 ctrl->value = params->audio_encoding;
55 break;
56 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
57 ctrl->value = params->audio_l2_bitrate;
58 break;
59 case V4L2_CID_MPEG_AUDIO_MODE:
60 ctrl->value = params->audio_mode;
61 break;
62 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
63 ctrl->value = params->audio_mode_extension;
64 break;
65 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
66 ctrl->value = params->audio_emphasis;
67 break;
68 case V4L2_CID_MPEG_AUDIO_CRC:
69 ctrl->value = params->audio_crc;
70 break;
71 case V4L2_CID_MPEG_VIDEO_ENCODING:
72 ctrl->value = params->video_encoding;
73 break;
74 case V4L2_CID_MPEG_VIDEO_ASPECT:
75 ctrl->value = params->video_aspect;
76 break;
77 case V4L2_CID_MPEG_VIDEO_B_FRAMES:
78 ctrl->value = params->video_b_frames;
79 break;
80 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
81 ctrl->value = params->video_gop_size;
82 break;
83 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
84 ctrl->value = params->video_gop_closure;
85 break;
86 case V4L2_CID_MPEG_VIDEO_PULLDOWN:
87 ctrl->value = params->video_pulldown;
88 break;
89 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
90 ctrl->value = params->video_bitrate_mode;
91 break;
92 case V4L2_CID_MPEG_VIDEO_BITRATE:
93 ctrl->value = params->video_bitrate;
94 break;
95 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
96 ctrl->value = params->video_bitrate_peak;
97 break;
98 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
99 ctrl->value = params->video_temporal_decimation;
100 break;
101 case V4L2_CID_MPEG_STREAM_TYPE:
102 ctrl->value = params->stream_type;
103 break;
104 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
105 ctrl->value = params->video_spatial_filter_mode;
106 break;
107 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
108 ctrl->value = params->video_spatial_filter;
109 break;
110 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
111 ctrl->value = params->video_luma_spatial_filter_type;
112 break;
113 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
114 ctrl->value = params->video_chroma_spatial_filter_type;
115 break;
116 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
117 ctrl->value = params->video_temporal_filter_mode;
118 break;
119 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
120 ctrl->value = params->video_temporal_filter;
121 break;
122 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
123 ctrl->value = params->video_median_filter_type;
124 break;
125 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
126 ctrl->value = params->video_luma_median_filter_top;
127 break;
128 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
129 ctrl->value = params->video_luma_median_filter_bottom;
130 break;
131 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
132 ctrl->value = params->video_chroma_median_filter_top;
133 break;
134 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
135 ctrl->value = params->video_chroma_median_filter_bottom;
136 break;
137 default:
138 return -EINVAL;
139 }
140 return 0;
141}
142
143/* Map the control ID to the correct field in the cx2341x_mpeg_params
144 struct. Return -EINVAL if the ID is unknown, else return 0. */
145static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
146 struct v4l2_ext_control *ctrl)
147{
148 switch (ctrl->id) {
149 case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
150 params->audio_sampling_freq = ctrl->value;
151 break;
152 case V4L2_CID_MPEG_AUDIO_ENCODING:
153 params->audio_encoding = ctrl->value;
154 break;
155 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
156 params->audio_l2_bitrate = ctrl->value;
157 break;
158 case V4L2_CID_MPEG_AUDIO_MODE:
159 params->audio_mode = ctrl->value;
160 break;
161 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
162 params->audio_mode_extension = ctrl->value;
163 break;
164 case V4L2_CID_MPEG_AUDIO_EMPHASIS:
165 params->audio_emphasis = ctrl->value;
166 break;
167 case V4L2_CID_MPEG_AUDIO_CRC:
168 params->audio_crc = ctrl->value;
169 break;
170 case V4L2_CID_MPEG_VIDEO_ASPECT:
171 params->video_aspect = ctrl->value;
172 break;
173 case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
174 int b = ctrl->value + 1;
175 int gop = params->video_gop_size;
176 params->video_b_frames = ctrl->value;
177 params->video_gop_size = b * ((gop + b - 1) / b);
178 /* Max GOP size = 34 */
179 while (params->video_gop_size > 34)
180 params->video_gop_size -= b;
181 break;
182 }
183 case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
184 int b = params->video_b_frames + 1;
185 int gop = ctrl->value;
186 params->video_gop_size = b * ((gop + b - 1) / b);
187 /* Max GOP size = 34 */
188 while (params->video_gop_size > 34)
189 params->video_gop_size -= b;
190 ctrl->value = params->video_gop_size;
191 break;
192 }
193 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
194 params->video_gop_closure = ctrl->value;
195 break;
196 case V4L2_CID_MPEG_VIDEO_PULLDOWN:
197 params->video_pulldown = ctrl->value;
198 break;
199 case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
200 /* MPEG-1 only allows CBR */
201 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
202 ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
203 return -EINVAL;
204 params->video_bitrate_mode = ctrl->value;
205 break;
206 case V4L2_CID_MPEG_VIDEO_BITRATE:
207 params->video_bitrate = ctrl->value;
208 break;
209 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
210 params->video_bitrate_peak = ctrl->value;
211 break;
212 case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
213 params->video_temporal_decimation = ctrl->value;
214 break;
215 case V4L2_CID_MPEG_STREAM_TYPE:
216 params->stream_type = ctrl->value;
217 params->video_encoding =
218 (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
219 params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
220 V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
221 if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
222 /* MPEG-1 implies CBR */
223 params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
224 }
225 break;
226 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
227 params->video_spatial_filter_mode = ctrl->value;
228 break;
229 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
230 params->video_spatial_filter = ctrl->value;
231 break;
232 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
233 params->video_luma_spatial_filter_type = ctrl->value;
234 break;
235 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
236 params->video_chroma_spatial_filter_type = ctrl->value;
237 break;
238 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
239 params->video_temporal_filter_mode = ctrl->value;
240 break;
241 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
242 params->video_temporal_filter = ctrl->value;
243 break;
244 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
245 params->video_median_filter_type = ctrl->value;
246 break;
247 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
248 params->video_luma_median_filter_top = ctrl->value;
249 break;
250 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
251 params->video_luma_median_filter_bottom = ctrl->value;
252 break;
253 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
254 params->video_chroma_median_filter_top = ctrl->value;
255 break;
256 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
257 params->video_chroma_median_filter_bottom = ctrl->value;
258 break;
259 default:
260 return -EINVAL;
261 }
262 return 0;
263}
264
265static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
266{
267 const char *name;
268
269 qctrl->flags = 0;
270 switch (qctrl->id) {
271 /* MPEG controls */
272 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
273 name = "Spatial Filter Mode";
274 break;
275 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
276 name = "Spatial Filter";
277 break;
278 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
279 name = "Spatial Luma Filter Type";
280 break;
281 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
282 name = "Spatial Chroma Filter Type";
283 break;
284 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
285 name = "Temporal Filter Mode";
286 break;
287 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
288 name = "Temporal Filter";
289 break;
290 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
291 name = "Median Filter Type";
292 break;
293 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
294 name = "Median Luma Filter Maximum";
295 break;
296 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
297 name = "Median Luma Filter Minimum";
298 break;
299 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
300 name = "Median Chroma Filter Maximum";
301 break;
302 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
303 name = "Median Chroma Filter Minimum";
304 break;
305
306 default:
307 return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
308 }
309 switch (qctrl->id) {
310 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
311 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
312 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
313 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
314 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
315 qctrl->type = V4L2_CTRL_TYPE_MENU;
316 min = 0;
317 step = 1;
318 break;
319 default:
320 qctrl->type = V4L2_CTRL_TYPE_INTEGER;
321 break;
322 }
323 switch (qctrl->id) {
324 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
325 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
326 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
327 qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
328 break;
329 }
330 qctrl->minimum = min;
331 qctrl->maximum = max;
332 qctrl->step = step;
333 qctrl->default_value = def;
334 qctrl->reserved[0] = qctrl->reserved[1] = 0;
335 snprintf(qctrl->name, sizeof(qctrl->name), name);
336 return 0;
337}
338
339int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
340{
341 int err;
342
343 switch (qctrl->id) {
344 case V4L2_CID_MPEG_AUDIO_ENCODING:
345 return v4l2_ctrl_query_fill(qctrl,
346 V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
347 V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
348 V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
349
350 case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
351 return v4l2_ctrl_query_fill(qctrl,
352 V4L2_MPEG_AUDIO_L2_BITRATE_192K,
353 V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
354 V4L2_MPEG_AUDIO_L2_BITRATE_224K);
355
356 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
357 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
358 return -EINVAL;
359
360 case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
361 err = v4l2_ctrl_query_fill_std(qctrl);
362 if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
363 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
364 return err;
365
366 case V4L2_CID_MPEG_VIDEO_ENCODING:
367 /* this setting is read-only for the cx2341x since the
368 V4L2_CID_MPEG_STREAM_TYPE really determines the
369 MPEG-1/2 setting */
370 err = v4l2_ctrl_query_fill_std(qctrl);
371 if (err == 0)
372 qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
373 return err;
374
375 case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
376 err = v4l2_ctrl_query_fill_std(qctrl);
377 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
378 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
379 return err;
380
381 /* CX23415/6 specific */
382 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
383 return cx2341x_ctrl_query_fill(qctrl,
384 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
385 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
386 V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
387
388 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
389 cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
390 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
391 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
392 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
393 return 0;
394
395 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
396 cx2341x_ctrl_query_fill(qctrl,
397 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
398 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
399 V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
400 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
401 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
402 return 0;
403
404 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
405 cx2341x_ctrl_query_fill(qctrl,
406 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
407 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
408 V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
409 if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
410 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
411 return 0;
412
413 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
414 return cx2341x_ctrl_query_fill(qctrl,
415 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
416 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
417 V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
418
419 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
420 cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
421 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
422 if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
423 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
424 return 0;
425
426 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
427 return cx2341x_ctrl_query_fill(qctrl,
428 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
429 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
430 V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
431
432 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
433 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
434 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
435 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
436 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
437 return 0;
438
439 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
440 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
441 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
442 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
443 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
444 return 0;
445
446 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
447 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
448 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
449 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
450 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
451 return 0;
452
453 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
454 cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
455 qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
456 if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
457 qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
458 return 0;
459
460 default:
461 return v4l2_ctrl_query_fill_std(qctrl);
462
463 }
464}
465
466const char **cx2341x_ctrl_get_menu(u32 id)
467{
468 static const char *mpeg_stream_type[] = {
469 "MPEG-2 Program Stream",
470 "",
471 "MPEG-1 System Stream",
472 "MPEG-2 DVD-compatible Stream",
473 "MPEG-1 VCD-compatible Stream",
474 "MPEG-2 SVCD-compatible Stream",
475 NULL
476 };
477
478 static const char *cx2341x_video_spatial_filter_mode_menu[] = {
479 "Manual",
480 "Auto",
481 NULL
482 };
483
484 static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
485 "Off",
486 "1D Horizontal",
487 "1D Vertical",
488 "2D H/V Separable",
489 "2D Symmetric non-separable",
490 NULL
491 };
492
493 static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
494 "Off",
495 "1D Horizontal",
496 NULL
497 };
498
499 static const char *cx2341x_video_temporal_filter_mode_menu[] = {
500 "Manual",
501 "Auto",
502 NULL
503 };
504
505 static const char *cx2341x_video_median_filter_type_menu[] = {
506 "Off",
507 "Horizontal",
508 "Vertical",
509 "Horizontal/Vertical",
510 "Diagonal",
511 NULL
512 };
513
514 switch (id) {
515 case V4L2_CID_MPEG_STREAM_TYPE:
516 return mpeg_stream_type;
517 case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
518 case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
519 return NULL;
520 case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
521 return cx2341x_video_spatial_filter_mode_menu;
522 case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
523 return cx2341x_video_luma_spatial_filter_type_menu;
524 case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
525 return cx2341x_video_chroma_spatial_filter_type_menu;
526 case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
527 return cx2341x_video_temporal_filter_mode_menu;
528 case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
529 return cx2341x_video_median_filter_type_menu;
530 default:
531 return v4l2_ctrl_get_menu(id);
532 }
533}
534
535static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
536{
537 params->audio_properties = (params->audio_sampling_freq << 0) |
538 ((3 - params->audio_encoding) << 2) |
539 ((1 + params->audio_l2_bitrate) << 4) |
540 (params->audio_mode << 8) |
541 (params->audio_mode_extension << 10) |
542 (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
543 3 :
544 params->audio_emphasis) << 12) |
545 (params->audio_crc << 14);
546}
547
548int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
549 struct v4l2_ext_controls *ctrls, int cmd)
550{
551 int err = 0;
552 int i;
553
554 if (cmd == VIDIOC_G_EXT_CTRLS) {
555 for (i = 0; i < ctrls->count; i++) {
556 struct v4l2_ext_control *ctrl = ctrls->controls + i;
557
558 err = cx2341x_get_ctrl(params, ctrl);
559 if (err) {
560 ctrls->error_idx = i;
561 break;
562 }
563 }
564 return err;
565 }
566 for (i = 0; i < ctrls->count; i++) {
567 struct v4l2_ext_control *ctrl = ctrls->controls + i;
568 struct v4l2_queryctrl qctrl;
569 const char **menu_items = NULL;
570
571 qctrl.id = ctrl->id;
572 err = cx2341x_ctrl_query(params, &qctrl);
573 if (err)
574 break;
575 if (qctrl.type == V4L2_CTRL_TYPE_MENU)
576 menu_items = cx2341x_ctrl_get_menu(qctrl.id);
577 err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
578 if (err)
579 break;
580 err = cx2341x_set_ctrl(params, ctrl);
581 if (err)
582 break;
583 }
584 if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
585 params->video_bitrate_peak < params->video_bitrate) {
586 err = -ERANGE;
587 ctrls->error_idx = ctrls->count;
588 }
589 if (err) {
590 ctrls->error_idx = i;
591 }
592 else {
593 cx2341x_calc_audio_properties(params);
594 }
595 return err;
596}
597
598void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
599{
600 static struct cx2341x_mpeg_params default_params = {
601 /* misc */
602 .width = 720,
603 .height = 480,
604 .is_50hz = 0,
605
606 /* stream */
607 .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
608
609 /* audio */
610 .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
611 .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
612 .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
613 .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
614 .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
615 .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
616 .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
617
618 /* video */
619 .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
620 .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
621 .video_b_frames = 2,
622 .video_gop_size = 12,
623 .video_gop_closure = 1,
624 .video_pulldown = 0,
625 .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
626 .video_bitrate = 6000000,
627 .video_bitrate_peak = 8000000,
628 .video_temporal_decimation = 0,
629
630 /* encoding filters */
631 .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
632 .video_spatial_filter = 0,
633 .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
634 .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
635 .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
636 .video_temporal_filter = 0,
637 .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
638 .video_luma_median_filter_top = 255,
639 .video_luma_median_filter_bottom = 0,
640 .video_chroma_median_filter_top = 255,
641 .video_chroma_median_filter_bottom = 0,
642 };
643
644 *p = default_params;
645 cx2341x_calc_audio_properties(p);
646}
647
648static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
649{
650 u32 data[CX2341X_MBOX_MAX_DATA];
651 va_list vargs;
652 int i;
653
654 va_start(vargs, args);
655
656 for (i = 0; i < args; i++) {
657 data[i] = va_arg(vargs, int);
658 }
659 va_end(vargs);
660 return func(priv, cmd, args, 0, data);
661}
662
663int cx2341x_update(void *priv, cx2341x_mbox_func func,
664 const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
665{
666 static int mpeg_stream_type[] = {
667 0, /* MPEG-2 PS */
668 1, /* MPEG-2 TS */
669 2, /* MPEG-1 SS */
670 14, /* DVD */
671 11, /* VCD */
672 12, /* SVCD */
673 };
674
675 int err = 0;
676
677 cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 1, 0); /* 0 = Memory */
678
679 if (old == NULL || old->is_50hz != new->is_50hz) {
680 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
681 if (err) return err;
682 }
683
684 if (old == NULL || old->width != new->width || old->height != new->height ||
685 old->video_encoding != new->video_encoding) {
686 u16 w = new->width;
687 u16 h = new->height;
688
689 if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
690 w /= 2;
691 h /= 2;
692 }
693 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
694 if (err) return err;
695 }
696
697 if (old == NULL || old->stream_type != new->stream_type) {
698 err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
699 if (err) return err;
700 }
701 if (old == NULL || old->video_aspect != new->video_aspect) {
702 err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
703 if (err) return err;
704 }
705 if (old == NULL || old->video_b_frames != new->video_b_frames ||
706 old->video_gop_size != new->video_gop_size) {
707 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
708 new->video_gop_size, new->video_b_frames + 1);
709 if (err) return err;
710 }
711 if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
712 err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
713 if (err) return err;
714 }
715 if (old == NULL || old->video_pulldown != new->video_pulldown) {
716 err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
717 if (err) return err;
718 }
719 if (old == NULL || old->audio_properties != new->audio_properties) {
720 err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
721 if (err) return err;
722 }
723 if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
724 old->video_bitrate != new->video_bitrate ||
725 old->video_bitrate_peak != new->video_bitrate_peak) {
726 err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
727 new->video_bitrate_mode, new->video_bitrate,
728 new->video_bitrate_peak / 400, 0, 0);
729 if (err) return err;
730 }
731 if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
732 old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
733 old->video_median_filter_type != new->video_median_filter_type) {
734 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
735 new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
736 new->video_median_filter_type);
737 if (err) return err;
738 }
739 if (old == NULL ||
740 old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
741 old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
742 old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
743 old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
744 err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
745 new->video_luma_median_filter_bottom,
746 new->video_luma_median_filter_top,
747 new->video_chroma_median_filter_bottom,
748 new->video_chroma_median_filter_top);
749 if (err) return err;
750 }
751 if (old == NULL ||
752 old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
753 old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
754 err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
755 new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
756 if (err) return err;
757 }
758 if (old == NULL ||
759 old->video_spatial_filter != new->video_spatial_filter ||
760 old->video_temporal_filter != new->video_temporal_filter) {
761 err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
762 new->video_spatial_filter, new->video_temporal_filter);
763 if (err) return err;
764 }
765 if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
766 err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
767 new->video_temporal_decimation);
768 if (err) return err;
769 }
770 return 0;
771}
772
773static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
774{
775 const char **menu = cx2341x_ctrl_get_menu(id);
776 struct v4l2_ext_control ctrl;
777
778 if (menu == NULL)
779 goto invalid;
780 ctrl.id = id;
781 if (cx2341x_get_ctrl(p, &ctrl))
782 goto invalid;
783 while (ctrl.value-- && *menu) menu++;
784 if (*menu == NULL)
785 goto invalid;
786 return *menu;
787
788invalid:
789 return "<invalid>";
790}
791
792void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
793{
794 int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
795
796 /* Stream */
797 printk(KERN_INFO "cx2341x-%d: Stream: %s\n",
798 card_id,
799 cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
800
801 /* Video */
802 printk(KERN_INFO "cx2341x-%d: Video: %dx%d, %d fps\n",
803 card_id,
804 p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
805 p->is_50hz ? 25 : 30);
806 printk(KERN_INFO "cx2341x-%d: Video: %s, %s, %s, %d",
807 card_id,
808 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
809 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
810 cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
811 p->video_bitrate);
812 if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
813 printk(", Peak %d", p->video_bitrate_peak);
814 }
815 printk("\n");
816 printk(KERN_INFO "cx2341x-%d: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
817 card_id,
818 p->video_gop_size, p->video_b_frames,
819 p->video_gop_closure ? "" : "No ",
820 p->video_pulldown ? "" : "No ");
821 if (p->video_temporal_decimation) {
822 printk(KERN_INFO "cx2341x-%d: Video: Temporal Decimation %d\n",
823 card_id, p->video_temporal_decimation);
824 }
825
826 /* Audio */
827 printk(KERN_INFO "cx2341x-%d: Audio: %s, %s, %s, %s",
828 card_id,
829 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
830 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
831 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
832 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
833 if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
834 printk(", %s",
835 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
836 }
837 printk(", %s, %s\n",
838 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
839 cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
840
841 /* Encoding filters */
842 printk(KERN_INFO "cx2341x-%d: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
843 card_id,
844 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
845 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
846 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
847 p->video_spatial_filter);
848 printk(KERN_INFO "cx2341x-%d: Temporal Filter: %s, %d\n",
849 card_id,
850 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
851 p->video_temporal_filter);
852 printk(KERN_INFO "cx2341x-%d: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
853 card_id,
854 cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
855 p->video_luma_median_filter_bottom,
856 p->video_luma_median_filter_top,
857 p->video_chroma_median_filter_bottom,
858 p->video_chroma_median_filter_top);
859}
860
861EXPORT_SYMBOL(cx2341x_fill_defaults);
862EXPORT_SYMBOL(cx2341x_ctrl_query);
863EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
864EXPORT_SYMBOL(cx2341x_ext_ctrls);
865EXPORT_SYMBOL(cx2341x_update);
866EXPORT_SYMBOL(cx2341x_log_status);
867
868/*
869 * Local variables:
870 * c-basic-offset: 8
871 * End:
872 */
873