V4L/DVB (4244): Implement use of cx2341x module in pvrusb2 driver

Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
Mike Isely 2006-06-25 20:05:01 -03:00 committed by Mauro Carvalho Chehab
parent 1d9f8461f1
commit b30d244176
6 changed files with 303 additions and 294 deletions

View file

@ -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);
}

View file

@ -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 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);
int is_30fps, is_ntsc;
ret = 0;
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;
}
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 <isely@pobox.com> 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);
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);
/* set fps to 25 or 30 (1 or 0)*/
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_SET_FRAME_RATE, 1,
is_30fps ? 0 : 1);
if (!ret) ret = pvr2_encoder_vcmd(
hdw,CX2341X_ENC_SET_VBI_LINE, 5,
0xffffffff,0,0,0,0);
/* 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);
/* VBI */
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);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Failed to configure cx32416");
return ret;
}
/* 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<<PVR2_SUBSYS_B_ENC_CFG);
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;
}
return ret;
ret = 0;
if (!ret) ret = pvr2_encoder_vcmd(
hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Failed to initialize cx32416 video input");
return ret;
}
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
memcpy(&hdw->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;

View file

@ -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;

View file

@ -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,67 +711,12 @@ 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",
@ -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);
}

View file

@ -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

View file

@ -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);
}