aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pvrusb2/pvrusb2-encoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-encoder.c')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c499
1 files changed, 499 insertions, 0 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
new file mode 100644
index 000000000000..0917fe315f3c
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -0,0 +1,499 @@
1/*
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
68static int pvr2_write_encoder_words(struct pvr2_hdw *hdw,
69 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
109static int pvr2_read_encoder_words(struct pvr2_hdw *hdw,int statusFl,
110 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
150static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd,
151 int args, ...)
152{
153 unsigned int poll_count;
154 int ret = 0;
155 va_list vl;
156 unsigned int idx;
157 u32 wrData[16];
158 u32 rdData[32];
159
160 /*
161
162 The encoder seems to speak entirely using blocks 32 bit words.
163 In ivtv driver terms, this is a mailbox which we populate with
164 data and watch what the hardware does with it. The first word
165 is a set of flags used to control the transaction, the second
166 word is the command to execute, the third byte is zero (ivtv
167 driver suggests that this is some kind of return value), and
168 the fourth byte is a specified timeout (windows driver always
169 uses 0x00060000 except for one case when it is zero). All
170 successive words are the argument words for the command.
171
172 First, write out the entire set of words, with the first word
173 being zero.
174
175 Next, write out just the first word again, but set it to
176 IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
177 probably means "go").
178
179 Next, read back 16 words as status. Check the first word,
180 which should have IVTV_MBOX_FIRMWARE_DONE set. If however
181 that bit is not set, then the command isn't done so repeat the
182 read.
183
184 Next, read back 32 words and compare with the original
185 arugments. Hopefully they will match.
186
187 Finally, write out just the first word again, but set it to
188 0x0 this time (which probably means "idle").
189
190 */
191
192
193 LOCK_TAKE(hdw->ctl_lock); do {
194
195 wrData[0] = 0;
196 wrData[1] = cmd;
197 wrData[2] = 0;
198 wrData[3] = 0x00060000;
199 va_start(vl, args);
200 for (idx = 0; idx < args; idx++) {
201 wrData[idx+4] = va_arg(vl, u32);
202 }
203 va_end(vl);
204 args += 4;
205 while (args < sizeof(wrData)/sizeof(wrData[0])) {
206 wrData[args++] = 0;
207 }
208
209 ret = pvr2_write_encoder_words(hdw,wrData,args);
210 if (ret) break;
211 wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
212 ret = pvr2_write_encoder_words(hdw,wrData,1);
213 if (ret) break;
214 poll_count = 0;
215 while (1) {
216 if (poll_count < 10000000) poll_count++;
217 ret = pvr2_read_encoder_words(hdw,!0,rdData,1);
218 if (ret) break;
219 if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
220 break;
221 }
222 if (poll_count == 100) {
223 pvr2_trace(
224 PVR2_TRACE_ERROR_LEGS,
225 "***WARNING*** device's encoder"
226 " appears to be stuck"
227 " (status=0%08x)",rdData[0]);
228 pvr2_trace(
229 PVR2_TRACE_ERROR_LEGS,
230 "Encoder command: 0x%02x",cmd);
231 for (idx = 4; idx < args; idx++) {
232 pvr2_trace(
233 PVR2_TRACE_ERROR_LEGS,
234 "Encoder arg%d: 0x%08x",
235 idx-3,wrData[idx]);
236 }
237 pvr2_trace(
238 PVR2_TRACE_ERROR_LEGS,
239 "Giving up waiting."
240 " It is likely that"
241 " this is a bad idea...");
242 ret = -EBUSY;
243 break;
244 }
245 }
246 if (ret) break;
247 wrData[0] = 0x7;
248 ret = pvr2_read_encoder_words(hdw,0,rdData,16);
249 if (ret) break;
250 for (idx = 0; idx < args; idx++) {
251 if (rdData[idx] != wrData[idx]) {
252 pvr2_trace(
253 PVR2_TRACE_DEBUG,
254 "pvr2_encoder idx %02x mismatch exp:"
255 " %08x got: %08x",
256 idx,wrData[idx],rdData[idx]);
257 }
258 }
259
260 wrData[0] = 0x0;
261 ret = pvr2_write_encoder_words(hdw,wrData,1);
262 if (ret) break;
263
264 } while(0); LOCK_GIVE(hdw->ctl_lock);
265
266 return ret;
267}
268
269int pvr2_encoder_configure(struct pvr2_hdw *hdw)
270{
271 int ret = 0, audio, i;
272 v4l2_std_id vd_std = hdw->std_mask_cur;
273 int height = hdw->res_ver_val;
274 int width = hdw->res_hor_val;
275 int height_full = !hdw->interlace_val;
276
277 int is_30fps, is_ntsc;
278
279 if (vd_std & V4L2_STD_NTSC) {
280 is_ntsc=1;
281 is_30fps=1;
282 } else if (vd_std & V4L2_STD_PAL_M) {
283 is_ntsc=0;
284 is_30fps=1;
285 } else {
286 is_ntsc=0;
287 is_30fps=0;
288 }
289
290 pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure");
291
292 /* set stream output port. Some notes here: The ivtv-derived
293 encoder documentation says that this command only gets a
294 single argument. However the Windows driver for the model
295 29xxx series hardware has been sending 0x01 as a second
296 argument, while the Windows driver for the model 24xxx
297 series hardware has been sending 0x02 as a second argument.
298 Confusing matters further are the observations that 0x01
299 for that second argument simply won't work on the 24xxx
300 hardware, while 0x02 will work on the 29xxx - except that
301 when we use 0x02 then xawtv breaks due to a loss of
302 synchronization with the mpeg packet headers. While xawtv
303 should be fixed to let it resync better (I did try to
304 contact Gerd about this but he has not answered), it has
305 also been determined that sending 0x00 as this mystery
306 second argument seems to work on both hardware models AND
307 xawtv works again. So we're going to send 0x00. */
308 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_OUTPUT_PORT, 2,
309 0x01, 0x00);
310
311 /* set the Program Index Information. We want I,P,B frames (max 400) */
312 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_PGM_INDEX_INFO, 2,
313 0x07, 0x0190);
314
315 /* NOTE : windows driver sends these */
316 /* Mike Isely <isely@pobox.com> 7-Mar-2006 The windows driver
317 sends the following commands but if we do the same then
318 many apps are no longer able to read the video stream.
319 Leaving these out seems to do no harm at all, so they're
320 commented out for that reason. */
321#ifdef notdef
322 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
323 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,1,0,0);
324 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
325 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
326 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
327 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
328#endif
329
330 /* Strange compared to ivtv data. */
331 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
332 0xf0, 0xf0);
333
334 /* setup firmware to notify us about some events (don't know why...) */
335 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
336 0, 0, 0x10000000, 0xffffffff);
337
338 /* set fps to 25 or 30 (1 or 0)*/
339 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_RATE, 1,
340 is_30fps ? 0 : 1);
341
342 /* set encoding resolution */
343 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_SIZE, 2,
344 (height_full ? height : (height / 2)),
345 width);
346 /* set encoding aspect ratio to 4:3 */
347 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_ASPECT_RATIO, 1,
348 0x02);
349
350 /* VBI */
351
352 if (hdw->config == pvr2_config_vbi) {
353 int lines = 2 * (is_30fps ? 12 : 18);
354 int size = (4*((lines*1443+3)/4)) / lines;
355 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_VBI_CONFIG, 7,
356 0xbd05, 1, 4,
357 0x25256262, 0x387f7f7f,
358 lines , size);
359// 0x25256262, 0x13135454, lines , size);
360 /* select vbi lines */
361#define line_used(l) (is_30fps ? (l >= 10 && l <= 21) : (l >= 6 && l <= 23))
362 for (i = 2 ; i <= 24 ; i++){
363 ret |= pvr2_write_encoder_vcmd(
364 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
365 i-1,line_used(i), 0, 0, 0);
366 ret |= pvr2_write_encoder_vcmd(
367 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
368 (i-1) | (1 << 31),
369 line_used(i), 0, 0, 0);
370 }
371 } else {
372 ret |= pvr2_write_encoder_vcmd(
373 hdw,CX2341X_ENC_SET_VBI_LINE, 5,
374 0xffffffff,0,0,0,0);
375 }
376
377 /* set stream type, depending on resolution. */
378 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_STREAM_TYPE, 1,
379 height_full ? 0x0a : 0x0b);
380 /* set video bitrate */
381 ret |= pvr2_write_encoder_vcmd(
382 hdw, CX2341X_ENC_SET_BIT_RATE, 3,
383 (hdw->vbr_val ? 1 : 0),
384 hdw->videobitrate_val,
385 hdw->videopeak_val / 400);
386 /* setup GOP structure (GOP size = 0f or 0c, 3-1 = 2 B-frames) */
387 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
388 is_30fps ? 0x0f : 0x0c, 0x03);
389
390 /* enable 3:2 pulldown */
391 ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_3_2_PULLDOWN,1,0);
392
393 /* set GOP open/close property (open) */
394 ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_GOP_CLOSURE,1,0);
395
396 /* set audio stream properties 0x40b9? 0100 0000 1011 1001 */
397 audio = (pvr_tbl_audiobitrate[hdw->audiobitrate_val] |
398 pvr_tbl_srate[hdw->srate_val] |
399 hdw->audiolayer_val << 2 |
400 (hdw->audiocrc_val ? 1 << 14 : 0) |
401 pvr_tbl_emphasis[hdw->audioemphasis_val]);
402
403 ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_AUDIO_PROPERTIES,1,
404 audio);
405
406 /* set dynamic noise reduction filter to manual, Horiz/Vert */
407 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
408 0, 0x03);
409
410 /* dynamic noise reduction filter param */
411 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2
412 , 0, 0);
413
414 /* dynamic noise reduction median filter */
415 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_CORING_LEVELS, 4,
416 0, 0xff, 0, 0xff);
417
418 /* spacial prefiler parameter */
419 ret |= pvr2_write_encoder_vcmd(hdw,
420 CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
421 0x01, 0x01);
422
423 /* initialize video input */
424 ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
425
426 if (!ret) {
427 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
428 }
429
430 return ret;
431}
432
433int pvr2_encoder_start(struct pvr2_hdw *hdw)
434{
435 int status;
436
437 /* unmask some interrupts */
438 pvr2_write_register(hdw, 0x0048, 0xbfffffff);
439
440 /* change some GPIO data */
441 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
442 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
443
444 if (hdw->config == pvr2_config_vbi) {
445 status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
446 0x01,0x14);
447 } else if (hdw->config == pvr2_config_mpeg) {
448 status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
449 0,0x13);
450 } else {
451 status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
452 0,0x13);
453 }
454 if (!status) {
455 hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
456 }
457 return status;
458}
459
460int pvr2_encoder_stop(struct pvr2_hdw *hdw)
461{
462 int status;
463
464 /* mask all interrupts */
465 pvr2_write_register(hdw, 0x0048, 0xffffffff);
466
467 if (hdw->config == pvr2_config_vbi) {
468 status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
469 0x01,0x01,0x14);
470 } else if (hdw->config == pvr2_config_mpeg) {
471 status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
472 0x01,0,0x13);
473 } else {
474 status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
475 0x01,0,0x13);
476 }
477
478 /* change some GPIO data */
479 /* Note: Bit d7 of dir appears to control the LED. So we shut it
480 off here. */
481 pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
482 pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
483
484 if (!status) {
485 hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
486 }
487 return status;
488}
489
490
491/*
492 Stuff for Emacs to see, in order to encourage consistent editing style:
493 *** Local Variables: ***
494 *** mode: c ***
495 *** fill-column: 70 ***
496 *** tab-width: 8 ***
497 *** c-basic-offset: 8 ***
498 *** End: ***
499 */