From b30d244176846de3480ae17097a5f7831ec6aaf6 Mon Sep 17 00:00:00 2001 From: Mike Isely Date: Sun, 25 Jun 2006 20:05:01 -0300 Subject: [PATCH] V4L/DVB (4244): Implement use of cx2341x module in pvrusb2 driver Signed-off-by: Mike Isely Signed-off-by: Mauro Carvalho Chehab --- drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c | 7 +- drivers/media/video/pvrusb2/pvrusb2-encoder.c | 228 +++----------- drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 16 +- drivers/media/video/pvrusb2/pvrusb2-hdw.c | 330 +++++++++++++++------ drivers/media/video/pvrusb2/pvrusb2-hdw.h | 11 - drivers/media/video/pvrusb2/pvrusb2-video-v4l.c | 7 +- 6 files changed, 304 insertions(+), 295 deletions(-) diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c index 47e7f5d..27eadaf 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -104,12 +104,15 @@ static void set_audio(struct pvr2_v4l_cx2584x *ctxt) hdw->srate_val); switch (hdw->srate_val) { default: - case PVR2_CVAL_SRATE_48: + case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000: val = 48000; break; - case PVR2_CVAL_SRATE_44_1: + case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100: val = 44100; break; + case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000: + val = 32000; + break; } pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c index 47c8e02..d944081 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c @@ -27,34 +27,6 @@ #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 */ @@ -316,171 +288,67 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd, return pvr2_encoder_cmd(hdw,cmd,args,0,data); } - int pvr2_encoder_configure(struct pvr2_hdw *hdw) { - int ret = 0, audio, i; - v4l2_std_id vd_std = hdw->std_mask_cur; - int height = hdw->res_ver_val; - int width = hdw->res_hor_val; - int height_full = !hdw->interlace_val; - - int is_30fps, is_ntsc; - - if (vd_std & V4L2_STD_NTSC) { - is_ntsc=1; - is_30fps=1; - } else if (vd_std & V4L2_STD_PAL_M) { - is_ntsc=0; - is_30fps=1; - } else { - is_ntsc=0; - is_30fps=0; - } + int ret; + pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure" + " (cx2341x module)"); + hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING; + hdw->enc_ctl_state.width = hdw->res_hor_val; + hdw->enc_ctl_state.height = hdw->res_ver_val; + hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur & + (V4L2_STD_NTSC|V4L2_STD_PAL_M)) ? + 0 : 1); - pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure (native)"); - - /* set stream output port. Some notes here: The ivtv-derived - encoder documentation says that this command only gets a - single argument. However the Windows driver for the model - 29xxx series hardware has been sending 0x01 as a second - argument, while the Windows driver for the model 24xxx - series hardware has been sending 0x02 as a second argument. - Confusing matters further are the observations that 0x01 - for that second argument simply won't work on the 24xxx - hardware, while 0x02 will work on the 29xxx - except that - when we use 0x02 then xawtv breaks due to a loss of - synchronization with the mpeg packet headers. While xawtv - should be fixed to let it resync better (I did try to - contact Gerd about this but he has not answered), it has - also been determined that sending 0x00 as this mystery - second argument seems to work on both hardware models AND - xawtv works again. So we're going to send 0x00. */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_OUTPUT_PORT, 2, - 0x01, 0x00); - - /* set the Program Index Information. We want I,P,B frames (max 400) */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_PGM_INDEX_INFO, 2, - 0x07, 0x0190); - - /* NOTE : windows driver sends these */ - /* Mike Isely 7-Mar-2006 The windows driver - sends the following commands but if we do the same then - many apps are no longer able to read the video stream. - Leaving these out seems to do no harm at all, so they're - commented out for that reason. */ -#ifdef notdef - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0); - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,1,0,0); - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0); - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0); - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0); - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0); -#endif - - /* Strange compared to ivtv data. */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, - 0xf0, 0xf0); + ret = 0; + + if (!ret) ret = pvr2_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_encoder_vcmd(hdw, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, - 0, 0, 0x10000000, 0xffffffff); + if (!ret) ret = pvr2_encoder_vcmd( + hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, + 0, 0, 0x10000000, 0xffffffff); + + if (!ret) ret = pvr2_encoder_vcmd( + hdw,CX2341X_ENC_SET_VBI_LINE, 5, + 0xffffffff,0,0,0,0); + + if (ret) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Failed to configure cx32416"); + return ret; + } - /* set fps to 25 or 30 (1 or 0)*/ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_RATE, 1, - is_30fps ? 0 : 1); + ret = cx2341x_update(hdw,pvr2_encoder_cmd, + (hdw->enc_cur_valid ? &hdw->enc_cur_state : 0), + &hdw->enc_ctl_state); + if (ret) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "Error from cx2341x module code=%d",ret); + return ret; + } - /* set encoding resolution */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_SIZE, 2, - (height_full ? height : (height / 2)), - width); - /* set encoding aspect ratio to 4:3 */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_ASPECT_RATIO, 1, - 0x02); + ret = 0; - /* VBI */ + if (!ret) ret = pvr2_encoder_vcmd( + hdw, CX2341X_ENC_INITIALIZE_INPUT, 0); - if (hdw->config == pvr2_config_vbi) { - int lines = 2 * (is_30fps ? 12 : 18); - int size = (4*((lines*1443+3)/4)) / lines; - ret |= pvr2_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_encoder_vcmd( - hdw,CX2341X_ENC_SET_VBI_LINE, 5, - i-1,line_used(i), 0, 0, 0); - ret |= pvr2_encoder_vcmd( - hdw,CX2341X_ENC_SET_VBI_LINE, 5, - (i-1) | (1 << 31), - line_used(i), 0, 0, 0); - } - } else { - ret |= pvr2_encoder_vcmd( - hdw,CX2341X_ENC_SET_VBI_LINE, 5, - 0xffffffff,0,0,0,0); - } - - /* set stream type, depending on resolution. */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_STREAM_TYPE, 1, - height_full ? 0x0a : 0x0b); - /* set video bitrate */ - ret |= pvr2_encoder_vcmd( - hdw, CX2341X_ENC_SET_BIT_RATE, 3, - (hdw->vbr_val ? 1 : 0), - hdw->videobitrate_val, - hdw->videopeak_val / 400); - /* setup GOP structure (GOP size = 0f or 0c, 3-1 = 2 B-frames) */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_GOP_PROPERTIES, 2, - is_30fps ? 0x0f : 0x0c, 0x03); - - /* enable 3:2 pulldown */ - ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_3_2_PULLDOWN,1,0); - - /* set GOP open/close property (open) */ - ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_GOP_CLOSURE,1,0); - - /* set audio stream properties 0x40b9? 0100 0000 1011 1001 */ - audio = (pvr_tbl_audiobitrate[hdw->audiobitrate_val] | - pvr_tbl_srate[hdw->srate_val] | - hdw->audiolayer_val << 2 | - (hdw->audiocrc_val ? 1 << 14 : 0) | - pvr_tbl_emphasis[hdw->audioemphasis_val]); - - ret |= pvr2_encoder_vcmd(hdw,CX2341X_ENC_SET_AUDIO_PROPERTIES,1, - audio); - - /* set dynamic noise reduction filter to manual, Horiz/Vert */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_MODE, 2, - 0, 0x03); - - /* dynamic noise reduction filter param */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2 - , 0, 0); - - /* dynamic noise reduction median filter */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_CORING_LEVELS, 4, - 0, 0xff, 0, 0xff); - - /* spacial prefiler parameter */ - ret |= pvr2_encoder_vcmd(hdw, - CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, - 0x01, 0x01); - - /* initialize video input */ - ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_INITIALIZE_INPUT, 0); - - if (!ret) { - hdw->subsys_enabled_mask |= (1<subsys_enabled_mask |= (1<enc_cur_state,&hdw->enc_ctl_state, + sizeof(struct cx2341x_mpeg_params)); + hdw->enc_cur_valid = !0; + return 0; } + int pvr2_encoder_start(struct pvr2_hdw *hdw) { int status; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 3887190..ba2afbf 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -322,6 +322,13 @@ struct pvr2_hdw { int flag_bilingual; struct pvr2_audio_stat *audio_stat; + /* Control state needed for cx2341x module */ + struct cx2341x_mpeg_params enc_cur_state; + struct cx2341x_mpeg_params enc_ctl_state; + /* True if an encoder attribute has changed */ + int enc_stale; + /* True if enc_cur_state is valid */ + int enc_cur_valid; /* Control state */ #define VCREATE_DATA(lab) int lab##_val; int lab##_dirty @@ -339,16 +346,9 @@ struct pvr2_hdw { VCREATE_DATA(res_hor); VCREATE_DATA(res_ver); VCREATE_DATA(srate); - VCREATE_DATA(audiobitrate); - VCREATE_DATA(audiocrc); - VCREATE_DATA(audioemphasis); - VCREATE_DATA(vbr); - VCREATE_DATA(videobitrate); - VCREATE_DATA(videopeak); - VCREATE_DATA(interlace); - VCREATE_DATA(audiolayer); #undef VCREATE_DATA + struct pvr2_ctld_info *mpeg_ctrl_info; struct pvr2_ctrl *controls; unsigned int control_cnt; diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 45faabe..7d4799a 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -130,6 +130,98 @@ MODULE_PARM_DESC(tolerance,"specify stream error tolerance"); /* size of a firmware chunk */ #define FIRMWARE_CHUNK_SIZE 0x2000 +/* Define the list of additional controls we'll dynamically construct based + on query of the cx2341x module. */ +struct pvr2_mpeg_ids { + const char *strid; + int id; +}; +static const struct pvr2_mpeg_ids mpeg_ids[] = { + { + .strid = "audio_layer", + .id = V4L2_CID_MPEG_AUDIO_ENCODING, + },{ + .strid = "audio_bitrate", + .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE, + },{ + /* Already using audio_mode elsewhere :-( */ + .strid = "mpeg_audio_mode", + .id = V4L2_CID_MPEG_AUDIO_MODE, + },{ + .strid = "mpeg_audio_mode_extension", + .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION, + },{ + .strid = "audio_emphasis", + .id = V4L2_CID_MPEG_AUDIO_EMPHASIS, + },{ + .strid = "audio_crc", + .id = V4L2_CID_MPEG_AUDIO_CRC, + },{ + .strid = "video_aspect", + .id = V4L2_CID_MPEG_VIDEO_ASPECT, + },{ + .strid = "video_b_frames", + .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, + },{ + .strid = "video_gop_size", + .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, + },{ + .strid = "video_gop_closure", + .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + },{ + .strid = "video_pulldown", + .id = V4L2_CID_MPEG_VIDEO_PULLDOWN, + },{ + .strid = "video_bitrate_mode", + .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + },{ + .strid = "video_bitrate", + .id = V4L2_CID_MPEG_VIDEO_BITRATE, + },{ + .strid = "video_bitrate_peak", + .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + },{ + .strid = "video_temporal_decimation", + .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, + },{ + .strid = "stream_type", + .id = V4L2_CID_MPEG_STREAM_TYPE, + },{ + .strid = "video_spatial_filter_mode", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE, + },{ + .strid = "video_spatial_filter", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER, + },{ + .strid = "video_luma_spatial_filter_type", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE, + },{ + .strid = "video_chroma_spatial_filter_type", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE, + },{ + .strid = "video_temporal_filter_mode", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE, + },{ + .strid = "video_temporal_filter", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER, + },{ + .strid = "video_median_filter_type", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE, + },{ + .strid = "video_luma_median_filter_top", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP, + },{ + .strid = "video_luma_median_filter_bottom", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM, + },{ + .strid = "video_chroma_median_filter_top", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP, + },{ + .strid = "video_chroma_median_filter_bottom", + .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM, + } +}; +#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0])) static const char *control_values_srate[] = { [PVR2_CVAL_SRATE_48] = "48KHz", @@ -137,30 +229,6 @@ static const char *control_values_srate[] = { }; -static const char *control_values_audiobitrate[] = { - [PVR2_CVAL_AUDIOBITRATE_384] = "384kb/s", - [PVR2_CVAL_AUDIOBITRATE_320] = "320kb/s", - [PVR2_CVAL_AUDIOBITRATE_256] = "256kb/s", - [PVR2_CVAL_AUDIOBITRATE_224] = "224kb/s", - [PVR2_CVAL_AUDIOBITRATE_192] = "192kb/s", - [PVR2_CVAL_AUDIOBITRATE_160] = "160kb/s", - [PVR2_CVAL_AUDIOBITRATE_128] = "128kb/s", - [PVR2_CVAL_AUDIOBITRATE_112] = "112kb/s", - [PVR2_CVAL_AUDIOBITRATE_96] = "96kb/s", - [PVR2_CVAL_AUDIOBITRATE_80] = "80kb/s", - [PVR2_CVAL_AUDIOBITRATE_64] = "64kb/s", - [PVR2_CVAL_AUDIOBITRATE_56] = "56kb/s", - [PVR2_CVAL_AUDIOBITRATE_48] = "48kb/s", - [PVR2_CVAL_AUDIOBITRATE_32] = "32kb/s", - [PVR2_CVAL_AUDIOBITRATE_VBR] = "VBR", -}; - - -static const char *control_values_audioemphasis[] = { - [PVR2_CVAL_AUDIOEMPHASIS_NONE] = "None", - [PVR2_CVAL_AUDIOEMPHASIS_50_15] = "50/15us", - [PVR2_CVAL_AUDIOEMPHASIS_CCITT] = "CCITT J.17", -}; static const char *control_values_input[] = { @@ -277,6 +345,76 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) return 0; } +static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr) +{ + return cptr->hdw->enc_stale != 0; +} + +static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr) +{ + cptr->hdw->enc_stale = 0; +} + +static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp) +{ + int ret; + struct v4l2_ext_controls cs; + struct v4l2_ext_control c1; + memset(&cs,0,sizeof(cs)); + memset(&c1,0,sizeof(c1)); + cs.controls = &c1; + cs.count = 1; + c1.id = cptr->info->v4l_id; + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + VIDIOC_G_EXT_CTRLS); + if (ret) return ret; + *vp = c1.value; + return 0; +} + +static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v) +{ + int ret; + struct v4l2_ext_controls cs; + struct v4l2_ext_control c1; + memset(&cs,0,sizeof(cs)); + memset(&c1,0,sizeof(c1)); + cs.controls = &c1; + cs.count = 1; + c1.id = cptr->info->v4l_id; + c1.value = v; + ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs, + VIDIOC_S_EXT_CTRLS); + if (ret) return ret; + cptr->hdw->enc_stale = !0; + return 0; +} + +static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr) +{ + struct v4l2_queryctrl qctrl; + struct pvr2_ctl_info *info; + qctrl.id = cptr->info->v4l_id; + cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl); + /* Strip out the const so we can adjust a function pointer. It's + OK to do this here because we know this is a dynamically created + control, so the underlying storage for the info pointer is (a) + private to us, and (b) not in read-only storage. Either we do + this or we significantly complicate the underlying control + implementation. */ + info = (struct pvr2_ctl_info *)(cptr->info); + if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) { + if (info->set_value) { + info->set_value = 0; + } + } else { + if (!(info->set_value)) { + info->set_value = ctrl_cx2341x_set; + } + } + return qctrl.flags; +} + static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp) { *vp = cptr->hdw->flag_streaming_enabled; @@ -475,14 +613,6 @@ VCREATE_FUNCS(audiomode) VCREATE_FUNCS(res_hor) VCREATE_FUNCS(res_ver) VCREATE_FUNCS(srate) -VCREATE_FUNCS(audiobitrate) -VCREATE_FUNCS(audiocrc) -VCREATE_FUNCS(audioemphasis) -VCREATE_FUNCS(vbr) -VCREATE_FUNCS(videobitrate) -VCREATE_FUNCS(videopeak) -VCREATE_FUNCS(interlace) -VCREATE_FUNCS(audiolayer) #define MIN_FREQ 55250000L #define MAX_FREQ 850000000L @@ -581,68 +711,13 @@ static const struct pvr2_ctl_info control_defs[] = { DEFREF(res_ver), DEFINT(200,625), },{ - .v4l_id = V4L2_CID_PVR_SRATE, + .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, .desc = "Sample rate", .name = "srate", .default_value = PVR2_CVAL_SRATE_48, DEFREF(srate), DEFENUM(control_values_srate), },{ - .v4l_id = V4L2_CID_PVR_AUDIOBITRATE, - .desc = "Audio Bitrate", - .name = "audio_bitrate", - .default_value = PVR2_CVAL_AUDIOBITRATE_224, - DEFREF(audiobitrate), - DEFENUM(control_values_audiobitrate), - },{ - .v4l_id = V4L2_CID_PVR_AUDIOCRC, - .desc = "Audio CRC", - .name = "audio_crc", - .default_value = 1, - DEFREF(audiocrc), - DEFBOOL, - },{ - .v4l_id = V4L2_CID_PVR_AUDIOEMPHASIS, - .desc = "Audio Emphasis", - .name = "audio_emphasis", - .default_value = PVR2_CVAL_AUDIOEMPHASIS_NONE, - DEFREF(audioemphasis), - DEFENUM(control_values_audioemphasis), - },{ - .v4l_id = V4L2_CID_PVR_VBR, - .desc = "Variable video bitrate", - .name = "vbr", - .default_value = 0, - DEFREF(vbr), - DEFBOOL, - },{ - .v4l_id = V4L2_CID_PVR_VIDEOBITRATE, - .desc = "Average video bitrate", - .name = "video_average_bitrate", - .default_value = 6000000, - DEFREF(videobitrate), - DEFINT(500000,20000000), - },{ - .v4l_id = V4L2_CID_PVR_VIDEOPEAK, - .desc = "Peak video bitrate", - .name = "video_peak_bitrate", - .default_value = 6000000, - DEFREF(videopeak), - DEFINT(500000,20000000), - },{ - .desc = "Interlace mode", - .name = "interlace", - .internal_id = PVR2_CID_INTERLACE, - .default_value = 0, - DEFREF(interlace), - DEFBOOL, - },{ - .desc = "Audio Layer", - .name = "audio_layer", - .default_value = 2, - DEFREF(audiolayer), - DEFINT(0,3), - },{ .desc = "Tuner Frequency (Hz)", .name = "frequency", .internal_id = PVR2_CID_FREQUENCY, @@ -958,6 +1033,10 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) if (ret < 0) return ret; fwidx = ret; ret = 0; + /* Since we're about to completely reinitialize the encoder, + invalidate our cached copy of its configuration state. Next + time we configure the encoder, then we'll fully configure it. */ + hdw->enc_cur_valid = 0; /* First prepare firmware loading */ ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/ @@ -1654,6 +1733,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, int valid_std_mask; struct pvr2_ctrl *cptr; __u8 ifnum; + struct v4l2_queryctrl qctrl; + struct pvr2_ctl_info *ciptr; hdw_type = devid - pvr2_device_table; if (hdw_type >= @@ -1668,8 +1749,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw,pvr2_device_names[hdw_type]); if (!hdw) goto fail; memset(hdw,0,sizeof(*hdw)); + cx2341x_fill_defaults(&hdw->enc_ctl_state); hdw->control_cnt = CTRLDEF_COUNT; + hdw->control_cnt += MPEGDEF_COUNT; hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt, GFP_KERNEL); if (!hdw->controls) goto fail; @@ -1686,6 +1769,54 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, cptr = hdw->controls + idx; cptr->info = control_defs+idx; } + /* Define and configure additional controls from cx2341x module. */ + hdw->mpeg_ctrl_info = kmalloc( + sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL); + if (!hdw->mpeg_ctrl_info) goto fail; + memset(hdw->mpeg_ctrl_info,0, + sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT); + for (idx = 0; idx < MPEGDEF_COUNT; idx++) { + cptr = hdw->controls + idx + CTRLDEF_COUNT; + ciptr = &(hdw->mpeg_ctrl_info[idx].info); + ciptr->desc = hdw->mpeg_ctrl_info[idx].desc; + ciptr->name = mpeg_ids[idx].strid; + ciptr->v4l_id = mpeg_ids[idx].id; + ciptr->skip_init = !0; + ciptr->get_value = ctrl_cx2341x_get; + ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags; + ciptr->is_dirty = ctrl_cx2341x_is_dirty; + if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty; + qctrl.id = ciptr->v4l_id; + cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl); + if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) { + ciptr->set_value = ctrl_cx2341x_set; + } + strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name, + PVR2_CTLD_INFO_DESC_SIZE); + hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0; + ciptr->default_value = qctrl.default_value; + switch (qctrl.type) { + default: + case V4L2_CTRL_TYPE_INTEGER: + ciptr->type = pvr2_ctl_int; + ciptr->def.type_int.min_value = qctrl.minimum; + ciptr->def.type_int.max_value = qctrl.maximum; + break; + case V4L2_CTRL_TYPE_BOOLEAN: + ciptr->type = pvr2_ctl_bool; + break; + case V4L2_CTRL_TYPE_MENU: + ciptr->type = pvr2_ctl_enum; + ciptr->def.type_enum.value_names = + cx2341x_ctrl_get_menu(ciptr->v4l_id); + for (cnt1 = 0; + ciptr->def.type_enum.value_names[cnt1] != NULL; + cnt1++) { } + ciptr->def.type_enum.count = cnt1; + break; + } + cptr->info = ciptr; + } // Initialize video standard enum dynamic control cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM); @@ -1788,6 +1919,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer); if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer); if (hdw->controls) kfree(hdw->controls); + if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info); kfree(hdw); } return 0; @@ -1853,6 +1985,7 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw) } } while (0); up(&pvr2_unit_sem); if (hdw->controls) kfree(hdw->controls); + if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info); if (hdw->std_defs) kfree(hdw->std_defs); if (hdw->std_enum_names) kfree(hdw->std_enum_names); kfree(hdw); @@ -2104,10 +2237,6 @@ int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) hdw->res_ver_val = nvres; hdw->res_ver_dirty = !0; } - if (!hdw->interlace_val) { - hdw->interlace_val = 0; - hdw->interlace_dirty = !0; - } } if (hdw->std_dirty || @@ -2118,6 +2247,21 @@ int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw) stale_subsys_mask |= hdw->subsys_stream_mask; } + if (hdw->srate_dirty) { + /* Write new sample rate into control structure since + * the master copy is stale. We must track srate + * separate from the mpeg control structure because + * other logic also uses this value. */ + struct v4l2_ext_controls cs; + struct v4l2_ext_control c1; + memset(&cs,0,sizeof(cs)); + memset(&c1,0,sizeof(c1)); + cs.controls = &c1; + cs.count = 1; + c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ; + c1.value = hdw->srate_val; + cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS); + } /* Scan i2c core at this point - before we clear all the dirty bits. Various parts of the i2c core will notice dirty bits as @@ -2262,6 +2406,8 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw) pvr2_i2c_core_check_stale(hdw); hdw->log_requested = 0; pvr2_i2c_core_sync(hdw); + pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:"); + cx2341x_log_status(&hdw->enc_ctl_state,0); printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr); } while (0); LOCK_GIVE(hdw->big_lock); } diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 779c27e..63f5291 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -26,16 +26,6 @@ #include "pvrusb2-io.h" #include "pvrusb2-ctrl.h" -/* Private V4L2-compatible controls available in this driver, look these up - with pvr2_hdw_get_ctrl_v4l(). */ -#define V4L2_CID_PVR_SRATE (V4L2_CID_PRIVATE_BASE) -#define V4L2_CID_PVR_AUDIOBITRATE (V4L2_CID_PRIVATE_BASE+1) -#define V4L2_CID_PVR_AUDIOCRC (V4L2_CID_PRIVATE_BASE+2) -#define V4L2_CID_PVR_AUDIOEMPHASIS (V4L2_CID_PRIVATE_BASE+3) -#define V4L2_CID_PVR_VBR (V4L2_CID_PRIVATE_BASE+4) -#define V4L2_CID_PVR_VIDEOBITRATE (V4L2_CID_PRIVATE_BASE+5) -#define V4L2_CID_PVR_VIDEOPEAK (V4L2_CID_PRIVATE_BASE+6) -#define V4L2_CID_PVR_VIDEOSTANDARD (V4L2_CID_PRIVATE_BASE+7) /* Private internal control ids, look these up with pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */ @@ -47,7 +37,6 @@ #define PVR2_CID_FREQUENCY 6 #define PVR2_CID_HRES 7 #define PVR2_CID_VRES 8 -#define PVR2_CID_INTERLACE 9 /* Legal values for the INPUT state variable */ #define PVR2_CVAL_INPUT_TV 0 diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c index 4127c82..e4ec7f2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c @@ -91,12 +91,15 @@ static void set_audio(struct pvr2_v4l_decoder *ctxt) hdw->srate_val); switch (hdw->srate_val) { default: - case PVR2_CVAL_SRATE_48: + case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000: val = 48000; break; - case PVR2_CVAL_SRATE_44_1: + case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100: val = 44100; break; + case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000: + val = 32000; + break; } pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val); } -- 2.7.4