blob: 47c8e0203ce7318391c74a5b952218ce104cf550 [file] [log] [blame]
Mike Iselyd8554972006-06-26 20:58:46 -03001/*
2 *
3 * $Id$
4 *
5 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
6 * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <linux/device.h> // for linux/firmware.h
24#include <linux/firmware.h>
Mike Iselyd8554972006-06-26 20:58:46 -030025#include "pvrusb2-util.h"
26#include "pvrusb2-encoder.h"
27#include "pvrusb2-hdw-internal.h"
28#include "pvrusb2-debug.h"
29
30static u32 pvr_tbl_emphasis [] = {
31 [PVR2_CVAL_AUDIOEMPHASIS_NONE] = 0x0 << 12,
32 [PVR2_CVAL_AUDIOEMPHASIS_50_15] = 0x1 << 12,
33 [PVR2_CVAL_AUDIOEMPHASIS_CCITT] = 0x3 << 12,
34};
35
36static u32 pvr_tbl_srate[] = {
37 [PVR2_CVAL_SRATE_48] = 0x01,
38 [PVR2_CVAL_SRATE_44_1] = 0x00,
39};
40
41static u32 pvr_tbl_audiobitrate[] = {
42 [PVR2_CVAL_AUDIOBITRATE_384] = 0xe << 4,
43 [PVR2_CVAL_AUDIOBITRATE_320] = 0xd << 4,
44 [PVR2_CVAL_AUDIOBITRATE_256] = 0xc << 4,
45 [PVR2_CVAL_AUDIOBITRATE_224] = 0xb << 4,
46 [PVR2_CVAL_AUDIOBITRATE_192] = 0xa << 4,
47 [PVR2_CVAL_AUDIOBITRATE_160] = 0x9 << 4,
48 [PVR2_CVAL_AUDIOBITRATE_128] = 0x8 << 4,
49 [PVR2_CVAL_AUDIOBITRATE_112] = 0x7 << 4,
50 [PVR2_CVAL_AUDIOBITRATE_96] = 0x6 << 4,
51 [PVR2_CVAL_AUDIOBITRATE_80] = 0x5 << 4,
52 [PVR2_CVAL_AUDIOBITRATE_64] = 0x4 << 4,
53 [PVR2_CVAL_AUDIOBITRATE_56] = 0x3 << 4,
54 [PVR2_CVAL_AUDIOBITRATE_48] = 0x2 << 4,
55 [PVR2_CVAL_AUDIOBITRATE_32] = 0x1 << 4,
56 [PVR2_CVAL_AUDIOBITRATE_VBR] = 0x0 << 4,
57};
58
59
60/* Firmware mailbox flags - definitions found from ivtv */
61#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
62#define IVTV_MBOX_DRIVER_DONE 0x00000002
63#define IVTV_MBOX_DRIVER_BUSY 0x00000001
64
65
Mike Iselyeacbe7c2006-06-25 20:04:06 -030066static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
Mike Iselyd8554972006-06-26 20:58:46 -030067 const u32 *data, unsigned int dlen)
68{
69 unsigned int idx;
70 int ret;
71 unsigned int offs = 0;
72 unsigned int chunkCnt;
73
74 /*
75
76 Format: First byte must be 0x01. Remaining 32 bit words are
77 spread out into chunks of 7 bytes each, little-endian ordered,
78 offset at zero within each 2 blank bytes following and a
79 single byte that is 0x44 plus the offset of the word. Repeat
80 request for additional words, with offset adjusted
81 accordingly.
82
83 */
84 while (dlen) {
85 chunkCnt = 8;
86 if (chunkCnt > dlen) chunkCnt = dlen;
87 memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
88 hdw->cmd_buffer[0] = 0x01;
89 for (idx = 0; idx < chunkCnt; idx++) {
90 hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
91 PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
92 data[idx]);
93 }
94 ret = pvr2_send_request(hdw,
95 hdw->cmd_buffer,1+(chunkCnt*7),
96 0,0);
97 if (ret) return ret;
98 data += chunkCnt;
99 dlen -= chunkCnt;
100 offs += chunkCnt;
101 }
102
103 return 0;
104}
105
106
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300107static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
Mike Iselyd8554972006-06-26 20:58:46 -0300108 u32 *data, unsigned int dlen)
109{
110 unsigned int idx;
111 int ret;
112 unsigned int offs = 0;
113 unsigned int chunkCnt;
114
115 /*
116
117 Format: First byte must be 0x02 (status check) or 0x28 (read
118 back block of 32 bit words). Next 6 bytes must be zero,
119 followed by a single byte of 0x44+offset for portion to be
120 read. Returned data is packed set of 32 bits words that were
121 read.
122
123 */
124
125 while (dlen) {
126 chunkCnt = 16;
127 if (chunkCnt > dlen) chunkCnt = dlen;
128 memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
129 hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
130 hdw->cmd_buffer[7] = 0x44 + offs;
131 ret = pvr2_send_request(hdw,
132 hdw->cmd_buffer,8,
133 hdw->cmd_buffer,chunkCnt * 4);
134 if (ret) return ret;
135
136 for (idx = 0; idx < chunkCnt; idx++) {
137 data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);
138 }
139 data += chunkCnt;
140 dlen -= chunkCnt;
141 offs += chunkCnt;
142 }
143
144 return 0;
145}
146
147
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300148/* This prototype is set up to be compatible with the
149 cx2341x_mbox_func prototype in cx2341x.h, which should be in
150 kernels 2.6.18 or later. We do this so that we can enable
151 cx2341x.ko to write to our encoder (by handing it a pointer to this
152 function). For earlier kernels this doesn't really matter. */
153static int pvr2_encoder_cmd(void *ctxt,
154 int cmd,
155 int arg_cnt_send,
156 int arg_cnt_recv,
157 u32 *argp)
Mike Iselyd8554972006-06-26 20:58:46 -0300158{
159 unsigned int poll_count;
160 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300161 unsigned int idx;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300162 /* These sizes look to be limited by the FX2 firmware implementation */
Mike Iselyd8554972006-06-26 20:58:46 -0300163 u32 wrData[16];
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300164 u32 rdData[16];
165 struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
Mike Iselyd8554972006-06-26 20:58:46 -0300166
Mike Iselyc05c0462006-06-25 20:04:25 -0300167
Mike Iselyd8554972006-06-26 20:58:46 -0300168 /*
169
170 The encoder seems to speak entirely using blocks 32 bit words.
171 In ivtv driver terms, this is a mailbox which we populate with
172 data and watch what the hardware does with it. The first word
173 is a set of flags used to control the transaction, the second
174 word is the command to execute, the third byte is zero (ivtv
175 driver suggests that this is some kind of return value), and
176 the fourth byte is a specified timeout (windows driver always
177 uses 0x00060000 except for one case when it is zero). All
178 successive words are the argument words for the command.
179
180 First, write out the entire set of words, with the first word
181 being zero.
182
183 Next, write out just the first word again, but set it to
184 IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
185 probably means "go").
186
187 Next, read back 16 words as status. Check the first word,
188 which should have IVTV_MBOX_FIRMWARE_DONE set. If however
189 that bit is not set, then the command isn't done so repeat the
190 read.
191
192 Next, read back 32 words and compare with the original
193 arugments. Hopefully they will match.
194
195 Finally, write out just the first word again, but set it to
196 0x0 this time (which probably means "idle").
197
198 */
199
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300200 if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
201 pvr2_trace(
202 PVR2_TRACE_ERROR_LEGS,
203 "Failed to write cx23416 command"
204 " - too many input arguments"
205 " (was given %u limit %u)",
206 arg_cnt_send,
207 (sizeof(wrData)/sizeof(wrData[0])) - 4);
208 return -EINVAL;
209 }
210
211 if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
212 pvr2_trace(
213 PVR2_TRACE_ERROR_LEGS,
214 "Failed to write cx23416 command"
215 " - too many return arguments"
216 " (was given %u limit %u)",
217 arg_cnt_recv,
218 (sizeof(rdData)/sizeof(rdData[0])) - 4);
219 return -EINVAL;
220 }
221
Mike Iselyd8554972006-06-26 20:58:46 -0300222
223 LOCK_TAKE(hdw->ctl_lock); do {
224
225 wrData[0] = 0;
226 wrData[1] = cmd;
227 wrData[2] = 0;
228 wrData[3] = 0x00060000;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300229 for (idx = 0; idx < arg_cnt_send; idx++) {
230 wrData[idx+4] = argp[idx];
Mike Iselyd8554972006-06-26 20:58:46 -0300231 }
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300232 for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
233 wrData[idx+4] = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300234 }
235
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300236 ret = pvr2_encoder_write_words(hdw,wrData,idx);
Mike Iselyd8554972006-06-26 20:58:46 -0300237 if (ret) break;
238 wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300239 ret = pvr2_encoder_write_words(hdw,wrData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300240 if (ret) break;
241 poll_count = 0;
242 while (1) {
243 if (poll_count < 10000000) poll_count++;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300244 ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300245 if (ret) break;
246 if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
247 break;
248 }
249 if (poll_count == 100) {
250 pvr2_trace(
251 PVR2_TRACE_ERROR_LEGS,
252 "***WARNING*** device's encoder"
253 " appears to be stuck"
254 " (status=0%08x)",rdData[0]);
255 pvr2_trace(
256 PVR2_TRACE_ERROR_LEGS,
257 "Encoder command: 0x%02x",cmd);
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300258 for (idx = 4; idx < arg_cnt_send; idx++) {
Mike Iselyd8554972006-06-26 20:58:46 -0300259 pvr2_trace(
260 PVR2_TRACE_ERROR_LEGS,
261 "Encoder arg%d: 0x%08x",
262 idx-3,wrData[idx]);
263 }
264 pvr2_trace(
265 PVR2_TRACE_ERROR_LEGS,
266 "Giving up waiting."
267 " It is likely that"
268 " this is a bad idea...");
269 ret = -EBUSY;
270 break;
271 }
272 }
273 if (ret) break;
274 wrData[0] = 0x7;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300275 ret = pvr2_encoder_read_words(
276 hdw,0,rdData,
277 sizeof(rdData)/sizeof(rdData[0]));
Mike Iselyd8554972006-06-26 20:58:46 -0300278 if (ret) break;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300279 for (idx = 0; idx < arg_cnt_recv; idx++) {
280 argp[idx] = rdData[idx+4];
Mike Iselyd8554972006-06-26 20:58:46 -0300281 }
282
283 wrData[0] = 0x0;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300284 ret = pvr2_encoder_write_words(hdw,wrData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300285 if (ret) break;
286
287 } while(0); LOCK_GIVE(hdw->ctl_lock);
288
289 return ret;
290}
291
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300292
293static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
294 int args, ...)
295{
296 va_list vl;
297 unsigned int idx;
298 u32 data[12];
299
300 if (args > sizeof(data)/sizeof(data[0])) {
301 pvr2_trace(
302 PVR2_TRACE_ERROR_LEGS,
303 "Failed to write cx23416 command"
304 " - too many arguments"
305 " (was given %u limit %u)",
306 args,sizeof(data)/sizeof(data[0]));
307 return -EINVAL;
308 }
309
310 va_start(vl, args);
311 for (idx = 0; idx < args; idx++) {
312 data[idx] = va_arg(vl, u32);
313 }
314 va_end(vl);
315
316 return pvr2_encoder_cmd(hdw,cmd,args,0,data);
317}
318
319
Mike Iselyd8554972006-06-26 20:58:46 -0300320int pvr2_encoder_configure(struct pvr2_hdw *hdw)
321{
322 int ret = 0, audio, i;
323 v4l2_std_id vd_std = hdw->std_mask_cur;
324 int height = hdw->res_ver_val;
325 int width = hdw->res_hor_val;
326 int height_full = !hdw->interlace_val;
327
328 int is_30fps, is_ntsc;
329
330 if (vd_std & V4L2_STD_NTSC) {
331 is_ntsc=1;
332 is_30fps=1;
333 } else if (vd_std & V4L2_STD_PAL_M) {
334 is_ntsc=0;
335 is_30fps=1;
336 } else {
337 is_ntsc=0;
338 is_30fps=0;
339 }
340
Mike Iselyc05c0462006-06-25 20:04:25 -0300341 pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure (native)");
Mike Iselyd8554972006-06-26 20:58:46 -0300342
343 /* set stream output port. Some notes here: The ivtv-derived
344 encoder documentation says that this command only gets a
345 single argument. However the Windows driver for the model
346 29xxx series hardware has been sending 0x01 as a second
347 argument, while the Windows driver for the model 24xxx
348 series hardware has been sending 0x02 as a second argument.
349 Confusing matters further are the observations that 0x01
350 for that second argument simply won't work on the 24xxx
351 hardware, while 0x02 will work on the 29xxx - except that
352 when we use 0x02 then xawtv breaks due to a loss of
353 synchronization with the mpeg packet headers. While xawtv
354 should be fixed to let it resync better (I did try to
355 contact Gerd about this but he has not answered), it has
356 also been determined that sending 0x00 as this mystery
357 second argument seems to work on both hardware models AND
358 xawtv works again. So we're going to send 0x00. */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300359 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_OUTPUT_PORT, 2,
360 0x01, 0x00);
Mike Iselyd8554972006-06-26 20:58:46 -0300361
362 /* set the Program Index Information. We want I,P,B frames (max 400) */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300363 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_PGM_INDEX_INFO, 2,
364 0x07, 0x0190);
Mike Iselyd8554972006-06-26 20:58:46 -0300365
366 /* NOTE : windows driver sends these */
367 /* Mike Isely <isely@pobox.com> 7-Mar-2006 The windows driver
368 sends the following commands but if we do the same then
369 many apps are no longer able to read the video stream.
370 Leaving these out seems to do no harm at all, so they're
371 commented out for that reason. */
372#ifdef notdef
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300373 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
374 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,1,0,0);
375 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
376 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
377 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
378 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
Mike Iselyd8554972006-06-26 20:58:46 -0300379#endif
380
381 /* Strange compared to ivtv data. */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300382 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
383 0xf0, 0xf0);
Mike Iselyd8554972006-06-26 20:58:46 -0300384
385 /* setup firmware to notify us about some events (don't know why...) */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300386 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
387 0, 0, 0x10000000, 0xffffffff);
Mike Iselyd8554972006-06-26 20:58:46 -0300388
389 /* set fps to 25 or 30 (1 or 0)*/
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300390 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_RATE, 1,
391 is_30fps ? 0 : 1);
Mike Iselyd8554972006-06-26 20:58:46 -0300392
393 /* set encoding resolution */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300394 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_SIZE, 2,
395 (height_full ? height : (height / 2)),
396 width);
Mike Iselyd8554972006-06-26 20:58:46 -0300397 /* set encoding aspect ratio to 4:3 */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300398 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_ASPECT_RATIO, 1,
399 0x02);
Mike Iselyd8554972006-06-26 20:58:46 -0300400
401 /* VBI */
402
403 if (hdw->config == pvr2_config_vbi) {
404 int lines = 2 * (is_30fps ? 12 : 18);
405 int size = (4*((lines*1443+3)/4)) / lines;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300406 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_VBI_CONFIG, 7,
407 0xbd05, 1, 4,
408 0x25256262, 0x387f7f7f,
409 lines , size);
Mike Iselyd8554972006-06-26 20:58:46 -0300410// 0x25256262, 0x13135454, lines , size);
411 /* select vbi lines */
412#define line_used(l) (is_30fps ? (l >= 10 && l <= 21) : (l >= 6 && l <= 23))
413 for (i = 2 ; i <= 24 ; i++){
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300414 ret |= pvr2_encoder_vcmd(
Mike Iselyd8554972006-06-26 20:58:46 -0300415 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
416 i-1,line_used(i), 0, 0, 0);
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300417 ret |= pvr2_encoder_vcmd(
Mike Iselyd8554972006-06-26 20:58:46 -0300418 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
419 (i-1) | (1 << 31),
420 line_used(i), 0, 0, 0);
421 }
422 } else {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300423 ret |= pvr2_encoder_vcmd(
Mike Iselyd8554972006-06-26 20:58:46 -0300424 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
425 0xffffffff,0,0,0,0);
426 }
427
428 /* set stream type, depending on resolution. */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300429 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_STREAM_TYPE, 1,
430 height_full ? 0x0a : 0x0b);
Mike Iselyd8554972006-06-26 20:58:46 -0300431 /* set video bitrate */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300432 ret |= pvr2_encoder_vcmd(
Mike Iselyd8554972006-06-26 20:58:46 -0300433 hdw, CX2341X_ENC_SET_BIT_RATE, 3,
434 (hdw->vbr_val ? 1 : 0),
435 hdw->videobitrate_val,
436 hdw->videopeak_val / 400);
437 /* setup GOP structure (GOP size = 0f or 0c, 3-1 = 2 B-frames) */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300438 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
439 is_30fps ? 0x0f : 0x0c, 0x03);
Mike Iselyd8554972006-06-26 20:58:46 -0300440
441 /* enable 3:2 pulldown */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300442 ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_3_2_PULLDOWN,1,0);
Mike Iselyd8554972006-06-26 20:58:46 -0300443
444 /* set GOP open/close property (open) */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300445 ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_GOP_CLOSURE,1,0);
Mike Iselyd8554972006-06-26 20:58:46 -0300446
447 /* set audio stream properties 0x40b9? 0100 0000 1011 1001 */
448 audio = (pvr_tbl_audiobitrate[hdw->audiobitrate_val] |
449 pvr_tbl_srate[hdw->srate_val] |
450 hdw->audiolayer_val << 2 |
451 (hdw->audiocrc_val ? 1 << 14 : 0) |
452 pvr_tbl_emphasis[hdw->audioemphasis_val]);
453
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300454 ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_AUDIO_PROPERTIES,1,
455 audio);
Mike Iselyd8554972006-06-26 20:58:46 -0300456
457 /* set dynamic noise reduction filter to manual, Horiz/Vert */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300458 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
459 0, 0x03);
Mike Iselyd8554972006-06-26 20:58:46 -0300460
461 /* dynamic noise reduction filter param */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300462 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2
463 , 0, 0);
Mike Iselyd8554972006-06-26 20:58:46 -0300464
465 /* dynamic noise reduction median filter */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300466 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_CORING_LEVELS, 4,
467 0, 0xff, 0, 0xff);
Mike Iselyd8554972006-06-26 20:58:46 -0300468
469 /* spacial prefiler parameter */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300470 ret |= pvr2_encoder_vcmd(hdw,
471 CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
472 0x01, 0x01);
Mike Iselyd8554972006-06-26 20:58:46 -0300473
474 /* initialize video input */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300475 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
Mike Iselyd8554972006-06-26 20:58:46 -0300476
477 if (!ret) {
478 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
479 }
480
481 return ret;
482}
483
484int pvr2_encoder_start(struct pvr2_hdw *hdw)
485{
486 int status;
487
488 /* unmask some interrupts */
489 pvr2_write_register(hdw, 0x0048, 0xbfffffff);
490
491 /* change some GPIO data */
492 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
493 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
494
495 if (hdw->config == pvr2_config_vbi) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300496 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
497 0x01,0x14);
Mike Iselyd8554972006-06-26 20:58:46 -0300498 } else if (hdw->config == pvr2_config_mpeg) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300499 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
500 0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300501 } else {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300502 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
503 0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300504 }
505 if (!status) {
506 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
507 }
508 return status;
509}
510
511int pvr2_encoder_stop(struct pvr2_hdw *hdw)
512{
513 int status;
514
515 /* mask all interrupts */
516 pvr2_write_register(hdw, 0x0048, 0xffffffff);
517
518 if (hdw->config == pvr2_config_vbi) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300519 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
520 0x01,0x01,0x14);
Mike Iselyd8554972006-06-26 20:58:46 -0300521 } else if (hdw->config == pvr2_config_mpeg) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300522 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
523 0x01,0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300524 } else {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300525 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
526 0x01,0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300527 }
528
529 /* change some GPIO data */
530 /* Note: Bit d7 of dir appears to control the LED. So we shut it
531 off here. */
532 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
533 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
534
535 if (!status) {
536 hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
537 }
538 return status;
539}
540
541
542/*
543 Stuff for Emacs to see, in order to encourage consistent editing style:
544 *** Local Variables: ***
545 *** mode: c ***
546 *** fill-column: 70 ***
547 *** tab-width: 8 ***
548 *** c-basic-offset: 8 ***
549 *** End: ***
550 */