summaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2006-06-26 01:05:01 +0200
committerMauro Carvalho Chehab <mchehab@infradead.org>2006-06-27 05:17:32 +0200
commitb30d244176846de3480ae17097a5f7831ec6aaf6 (patch)
treefba5650757a84032802b87635b7fe41d77c8e3cd /drivers/media/video
parentV4L/DVB (4243): Exploit new V4L control features in pvrusb2 (diff)
downloadlinux-b30d244176846de3480ae17097a5f7831ec6aaf6.tar.xz
linux-b30d244176846de3480ae17097a5f7831ec6aaf6.zip
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>
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c7
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c228
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c330
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h11
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.c7
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 47e7f5dbd516..27eadaff75a0 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 47c8e0203ce7..d944081072e6 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 <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);
+ 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<<PVR2_SUBSYS_B_ENC_CFG);
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to initialize cx32416 video input");
+ return ret;
}
- 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;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 3887190079d1..ba2afbfe32c5 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 45faabe96584..7d4799a1c554 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 779c27ea188e..63f529154431 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 4127c82f7bf6..e4ec7f25194c 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);
}