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:
Родитель
1d9f8461f1
Коммит
b30d244176
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче