V4L/DVB (5081): Pvrusb2: VIDIOC_G_TUNER cleanup
authorMike Isely <isely@pobox.com>
Sat, 20 Jan 2007 03:09:47 +0000 (00:09 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Wed, 21 Feb 2007 15:34:38 +0000 (13:34 -0200)
Clean up use of VIDIOC_G_TUNER; we now correctly gather info from all
the I2C client modules.  Also abide by V4L2_TUNER_CAP_LOW
appropriately.

Signed-off-by: Mike Isely <isely@pobox.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
12 files changed:
drivers/media/video/pvrusb2/pvrusb2-audio.c
drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.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-i2c-chips-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pvrusb2/pvrusb2-video-v4l.c

index 122496f368458f71161743a537c3c1924853660f..5d30c93661442c5203c8845096ca7677a91696f0 100644 (file)
@@ -31,7 +31,6 @@ struct pvr2_msp3400_handler {
        struct pvr2_hdw *hdw;
        struct pvr2_i2c_client *client;
        struct pvr2_i2c_handler i2c_handler;
-       struct pvr2_audio_stat astat;
        unsigned long stale_mask;
 };
 
@@ -126,27 +125,9 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
 }
 
 
-/* This reads back the current signal type */
-static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
-{
-       struct v4l2_tuner vt;
-       int stat;
-
-       memset(&vt,0,sizeof(vt));
-       stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
-       if (stat < 0) return stat;
-
-       ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
-       ctxt->hdw->flag_bilingual =
-               (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
-       return 0;
-}
-
-
 static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
 {
        ctxt->client->handler = NULL;
-       ctxt->hdw->audio_stat = NULL;
        kfree(ctxt);
 }
 
@@ -169,7 +150,6 @@ static const struct pvr2_i2c_handler_functions msp3400_funcs = {
 int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
 {
        struct pvr2_msp3400_handler *ctxt;
-       if (hdw->audio_stat) return 0;
        if (cp->handler) return 0;
 
        ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
@@ -180,13 +160,9 @@ int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
        ctxt->i2c_handler.func_table = &msp3400_funcs;
        ctxt->client = cp;
        ctxt->hdw = hdw;
-       ctxt->astat.ctxt = ctxt;
-       ctxt->astat.status = (int (*)(void *))get_audio_status;
-       ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
        ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
                                  sizeof(msp3400_ops[0]))) - 1;
        cp->handler = &ctxt->i2c_handler;
-       hdw->audio_stat = &ctxt->astat;
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
                   cp->client->addr);
        return !0;
index c2a154e4ec5994d2a4ee9b027de5c87b4e2969c6..a3357bf2a1af4b5c20560a1ab64563df26bb1214 100644 (file)
@@ -199,18 +199,6 @@ static int decoder_detect(struct pvr2_i2c_client *cp)
 }
 
 
