V4L/DVB (4244): Implement use of cx2341x module in pvrusb2 driver
authorMike Isely <isely@pobox.com>
Sun, 25 Jun 2006 23:05:01 +0000 (20:05 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Tue, 27 Jun 2006 03:17:32 +0000 (00:17 -0300)
Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
drivers/media/video/pvrusb2/pvrusb2-encoder.c
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-hdw.h
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c

index 47e7f5d..27eadaf 100644 (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);
 }
index 47c8e02..d944081 100644 (file)
 #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;
index 3887190..ba2afbf 100644 (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;
index 45faabe..7d4799a 100644 (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,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);
 }
index 779c27e..63f5291 100644 (file)
 #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
index 4127c82..e4ec7f2 100644 (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);
 }