diff options
Diffstat (limited to 'v4l_experimental/pvrusb2/pvrusb2-encoder.c')
-rw-r--r-- | v4l_experimental/pvrusb2/pvrusb2-encoder.c | 494 |
1 files changed, 0 insertions, 494 deletions
diff --git a/v4l_experimental/pvrusb2/pvrusb2-encoder.c b/v4l_experimental/pvrusb2/pvrusb2-encoder.c deleted file mode 100644 index 046cd9f1f..000000000 --- a/v4l_experimental/pvrusb2/pvrusb2-encoder.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * - * $Id: pvrusb2-encoder.c,v 1.5 2006/01/14 20:11:08 mcisely Exp $ - * - * Copyright (C) 2005 Mike Isely <isely@pobox.com> - * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include <linux/device.h> // for linux/firmware.h -#include <linux/firmware.h> -#include "cx2341x.h" -#include "pvrusb2-util.h" -#include "pvrusb2-encoder.h" -#include "pvrusb2-hdw-internal.h" -#include "pvrusb2-debug.h" - -static u32 pvr_tbl_emphasis [] = { - [PVR2_CVAL_AUDIOEMPHASIS_NONE] = 0x0 << 12, - [PVR2_CVAL_AUDIOEMPHASIS_50_15] = 0x1 << 12, - [PVR2_CVAL_AUDIOEMPHASIS_CCITT] = 0x3 << 12, -}; - -static u32 pvr_tbl_srate[] = { - [PVR2_CVAL_SRATE_48] = 0x01, - [PVR2_CVAL_SRATE_44_1] = 0x00, -}; - -static u32 pvr_tbl_audiobitrate[] = { - [PVR2_CVAL_AUDIOBITRATE_384] = 0xe << 4, - [PVR2_CVAL_AUDIOBITRATE_320] = 0xd << 4, - [PVR2_CVAL_AUDIOBITRATE_256] = 0xc << 4, - [PVR2_CVAL_AUDIOBITRATE_224] = 0xb << 4, - [PVR2_CVAL_AUDIOBITRATE_192] = 0xa << 4, - [PVR2_CVAL_AUDIOBITRATE_160] = 0x9 << 4, - [PVR2_CVAL_AUDIOBITRATE_128] = 0x8 << 4, - [PVR2_CVAL_AUDIOBITRATE_112] = 0x7 << 4, - [PVR2_CVAL_AUDIOBITRATE_96] = 0x6 << 4, - [PVR2_CVAL_AUDIOBITRATE_80] = 0x5 << 4, - [PVR2_CVAL_AUDIOBITRATE_64] = 0x4 << 4, - [PVR2_CVAL_AUDIOBITRATE_56] = 0x3 << 4, - [PVR2_CVAL_AUDIOBITRATE_48] = 0x2 << 4, - [PVR2_CVAL_AUDIOBITRATE_32] = 0x1 << 4, - [PVR2_CVAL_AUDIOBITRATE_VBR] = 0x0 << 4, -}; - - -/* Firmware mailbox flags - definitions found from ivtv */ -#define IVTV_MBOX_FIRMWARE_DONE 0x00000004 -#define IVTV_MBOX_DRIVER_DONE 0x00000002 -#define IVTV_MBOX_DRIVER_BUSY 0x00000001 - - -static int pvr2_write_encoder_words(struct pvr2_hdw *hdw, - const u32 *data, unsigned int dlen) -{ - unsigned int idx; - int ret; - unsigned int offs = 0; - unsigned int chunkCnt; - - /* - - Format: First byte must be 0x01. Remaining 32 bit words are - spread out into chunks of 7 bytes each, little-endian ordered, - offset at zero within each 2 blank bytes following and a - single byte that is 0x44 plus the offset of the word. Repeat - request for additional words, with offset adjusted - accordingly. - - */ - while (dlen) { - chunkCnt = 8; - if (chunkCnt > dlen) chunkCnt = dlen; - memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer)); - hdw->cmd_buffer[0] = 0x01; - for (idx = 0; idx < chunkCnt; idx++) { - hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs; - PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7), - data[idx]); - } - ret = pvr2_send_request(hdw, - hdw->cmd_buffer,1+(chunkCnt*7), - 0,0); - if (ret) return ret; - data += chunkCnt; - dlen -= chunkCnt; - offs += chunkCnt; - } - - return 0; -} - - -static int pvr2_read_encoder_words(struct pvr2_hdw *hdw,int statusFl, - u32 *data, unsigned int dlen) -{ - unsigned int idx; - int ret; - unsigned int offs = 0; - unsigned int chunkCnt; - - /* - - Format: First byte must be 0x02 (status check) or 0x28 (read - back block of 32 bit words). Next 6 bytes must be zero, - followed by a single byte of 0x44+offset for portion to be - read. Returned data is packed set of 32 bits words that were - read. - - */ - - while (dlen) { - chunkCnt = 16; - if (chunkCnt > dlen) chunkCnt = dlen; - memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer)); - hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28; - hdw->cmd_buffer[7] = 0x44 + offs; - ret = pvr2_send_request(hdw, - hdw->cmd_buffer,8, - hdw->cmd_buffer,chunkCnt * 4); - if (ret) return ret; - - for (idx = 0; idx < chunkCnt; idx++) { - data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4); - } - data += chunkCnt; - dlen -= chunkCnt; - offs += chunkCnt; - } - - return 0; -} - - -static int pvr2_write_encoder_vcmd (struct pvr2_hdw *hdw, u8 cmd, - int args, ...) -{ - unsigned int poll_count; - int ret = 0; - va_list vl; - unsigned int idx; - u32 wrData[16]; - u32 rdData[32]; - - /* - - The encoder seems to speak entirely using blocks 32 bit words. - In ivtv driver terms, this is a mailbox which we populate with - data and watch what the hardware does with it. The first word - is a set of flags used to control the transaction, the second - word is the command to execute, the third byte is zero (ivtv - driver suggests that this is some kind of return value), and - the fourth byte is a specified timeout (windows driver always - uses 0x00060000 except for one case when it is zero). All - successive words are the argument words for the command. - - First, write out the entire set of words, with the first word - being zero. - - Next, write out just the first word again, but set it to - IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which - probably means "go"). - - Next, read back 16 words as status. Check the first word, - which should have IVTV_MBOX_FIRMWARE_DONE set. If however - that bit is not set, then the command isn't done so repeat the - read. - - Next, read back 32 words and compare with the original - arugments. Hopefully they will match. - - Finally, write out just the first word again, but set it to - 0x0 this time (which probably means "idle"). - - */ - - - LOCK_TAKE(hdw->ctl_lock); do { - - wrData[0] = 0; - wrData[1] = cmd; - wrData[2] = 0; - wrData[3] = 0x00060000; - va_start(vl, args); - for (idx = 0; idx < args; idx++) { - wrData[idx+4] = va_arg(vl, u32); - } - va_end(vl); - args += 4; - while (args < sizeof(wrData)/sizeof(wrData[0])) { - wrData[args++] = 0; - } - - ret = pvr2_write_encoder_words(hdw,wrData,args); - if (ret) break; - wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY; - ret = pvr2_write_encoder_words(hdw,wrData,1); - if (ret) break; - poll_count = 0; - while (1) { - if (poll_count < 10000000) poll_count++; - ret = pvr2_read_encoder_words(hdw,!0,rdData,1); - if (ret) break; - if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) { - break; - } - if (poll_count == 100) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "***WARNING*** device's encoder" - " appears to be stuck" - " (status=0%08x)",rdData[0]); - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Encoder command: 0x%02x",cmd); - for (idx = 4; idx < args; idx++) { - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Encoder arg%d: 0x%08x", - idx-3,wrData[idx]); - } - pvr2_trace( - PVR2_TRACE_ERROR_LEGS, - "Giving up waiting." - " It is likely that" - " this is a bad idea..."); - ret = -EBUSY; - break; - } - } - if (ret) break; - wrData[0] = 0x7; - ret = pvr2_read_encoder_words(hdw,0,rdData,16); - if (ret) break; - for (idx = 0; idx < args; idx++) { - if (rdData[idx] != wrData[idx]) { - pvr2_trace( - PVR2_TRACE_DEBUG, - "pvr2_encoder idx %02x mismatch exp:" - " %08x got: %08x", - idx,wrData[idx],rdData[idx]); - } - } - - wrData[0] = 0x0; - ret = pvr2_write_encoder_words(hdw,wrData,1); - if (ret) break; - - } while(0); LOCK_GIVE(hdw->ctl_lock); - - return ret; -} - -int pvr2_encoder_configure(struct pvr2_hdw *hdw) -{ - int ret = 0, audio, i; - int vd_std = hdw->controls[PVR2_CID_VIDEOSTANDARD].value; - int height = hdw->controls[PVR2_CID_VRES].value; - int width = hdw->controls[PVR2_CID_HRES].value; - int height_full = !hdw->controls[PVR2_CID_INTERLACE].value; - - int is_30fps, is_ntsc; - - switch (vd_std) { - case PVR2_CVAL_VIDEOSTANDARD_NTSC_M: - is_ntsc=1; - is_30fps=1; - break; - case PVR2_CVAL_VIDEOSTANDARD_PAL_M: - is_ntsc=0; - is_30fps=1; - break; - default: - is_ntsc=0; - is_30fps=0; - break; - } - - pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure"); - - /* set stream output port. */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_OUTPUT_PORT, 2, - 0x01, 0x01); - - /* set the Program Index Information. We want I,P,B frames (max 400) */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, - 0x07, 0x0190); - - /* NOTE : windows driver sends some 0xdc */ - - /* Mike Isely <isely@pobox.com> 19-Jun-2005 I've confirmed - that the Windows driver seems to issue these commands, but - right now I have no idea what these do (and neither does - the ivtv driver). But, if I leave them in, then mplayer - goes nuts with xrun errors. So for now we don't do this. - It sure would be nice to know what these are for. */ -#ifdef notdef - ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 1, 5); - ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 2, 3, 1); - ret |= pvr2_write_encoder_vcmd(hdw, 0xdc, 1, 8); -#endif - - /* Strange compared to ivtv data. */ -#ifdef notdef - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, - 0x0120, 0x0120); - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, - 0x0131, 0x0131); -#endif - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, - 0xf0, 0xf0); - - /* setup firmware to notify us about some events (don't know why...) */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, - 0, 0, 0x10000000, 0xffffffff); - - /* set fps to 25 or 30 (1 or 0)*/ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_RATE, 1, - is_30fps ? 0 : 1); - - /* set encoding resolution */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_SIZE, 2, - (height_full ? height : (height / 2)), - width); - /* set encoding aspect ratio to 4:3 */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_ASPECT_RATIO, 1, - 0x02); - - /* VBI */ - - if (hdw->config == pvr2_config_vbi) { - int lines = 2 * (is_30fps ? 12 : 18); - int size = (4*((lines*1443+3)/4)) / lines; - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_VBI_CONFIG, 7, - 0xbd05, 1, 4, - 0x25256262, 0x387f7f7f, - lines , size); -// 0x25256262, 0x13135454, lines , size); - /* select vbi lines */ -#define line_used(l) (is_30fps ? (l >= 10 && l <= 21) : (l >= 6 && l <= 23)) - for (i = 2 ; i <= 24 ; i++){ - ret |= pvr2_write_encoder_vcmd( - hdw,CX2341X_ENC_SET_VBI_LINE, 5, - i-1,line_used(i), 0, 0, 0); - ret |= pvr2_write_encoder_vcmd( - hdw,CX2341X_ENC_SET_VBI_LINE, 5, - (i-1) | (1 << 31), - line_used(i), 0, 0, 0); - } - } else { - ret |= pvr2_write_encoder_vcmd( - hdw,CX2341X_ENC_SET_VBI_LINE, 5, - 0xffffffff,0,0,0,0); - } - - /* set stream type, depending on resolution. */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_STREAM_TYPE, 1, - height_full ? 0x0a : 0x0b); - /* set video bitrate */ - ret |= pvr2_write_encoder_vcmd( - hdw, CX2341X_ENC_SET_BIT_RATE, 3, - (hdw->controls[PVR2_CID_VBR].value ? 1 : 0), - hdw->controls[PVR2_CID_AVERAGEVIDEOBITRATE].value, - (u32) (hdw->controls[PVR2_CID_PEAKVIDEOBITRATE].value) / 400); - /* setup GOP structure (GOP size = 0f or 0c, 3-1 = 2 B-frames) */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_GOP_PROPERTIES, 2, - is_30fps ? 0x0f : 0x0c, 0x03); - - /* enable 3:2 pulldown */ - ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_3_2_PULLDOWN,1,0); - - /* set GOP open/close property (open) */ - ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_GOP_CLOSURE,1,0); - - /* set audio stream properties 0x40b9? 0100 0000 1011 1001 */ - audio = (pvr_tbl_audiobitrate[hdw->controls[ - PVR2_CID_AUDIOBITRATE].value] | - pvr_tbl_srate[hdw->controls[PVR2_CID_SRATE].value] | - hdw->controls[PVR2_CID_AUDIOLAYER].value << 2 | - (hdw->controls[PVR2_CID_AUDIOCRC].value ? 1 << 14 : 0) | - pvr_tbl_emphasis[hdw->controls[ - PVR2_CID_AUDIOEMPHASIS].value]); - - ret |= pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_SET_AUDIO_PROPERTIES,1, - audio); - - /* set dynamic noise reduction filter to manual, Horiz/Vert */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, - 0, 0x03); - - /* dynamic noise reduction filter param */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2 - , 0, 0); - - /* dynamic noise reduction median filter */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_SET_CORING_LEVELS, 4, - 0, 0xff, 0, 0xff); - - /* spacial prefiler parameter */ - ret |= pvr2_write_encoder_vcmd(hdw, - CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, - 0x01, 0x01); - - /* initialize video input */ - ret |= pvr2_write_encoder_vcmd(hdw, CX2341X_ENC_INITIALIZE_INPUT, 0); - - if (!ret) { - hdw->subsys_enabled_mask |= PVR2_SUBSYS_ENC_CFG; - } - - return ret; -} - -int pvr2_encoder_start(struct pvr2_hdw *hdw) -{ - int status; - - /* unmask some interrupts */ - pvr2_write_register(hdw, 0x0048, 0xbfffffff); - - /* change some GPIO data */ - pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481); - pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000); - - if (hdw->config == pvr2_config_vbi) { - status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, - 0x01,0x14); - } else if (hdw->config == pvr2_config_mpeg) { - status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, - 0,0x13); - } else { - status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2, - 0,0x13); - } - if (!status) { - hdw->subsys_enabled_mask |= PVR2_SUBSYS_ENC_RUN; - } - return status; -} - -int pvr2_encoder_stop(struct pvr2_hdw *hdw) -{ - int status; - - /* mask all interrupts */ - pvr2_write_register(hdw, 0x0048, 0xffffffff); - - if (hdw->config == pvr2_config_vbi) { - status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, - 0x01,0x01,0x14); - } else if (hdw->config == pvr2_config_mpeg) { - status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, - 0x01,0,0x13); - } else { - status = pvr2_write_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3, - 0x01,0,0x13); - } - - /* change some GPIO data */ - /* Note: Bit d7 of dir appears to control the LED. So we shut it - off here. */ - pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401); - pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000); - - if (!status) { - hdw->subsys_enabled_mask &= ~PVR2_SUBSYS_ENC_RUN; - } - return status; -} - - -/* - Stuff for Emacs to see, in order to encourage consistent editing style: - *** Local Variables: *** - *** mode: c *** - *** fill-column: 70 *** - *** tab-width: 8 *** - *** c-basic-offset: 8 *** - *** End: *** - */ |