-static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
-{
-       struct v4l2_tuner vt;
-       int ret;
-
-       memset(&vt,0,sizeof(vt));
-       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
-       if (ret < 0) return -EINVAL;
-       return vt.signal ? 1 : 0;
-}
-
-
 static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
                                     char *buf,unsigned int cnt)
 {
@@ -252,7 +240,6 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
        ctxt->ctrl.ctxt = ctxt;
        ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
        ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
-       ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
        ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
        ctxt->client = cp;
        ctxt->hdw = hdw;
index b9df52c882a82ff47dae29a954e550bd6497e372..bc911ff753062d92bca1cd62e2f43b9126197d31 100644 (file)
@@ -137,17 +137,10 @@ struct pvr2_ctrl {
 };
 
 
-struct pvr2_audio_stat {
-       void *ctxt;
-       void (*detach)(void *);
-       int (*status)(void *);
-};
-
 struct pvr2_decoder_ctrl {
        void *ctxt;
        void (*detach)(void *);
        void (*enable)(void *,int);
-       int (*tuned)(void *);
        void (*force_reset)(void *);
 };
 
@@ -266,6 +259,10 @@ struct pvr2_hdw {
        unsigned int freqSelector;       /* 0=radio 1=television */
        int freqDirty;
 
+       /* Current tuner info - this information is polled from the I2C bus */
+       struct v4l2_tuner tuner_signal_info;
+       int tuner_signal_stale;
+
        /* Video standard handling */
        v4l2_std_id std_mask_eeprom; // Hardware supported selections
        v4l2_std_id std_mask_avail;  // Which standards we may select from
@@ -297,11 +294,6 @@ struct pvr2_hdw {
 
        enum pvr2_config config;
 
-       /* Information about what audio signal we're hearing */
-       int flag_stereo;
-       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;
index 2de595112224021c2444fc0d10711888b1a98cfc..4672199ae92d7c61dfb9e2c8fd5db278c3cca21c 100644 (file)
@@ -264,7 +264,6 @@ static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
 static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
 static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
 static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
 static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
@@ -623,8 +622,34 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
 
 static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
 {
-       *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
-               PVR2_SIGNAL_OK) ? 1 : 0);
+       struct pvr2_hdw *hdw = cptr->hdw;
+       pvr2_i2c_core_status_poll(hdw);
+       *vp = hdw->tuner_signal_info.signal;
+       return 0;
+}
+
+static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+{
+       int val = 0;
+       unsigned int subchan;
+       struct pvr2_hdw *hdw = cptr->hdw;
+       if (hdw->tuner_signal_stale) {
+               pvr2_i2c_core_status_poll(hdw);
+       }
+       subchan = hdw->tuner_signal_info.rxsubchans;
+       if (subchan & V4L2_TUNER_SUB_MONO) {
+               val |= (1 << V4L2_TUNER_MODE_MONO);
+       }
+       if (subchan & V4L2_TUNER_SUB_STEREO) {
+               val |= (1 << V4L2_TUNER_MODE_STEREO);
+       }
+       if (subchan & V4L2_TUNER_SUB_LANG1) {
+               val |= (1 << V4L2_TUNER_MODE_LANG1);
+       }
+       if (subchan & V4L2_TUNER_SUB_LANG2) {
+               val |= (1 << V4L2_TUNER_MODE_LANG2);
+       }
+       *vp = val;
        return 0;
 }
 
@@ -898,7 +923,20 @@ static const struct pvr2_ctl_info control_defs[] = {
                .desc = "Signal Present",
                .name = "signal_present",
                .get_value = ctrl_signal_get,
-               DEFBOOL,
+               DEFINT(0,65535),
+       },{
+               .desc = "Audio Modes Present",
+               .name = "audio_modes_present",
+               .get_value = ctrl_audio_modes_present_get,
+               /* For this type we "borrow" the V4L2_TUNER_MODE enum from
+                  v4l.  Nothing outside of this module cares about this,
+                  but I reuse it in order to also reuse the
+                  control_values_audiomode string table. */
+               DEFMASK(((1 << V4L2_TUNER_MODE_MONO)|
+                        (1 << V4L2_TUNER_MODE_STEREO)|
+                        (1 << V4L2_TUNER_MODE_LANG1)|
+                        (1 << V4L2_TUNER_MODE_LANG2)),
+                       control_values_audiomode),
        },{
                .desc = "Video Standards Available Mask",
                .name = "video_standard_mask_available",
@@ -1957,6 +1995,7 @@ 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));
+       hdw->tuner_signal_stale = !0;
        cx2341x_fill_defaults(&hdw->enc_ctl_state);
 
        hdw->control_cnt = CTRLDEF_COUNT;
@@ -2179,9 +2218,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
                pvr2_stream_destroy(hdw->vid_stream);
                hdw->vid_stream = NULL;
        }
-       if (hdw->audio_stat) {
-               hdw->audio_stat->detach(hdw->audio_stat->ctxt);
-       }
        if (hdw->decoder_ctrl) {
                hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
        }
@@ -2547,34 +2583,6 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
 }
 
 
