blob: f3d2c2b4d5120ef61251f508f4d0eeae47ed8080 [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>
25#include <linux/videodev2.h>
26#include <media/cx2341x.h>
27#include "pvrusb2-util.h"
28#include "pvrusb2-encoder.h"
29#include "pvrusb2-hdw-internal.h"
30#include "pvrusb2-debug.h"
31
32static u32 pvr_tbl_emphasis [] = {
33 [PVR2_CVAL_AUDIOEMPHASIS_NONE] = 0x0 << 12,
34 [PVR2_CVAL_AUDIOEMPHASIS_50_15] = 0x1 << 12,
35 [PVR2_CVAL_AUDIOEMPHASIS_CCITT] = 0x3 << 12,
36};
37
38static u32 pvr_tbl_srate[] = {
39 [PVR2_CVAL_SRATE_48] = 0x01,
40 [PVR2_CVAL_SRATE_44_1] = 0x00,
41};
42
43static u32 pvr_tbl_audiobitrate[] = {
44 [PVR2_CVAL_AUDIOBITRATE_384] = 0xe << 4,
45 [PVR2_CVAL_AUDIOBITRATE_320] = 0xd << 4,
46 [PVR2_CVAL_AUDIOBITRATE_256] = 0xc << 4,
47 [PVR2_CVAL_AUDIOBITRATE_224] = 0xb << 4,
48 [PVR2_CVAL_AUDIOBITRATE_192] = 0xa << 4,
49 [PVR2_CVAL_AUDIOBITRATE_160] = 0x9 << 4,
50 [PVR2_CVAL_AUDIOBITRATE_128] = 0x8 << 4,
51 [PVR2_CVAL_AUDIOBITRATE_112] = 0x7 << 4,
52 [PVR2_CVAL_AUDIOBITRATE_96] = 0x6 << 4,
53 [PVR2_CVAL_AUDIOBITRATE_80] = 0x5 << 4,
54 [PVR2_CVAL_AUDIOBITRATE_64] = 0x4 << 4,
55 [PVR2_CVAL_AUDIOBITRATE_56] = 0x3 << 4,
56 [PVR2_CVAL_AUDIOBITRATE_48] = 0x2 << 4,
57 [PVR2_CVAL_AUDIOBITRATE_32] = 0x1 << 4,
58 [PVR2_CVAL_AUDIOBITRATE_VBR] = 0x0 << 4,
59};
60
61
62/* Firmware mailbox flags - definitions found from ivtv */
63#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
64#define IVTV_MBOX_DRIVER_DONE 0x00000002
65#define IVTV_MBOX_DRIVER_BUSY 0x00000001
66
67
Mike Iselyeacbe7c2006-06-25 20:04:06 -030068static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
Mike Iselyd8554972006-06-26 20:58:46 -030069 const u32 *data, unsigned int dlen)
70{
71 unsigned int idx;
72 int ret;
73 unsigned int offs = 0;
74 unsigned int chunkCnt;
75
76 /*
77
78 Format: First byte must be 0x01. Remaining 32 bit words are
79 spread out into chunks of 7 bytes each, little-endian ordered,
80 offset at zero within each 2 blank bytes following and a
81 single byte that is 0x44 plus the offset of the word. Repeat
82 request for additional words, with offset adjusted
83 accordingly.
84
85 */
86 while (dlen) {
87 chunkCnt = 8;
88 if (chunkCnt > dlen) chunkCnt = dlen;
89 memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
90 hdw->cmd_buffer[0] = 0x01;
91 for (idx = 0; idx < chunkCnt; idx++) {
92 hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
93 PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
94 data[idx]);
95 }
96 ret = pvr2_send_request(hdw,
97 hdw->cmd_buffer,1+(chunkCnt*7),
98 0,0);
99 if (ret) return ret;
100 data += chunkCnt;
101 dlen -= chunkCnt;
102 offs += chunkCnt;
103 }
104
105 return 0;
106}
107
108
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300109static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
Mike Iselyd8554972006-06-26 20:58:46 -0300110 u32 *data, unsigned int dlen)
111{
112 unsigned int idx;
113 int ret;
114 unsigned int offs = 0;
115 unsigned int chunkCnt;
116
117 /*
118
119 Format: First byte must be 0x02 (status check) or 0x28 (read
120 back block of 32 bit words). Next 6 bytes must be zero,
121 followed by a single byte of 0x44+offset for portion to be
122 read. Returned data is packed set of 32 bits words that were
123 read.
124
125 */
126
127 while (dlen) {
128 chunkCnt = 16;
129 if (chunkCnt > dlen) chunkCnt = dlen;
130 memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
131 hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
132 hdw->cmd_buffer[7] = 0x44 + offs;
133 ret = pvr2_send_request(hdw,
134 hdw->cmd_buffer,8,
135 hdw->cmd_buffer,chunkCnt * 4);
136 if (ret) return ret;
137
138 for (idx = 0; idx < chunkCnt; idx++) {
139 data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);
140 }
141 data += chunkCnt;
142 dlen -= chunkCnt;
143 offs += chunkCnt;
144 }
145
146 return 0;
147}
148
149
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300150/* This prototype is set up to be compatible with the
151 cx2341x_mbox_func prototype in cx2341x.h, which should be in
152 kernels 2.6.18 or later. We do this so that we can enable
153 cx2341x.ko to write to our encoder (by handing it a pointer to this
154 function). For earlier kernels this doesn't really matter. */
155static int pvr2_encoder_cmd(void *ctxt,
156 int cmd,
157 int arg_cnt_send,
158 int arg_cnt_recv,
159 u32 *argp)
Mike Iselyd8554972006-06-26 20:58:46 -0300160{
161 unsigned int poll_count;
162 int ret = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300163 unsigned int idx;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300164 /* These sizes look to be limited by the FX2 firmware implementation */
Mike Iselyd8554972006-06-26 20:58:46 -0300165 u32 wrData[16];
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300166 u32 rdData[16];
167 struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
Mike Iselyd8554972006-06-26 20:58:46 -0300168
169 /*
170
171 The encoder seems to speak entirely using blocks 32 bit words.
172 In ivtv driver terms, this is a mailbox which we populate with
173 data and watch what the hardware does with it. The first word
174 is a set of flags used to control the transaction, the second
175 word is the command to execute, the third byte is zero (ivtv
176 driver suggests that this is some kind of return value), and
177 the fourth byte is a specified timeout (windows driver always
178 uses 0x00060000 except for one case when it is zero). All
179 successive words are the argument words for the command.
180
181 First, write out the entire set of words, with the first word
182 being zero.
183
184 Next, write out just the first word again, but set it to
185 IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
186 probably means "go").
187
188 Next, read back 16 words as status. Check the first word,
189 which should have IVTV_MBOX_FIRMWARE_DONE set. If however
190 that bit is not set, then the command isn't done so repeat the
191 read.
192
193 Next, read back 32 words and compare with the original
194 arugments. Hopefully they will match.
195
196 Finally, write out just the first word again, but set it to
197 0x0 this time (which probably means "idle").
198
199 */
200
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300201 if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
202 pvr2_trace(
203 PVR2_TRACE_ERROR_LEGS,
204 "Failed to write cx23416 command"
205 " - too many input arguments"
206 " (was given %u limit %u)",
207 arg_cnt_send,
208 (sizeof(wrData)/sizeof(wrData[0])) - 4);
209 return -EINVAL;
210 }
211
212 if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
213 pvr2_trace(
214 PVR2_TRACE_ERROR_LEGS,
215 "Failed to write cx23416 command"
216 " - too many return arguments"
217 " (was given %u limit %u)",
218 arg_cnt_recv,
219 (sizeof(rdData)/sizeof(rdData[0])) - 4);
220 return -EINVAL;
221 }
222
Mike Iselyd8554972006-06-26 20:58:46 -0300223
224 LOCK_TAKE(hdw->ctl_lock); do {
225
226 wrData[0] = 0;
227 wrData[1] = cmd;
228 wrData[2] = 0;
229 wrData[3] = 0x00060000;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300230 for (idx = 0; idx < arg_cnt_send; idx++) {
231 wrData[idx+4] = argp[idx];
Mike Iselyd8554972006-06-26 20:58:46 -0300232 }
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300233 for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
234 wrData[idx+4] = 0;
Mike Iselyd8554972006-06-26 20:58:46 -0300235 }
236
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300237 ret = pvr2_encoder_write_words(hdw,wrData,idx);
Mike Iselyd8554972006-06-26 20:58:46 -0300238 if (ret) break;
239 wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300240 ret = pvr2_encoder_write_words(hdw,wrData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300241 if (ret) break;
242 poll_count = 0;
243 while (1) {
244 if (poll_count < 10000000) poll_count++;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300245 ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300246 if (ret) break;
247 if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
248 break;
249 }
250 if (poll_count == 100) {
251 pvr2_trace(
252 PVR2_TRACE_ERROR_LEGS,
253 "***WARNING*** device's encoder"
254 " appears to be stuck"
255 " (status=0%08x)",rdData[0]);
256 pvr2_trace(
257 PVR2_TRACE_ERROR_LEGS,
258 "Encoder command: 0x%02x",cmd);
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300259 for (idx = 4; idx < arg_cnt_send; idx++) {
Mike Iselyd8554972006-06-26 20:58:46 -0300260 pvr2_trace(
261 PVR2_TRACE_ERROR_LEGS,
262 "Encoder arg%d: 0x%08x",
263 idx-3,wrData[idx]);
264 }
265 pvr2_trace(
266 PVR2_TRACE_ERROR_LEGS,
267 "Giving up waiting."
268 " It is likely that"
269 " this is a bad idea...");
270 ret = -EBUSY;
271 break;
272 }
273 }
274 if (ret) break;
275 wrData[0] = 0x7;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300276 ret = pvr2_encoder_read_words(
277 hdw,0,rdData,
278 sizeof(rdData)/sizeof(rdData[0]));
Mike Iselyd8554972006-06-26 20:58:46 -0300279 if (ret) break;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300280 for (idx = 0; idx < arg_cnt_recv; idx++) {
281 argp[idx] = rdData[idx+4];
Mike Iselyd8554972006-06-26 20:58:46 -0300282 }
283
284 wrData[0] = 0x0;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300285 ret = pvr2_encoder_write_words(hdw,wrData,1);
Mike Iselyd8554972006-06-26 20:58:46 -0300286 if (ret) break;
287
288 } while(0); LOCK_GIVE(hdw->ctl_lock);
289
290 return ret;
291}
292
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300293
294static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
295 int args, ...)
296{
297 va_list vl;
298 unsigned int idx;
299 u32 data[12];
300
301 if (args > sizeof(data)/sizeof(data[0])) {
302 pvr2_trace(
303 PVR2_TRACE_ERROR_LEGS,
304 "Failed to write cx23416 command"
305 " - too many arguments"
306 " (was given %u limit %u)",
307 args,sizeof(data)/sizeof(data[0]));
308 return -EINVAL;
309 }
310
311 va_start(vl, args);
312 for (idx = 0; idx < args; idx++) {
313 data[idx] = va_arg(vl, u32);
314 }
315 va_end(vl);
316
317 return pvr2_encoder_cmd(hdw,cmd,args,0,data);
318}
319
320
Mike Iselyd8554972006-06-26 20:58:46 -0300321int pvr2_encoder_configure(struct pvr2_hdw *hdw)
322{
323 int ret = 0, audio, i;
324 v4l2_std_id vd_std = hdw->std_mask_cur;
325 int height = hdw->res_ver_val;
326 int width = hdw->res_hor_val;
327 int height_full = !hdw->interlace_val;
328
329 int is_30fps, is_ntsc;
330
331 if (vd_std & V4L2_STD_NTSC) {
332 is_ntsc=1;
333 is_30fps=1;
334 } else if (vd_std & V4L2_STD_PAL_M) {
335 is_ntsc=0;
336 is_30fps=1;
337 } else {
338 is_ntsc=0;
339 is_30fps=0;
340 }
341
342 pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure");
343
344 /* set stream output port. Some notes here: The ivtv-derived
345 encoder documentation says that this command only gets a
346 single argument. However the Windows driver for the model
347 29xxx series hardware has been sending 0x01 as a second
348 argument, while the Windows driver for the model 24xxx
349 series hardware has been sending 0x02 as a second argument.
350 Confusing matters further are the observations that 0x01
351 for that second argument simply won't work on the 24xxx
352 hardware, while 0x02 will work on the 29xxx - except that
353 when we use 0x02 then xawtv breaks due to a loss of
354 synchronization with the mpeg packet headers. While xawtv
355 should be fixed to let it resync better (I did try to
356 contact Gerd about this but he has not answered), it has
357 also been determined that sending 0x00 as this mystery
358 second argument seems to work on both hardware models AND
359 xawtv works again. So we're going to send 0x00. */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300360 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_OUTPUT_PORT, 2,
361 0x01, 0x00);
Mike Iselyd8554972006-06-26 20:58:46 -0300362
363 /* set the Program Index Information. We want I,P,B frames (max 400) */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300364 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_PGM_INDEX_INFO, 2,
365 0x07, 0x0190);
Mike Iselyd8554972006-06-26 20:58:46 -0300366
367 /* NOTE : windows driver sends these */
368 /* Mike Isely <isely@pobox.com> 7-Mar-2006 The windows driver
369 sends the following commands but if we do the same then
370 many apps are no longer able to read the video stream.
371 Leaving these out seems to do no harm at all, so they're
372 commented out for that reason. */
373#ifdef notdef
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300374 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
375 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,1,0,0);
376 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
377 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
378 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
379 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
Mike Iselyd8554972006-06-26 20:58:46 -0300380#endif
381
382 /* Strange compared to ivtv data. */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300383 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
384 0xf0, 0xf0);
Mike Iselyd8554972006-06-26 20:58:46 -0300385
386 /* setup firmware to notify us about some events (don't know why...) */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300387 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
388 0, 0, 0x10000000, 0xffffffff);
Mike Iselyd8554972006-06-26 20:58:46 -0300389
390 /* set fps to 25 or 30 (1 or 0)*/
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300391 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_RATE, 1,
392 is_30fps ? 0 : 1);
Mike Iselyd8554972006-06-26 20:58:46 -0300393
394 /* set encoding resolution */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300395 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_SIZE, 2,
396 (height_full ? height : (height / 2)),
397 width);
Mike Iselyd8554972006-06-26 20:58:46 -0300398 /* set encoding aspect ratio to 4:3 */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300399 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_ASPECT_RATIO, 1,
400 0x02);
Mike Iselyd8554972006-06-26 20:58:46 -0300401
402 /* VBI */
403
404 if (hdw->config == pvr2_config_vbi) {
405 int lines = 2 * (is_30fps ? 12 : 18);
406 int size = (4*((lines*1443+3)/4)) / lines;
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300407 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_VBI_CONFIG, 7,
408 0xbd05, 1, 4,
409 0x25256262, 0x387f7f7f,
410 lines , size);
Mike Iselyd8554972006-06-26 20:58:46 -0300411// 0x25256262, 0x13135454, lines , size);
412 /* select vbi lines */
413#define line_used(l) (is_30fps ? (l >= 10 && l <= 21) : (l >= 6 && l <= 23))
414 for (i = 2 ; i <= 24 ; i++){
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300415 ret |= pvr2_encoder_vcmd(
Mike Iselyd8554972006-06-26 20:58:46 -0300416 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
417 i-1,line_used(i), 0, 0, 0);
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300418 ret |= pvr2_encoder_vcmd(
Mike Iselyd8554972006-06-26 20:58:46 -0300419 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
420 (i-1) | (1 << 31),
421 line_used(i), 0, 0, 0);
422 }
423 } else {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300424 ret |= pvr2_encoder_vcmd(
Mike Iselyd8554972006-06-26 20:58:46 -0300425 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
426 0xffffffff,0,0,0,0);
427 }
428
429 /* set stream type, depending on resolution. */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300430 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_STREAM_TYPE, 1,
431 height_full ? 0x0a : 0x0b);
Mike Iselyd8554972006-06-26 20:58:46 -0300432 /* set video bitrate */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300433 ret |= pvr2_encoder_vcmd(
Mike Iselyd8554972006-06-26 20:58:46 -0300434 hdw, CX2341X_ENC_SET_BIT_RATE, 3,
435 (hdw->vbr_val ? 1 : 0),
436 hdw->videobitrate_val,
437 hdw->videopeak_val / 400);
438 /* setup GOP structure (GOP size = 0f or 0c, 3-1 = 2 B-frames) */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300439 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
440 is_30fps ? 0x0f : 0x0c, 0x03);
Mike Iselyd8554972006-06-26 20:58:46 -0300441
442 /* enable 3:2 pulldown */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300443 ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_3_2_PULLDOWN,1,0);
Mike Iselyd8554972006-06-26 20:58:46 -0300444
445 /* set GOP open/close property (open) */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300446 ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_GOP_CLOSURE,1,0);
Mike Iselyd8554972006-06-26 20:58:46 -0300447
448 /* set audio stream properties 0x40b9? 0100 0000 1011 1001 */
449 audio = (pvr_tbl_audiobitrate[hdw->audiobitrate_val] |
450 pvr_tbl_srate[hdw->srate_val] |
451 hdw->audiolayer_val << 2 |
452 (hdw->audiocrc_val ? 1 << 14 : 0) |
453 pvr_tbl_emphasis[hdw->audioemphasis_val]);
454
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300455 ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_AUDIO_PROPERTIES,1,
456 audio);
Mike Iselyd8554972006-06-26 20:58:46 -0300457
458 /* set dynamic noise reduction filter to manual, Horiz/Vert */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300459 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
460 0, 0x03);
Mike Iselyd8554972006-06-26 20:58:46 -0300461
462 /* dynamic noise reduction filter param */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300463 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2
464 , 0, 0);
Mike Iselyd8554972006-06-26 20:58:46 -0300465
466 /* dynamic noise reduction median filter */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300467 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_CORING_LEVELS, 4,
468 0, 0xff, 0, 0xff);
Mike Iselyd8554972006-06-26 20:58:46 -0300469
470 /* spacial prefiler parameter */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300471 ret |= pvr2_encoder_vcmd(hdw,
472 CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
473 0x01, 0x01);
Mike Iselyd8554972006-06-26 20:58:46 -0300474
475 /* initialize video input */
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300476 ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
Mike Iselyd8554972006-06-26 20:58:46 -0300477
478 if (!ret) {
479 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
480 }
481
482 return ret;
483}
484
485int pvr2_encoder_start(struct pvr2_hdw *hdw)
486{
487 int status;
488
489 /* unmask some interrupts */
490 pvr2_write_register(hdw, 0x0048, 0xbfffffff);
491
492 /* change some GPIO data */
493 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
494 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
495
496 if (hdw->config == pvr2_config_vbi) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300497 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
498 0x01,0x14);
Mike Iselyd8554972006-06-26 20:58:46 -0300499 } else if (hdw->config == pvr2_config_mpeg) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300500 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
501 0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300502 } else {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300503 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
504 0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300505 }
506 if (!status) {
507 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
508 }
509 return status;
510}
511
512int pvr2_encoder_stop(struct pvr2_hdw *hdw)
513{
514 int status;
515
516 /* mask all interrupts */
517 pvr2_write_register(hdw, 0x0048, 0xffffffff);
518
519 if (hdw->config == pvr2_config_vbi) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300520 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
521 0x01,0x01,0x14);
Mike Iselyd8554972006-06-26 20:58:46 -0300522 } else if (hdw->config == pvr2_config_mpeg) {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300523 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
524 0x01,0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300525 } else {
Mike Iselyeacbe7c2006-06-25 20:04:06 -0300526 status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
527 0x01,0,0x13);
Mike Iselyd8554972006-06-26 20:58:46 -0300528 }
529
530 /* change some GPIO data */
531 /* Note: Bit d7 of dir appears to control the LED. So we shut it
532 off here. */
533 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
534 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
535
536 if (!status) {
537 hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
538 }
539 return status;
540}
541
542
543/*
544 Stuff for Emacs to see, in order to encourage consistent editing style:
545 *** Local Variables: ***
546 *** mode: c ***
547 *** fill-column: 70 ***
548 *** tab-width: 8 ***
549 *** c-basic-offset: 8 ***
550 *** End: ***
551 */