-/* Return bit mask indicating signal status */
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
-{
-       unsigned int msk = 0;
-       switch (hdw->input_val) {
-       case PVR2_CVAL_INPUT_TV:
-       case PVR2_CVAL_INPUT_RADIO:
-               if (hdw->decoder_ctrl &&
-                   hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
-                       msk |= PVR2_SIGNAL_OK;
-                       if (hdw->audio_stat &&
-                           hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
-                               if (hdw->flag_stereo) {
-                                       msk |= PVR2_SIGNAL_STEREO;
-                               }
-                               if (hdw->flag_bilingual) {
-                                       msk |= PVR2_SIGNAL_SAP;
-                               }
-                       }
-               }
-               break;
-       default:
-               msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
-       }
-       return msk;
-}
-
-
 int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
 {
        int result;
@@ -2590,14 +2598,25 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
 }
 
 
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+/* Execute poll of tuner status */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
 {
-       unsigned int msk = 0;
        LOCK_TAKE(hdw->big_lock); do {
-               msk = pvr2_hdw_get_signal_status_internal(hdw);
+               pvr2_i2c_core_status_poll(hdw);
        } while (0); LOCK_GIVE(hdw->big_lock);
-       return msk;
+}
+
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
+{
+       LOCK_TAKE(hdw->big_lock); do {
+               if (hdw->tuner_signal_stale) {
+                       pvr2_i2c_core_status_poll(hdw);
+               }
+               memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
+       } while (0); LOCK_GIVE(hdw->big_lock);
+       return 0;
 }
 
 
index d803f24cc9e022c7459e34e4e50b951755ece388..dc7a3ba8dd18b4ea44b471ad213086e35a33b6f5 100644 (file)
 #define PVR2_CVAL_INPUT_COMPOSITE 2
 #define PVR2_CVAL_INPUT_RADIO 3
 
-/* Values that pvr2_hdw_get_signal_status() returns */
-#define PVR2_SIGNAL_OK     0x0001
-#define PVR2_SIGNAL_STEREO 0x0002
-#define PVR2_SIGNAL_SAP    0x0004
-
-
 /* Subsystem definitions - these are various pieces that can be
    independently stopped / started.  Usually you don't want to mess with
    this directly (let the driver handle things itself), but it is useful
@@ -155,8 +149,11 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
 /* Return name for this driver instance */
 const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
 
-/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+/* Mark tuner status stale so that it will be re-fetched */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
 
 /* Query device and see if it thinks it is on a high-speed USB link */
 int pvr2_hdw_is_hsm(struct pvr2_hdw *);
index 05121666b9ba5c6a516dcf76023c7a4602ac8401..16fa075a1eecd230dac4aa3c9aa4b11c203099c1 100644 (file)
@@ -59,6 +59,7 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
                        (1 << OP_FREQ) |
                        (1 << OP_SIZE) |
                        (1 << OP_LOG));
+       cp->status_poll = pvr2_v4l2_cmd_status_poll;
 
        if (id == I2C_DRIVERID_MSP3400) {
                if (pvr2_i2c_msp3400_setup(hdw,cp)) {
index 51da8945efe4110a7c785bcee8c9758deed7f4f3..b1f6809625e872ebcd69a3be565f18d756655b76 100644 (file)
@@ -37,6 +37,7 @@ static void set_standard(struct pvr2_hdw *hdw)
                vs = hdw->std_mask_cur;
                pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
        }
+       hdw->tuner_signal_stale = !0;
 }
 
 
@@ -145,13 +146,21 @@ static void set_frequency(struct pvr2_hdw *hdw)
        struct v4l2_frequency freq;
        fv = pvr2_hdw_get_cur_freq(hdw);
        pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+       if (hdw->tuner_signal_stale) {
+               pvr2_i2c_core_status_poll(hdw);
+       }
        memset(&freq,0,sizeof(freq));
-       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+       if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
                // ((fv * 1000) / 62500)
                freq.frequency = (fv * 2) / 125;
-               freq.type = V4L2_TUNER_RADIO;
        } else {
                freq.frequency = fv / 62500;
+       }
+       /* tuner-core currently doesn't seem to care about this, but
+          let's set it anyway for completeness. */
+       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+               freq.type = V4L2_TUNER_RADIO;
+       } else {
                freq.type = V4L2_TUNER_ANALOG_TV;
        }
        freq.tuner = 0;
@@ -230,6 +239,12 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
 }
 
 
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
+{
+       pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+}
+
+
 /*
   Stuff for Emacs to see, in order to encourage consistent editing style:
   *** Local Variables: ***
index 894de610893b6c808a8dc810a5916e06e0f060e8..6a9bb46d0654598d06f85908e7139eba619da503 100644 (file)
@@ -34,6 +34,7 @@ extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
 extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
 
 void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
 
 #endif /* __PVRUSB2_CMD_V4L2_H */
 
index 62a7cfca837dae7846a5faf299f88ccb4977527e..35a06652a60c786e6e3d4196faf7a49d8140834d 100644 (file)
@@ -590,6 +590,27 @@ static int handler_check(struct pvr2_i2c_client *cp)
 
 #define BUFSIZE 500
 
+
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
+{
+       struct list_head *item;
+       struct pvr2_i2c_client *cp;
+       mutex_lock(&hdw->i2c_list_lock); do {
+               struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+               memset(vtp,0,sizeof(vtp));
+               list_for_each(item,&hdw->i2c_clients) {
+                       cp = list_entry(item,struct pvr2_i2c_client,list);
+                       if (!cp->detected_flag) continue;
+                       if (!cp->status_poll) continue;
+                       cp->status_poll(cp);
+               }
+               hdw->tuner_signal_stale = 0;
+       } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+
+/* Issue various I2C operations to bring chip-level drivers into sync with
+   state stored in this driver. */
 void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
 {
        unsigned long msk;
@@ -876,6 +897,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
                  client->addr,cp);
        if (!cp) return -ENOMEM;
        memset(cp,0,sizeof(*cp));
+       cp->hdw = hdw;
        INIT_LIST_HEAD(&cp->list);
        cp->client = client;
        mutex_lock(&hdw->i2c_list_lock); do {
index 6d7e252475760fd2dbb5f20986d11ab7991f1b85..bd0807b905bbdb9ce4d4039ab7be099c59d1ea84 100644 (file)
@@ -35,10 +35,12 @@ struct pvr2_i2c_client {
        struct i2c_client *client;
        struct pvr2_i2c_handler *handler;
        struct list_head list;
+       struct pvr2_hdw *hdw;
        int detected_flag;
        int recv_enable;
        unsigned long pend_mask;
        unsigned long ctl_mask;
+       void (*status_poll)(struct pvr2_i2c_client *);
 };
 
 struct pvr2_i2c_handler {
@@ -67,6 +69,7 @@ int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
 
 int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
 void pvr2_i2c_core_sync(struct pvr2_hdw *);
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
 unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
 #define PVR2_I2C_DETAIL_DEBUG   0x0001
 #define PVR2_I2C_DETAIL_HANDLER 0x0002
index 655a722289eda682be8e8776baf85374c0800025..2a67638652662b0f2259d6d055c309d04aecb7fe 100644 (file)
@@ -95,25 +95,6 @@ static struct v4l2_capability pvr_capability ={
        .reserved       = {0,0,0,0}
 };
 
-static struct v4l2_tuner pvr_v4l2_tuners[]= {
-       {
-               .index      = 0,
-               .name       = "TV Tuner",
-               .type           = V4L2_TUNER_ANALOG_TV,
-               .capability     = (V4L2_TUNER_CAP_NORM |
-                                  V4L2_TUNER_CAP_STEREO |
-                                  V4L2_TUNER_CAP_LANG1 |
-                                  V4L2_TUNER_CAP_LANG2),
-               .rangelow   = 0,
-               .rangehigh  = 0,
-               .rxsubchans     = V4L2_TUNER_SUB_STEREO,
-               .audmode        = V4L2_TUNER_MODE_STEREO,
-               .signal         = 0,
-               .afc            = 0,
-               .reserved       = {0,0,0,0}
-       }
-};
-
 static struct v4l2_fmtdesc pvr_fmtdesc [] = {
        {
                .index          = 0,
@@ -358,34 +339,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
        case VIDIOC_G_TUNER:
        {
                struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
-               unsigned int status_mask;
-               int val;
-               if (vt->index !=0) break;
-
-               status_mask = pvr2_hdw_get_signal_status(hdw);
-
-               memcpy(vt, &pvr_v4l2_tuners[vt->index],
-                      sizeof(struct v4l2_tuner));
-
-               vt->signal = 0;
-               if (status_mask & PVR2_SIGNAL_OK) {
-                       if (status_mask & PVR2_SIGNAL_STEREO) {
-                               vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
-                       } else {
-                               vt->rxsubchans = V4L2_TUNER_SUB_MONO;
-                       }
-                       if (status_mask & PVR2_SIGNAL_SAP) {
-                               vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
-                                                  V4L2_TUNER_SUB_LANG2);
-                       }
-                       vt->signal = 65535;
-               }
-
-               val = 0;
-               ret = pvr2_ctrl_get_value(
-                       pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
-                       &val);
-               vt->audmode = val;
+               pvr2_hdw_execute_tuner_poll(hdw);
+               ret = pvr2_hdw_get_tuner_status(hdw,vt);
                break;
        }
 
@@ -405,8 +360,27 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
        {
                const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
                unsigned long fv;
-               fv = vf->frequency;
+               struct v4l2_tuner vt;
+               int cur_input;
+               struct pvr2_ctrl *ctrlp;
+               ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+               if (ret != 0) break;
+               ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+               ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
+               if (ret != 0) break;
                if (vf->type == V4L2_TUNER_RADIO) {
+                       if (cur_input != PVR2_CVAL_INPUT_RADIO) {
+                               pvr2_ctrl_set_value(ctrlp,
+                                                   PVR2_CVAL_INPUT_RADIO);
+                       }
+               } else {
+                       if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+                               pvr2_ctrl_set_value(ctrlp,
+                                                   PVR2_CVAL_INPUT_TV);
+                       }
+               }
+               fv = vf->frequency;
+               if (vt.capability & V4L2_TUNER_CAP_LOW) {
                        fv = (fv * 125) / 2;
                } else {
                        fv = fv * 62500;
@@ -420,7 +394,10 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
        {
                struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
                int val = 0;
-               int cur_input = PVR2_CVAL_INPUT_TV;
+               int cur_input;
+               struct v4l2_tuner vt;
+               ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+               if (ret != 0) break;
                ret = pvr2_ctrl_get_value(
                        pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
                        &val);
@@ -429,14 +406,16 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
                        pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
                        &cur_input);
                if (cur_input == PVR2_CVAL_INPUT_RADIO) {
-                       val = (val * 2) / 125;
-                       vf->frequency = val;
                        vf->type = V4L2_TUNER_RADIO;
                } else {
-                       val /= 62500;
-                       vf->frequency = val;
                        vf->type = V4L2_TUNER_ANALOG_TV;
                }
+               if (vt.capability & V4L2_TUNER_CAP_LOW) {
+                       val = (val * 2) / 125;
+               } else {
+                       val /= 62500;
+               }
+               vf->frequency = val;
                break;
        }
 
index 2a826464911a7e6d0f553c029970b19f60d8c0f3..8b37748cfcba6023d3378de9da8e0f3a6df0206b 100644 (file)
@@ -183,18 +183,6 @@ static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
 }
 
 
-static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt)
-{
-       struct v4l2_tuner vt;
-       int ret;
-
-       memset(&vt,0,sizeof(vt));
-       ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
-       if (ret < 0) return -EINVAL;
-       return vt.signal ? 1 : 0;
-}
-
-
 static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
 {
        return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
@@ -227,7 +215,6 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
        ctxt->ctrl.ctxt = ctxt;
        ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
        ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
-       ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
        ctxt->client = cp;
        ctxt->hdw = hdw;
        ctxt->stale_mask = (1 << (sizeof(decoder_ops)/