]> err.no Git - linux-2.6/blobdiff - drivers/media/video/pvrusb2/pvrusb2-hdw.c
V4L/DVB (7779): pvrusb2-dvb: quiet down noise in kernel log for feed debug
[linux-2.6] / drivers / media / video / pvrusb2 / pvrusb2-hdw.c
index 63d0af759ed8646053973a9fdf5f331bcf81286d..0a868888f389d2e74004051558511b90a8dd2b88 100644 (file)
@@ -249,6 +249,7 @@ static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = {
 };
 
 
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
 static void pvr2_hdw_state_sched(struct pvr2_hdw *);
 static int pvr2_hdw_state_eval(struct pvr2_hdw *);
 static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
@@ -404,30 +405,12 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
 
 static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
 {
-       return ((1 << v) & cptr->hdw->input_avail_mask) != 0;
+       return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
 }
 
 static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
 {
-       struct pvr2_hdw *hdw = cptr->hdw;
-
-       if (hdw->input_val != v) {
-               hdw->input_val = v;
-               hdw->input_dirty = !0;
-       }
-
-       /* Handle side effects - if we switch to a mode that needs the RF
-          tuner, then select the right frequency choice as well and mark
-          it dirty. */
-       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
-               hdw->freqSelector = 0;
-               hdw->freqDirty = !0;
-       } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) ||
-                  (hdw->input_val == PVR2_CVAL_INPUT_DTV)) {
-               hdw->freqSelector = 1;
-               hdw->freqDirty = !0;
-       }
-       return 0;
+       return pvr2_hdw_set_input(cptr->hdw,v);
 }
 
 static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
@@ -1269,7 +1252,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "firmware2 upload prep failed, ret=%d",ret);
                release_firmware(fw_entry);
-               return ret;
+               goto done;
        }
 
        /* Now send firmware */
@@ -1282,7 +1265,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                           " must be a multiple of %zu bytes",
                           fw_files[fwidx],sizeof(u32));
                release_firmware(fw_entry);
-               return -1;
+               ret = -EINVAL;
+               goto done;
        }
 
        fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
@@ -1290,7 +1274,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                release_firmware(fw_entry);
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "failed to allocate memory for firmware2 upload");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto done;
        }
 
        pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
@@ -1321,7 +1306,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "firmware2 upload transfer failure");
-               return ret;
+               goto done;
        }
 
        /* Finish upload */
@@ -1334,6 +1319,14 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
                           "firmware2 upload post-proc failure");
        }
+
+ done:
+       if (hdw->hdw_desc->signal_routing_scheme ==
+           PVR2_ROUTING_SCHEME_GOTVIEW) {
+               /* Ensure that GPIO 11 is set to output for GOTVIEW
+                  hardware. */
+               pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+       }
        return ret;
 }
 
@@ -1748,6 +1741,13 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
 
        if (!pvr2_hdw_dev_ok(hdw)) return;
 
+       if (hdw->hdw_desc->signal_routing_scheme ==
+           PVR2_ROUTING_SCHEME_GOTVIEW) {
+               /* Ensure that GPIO 11 is set to output for GOTVIEW
+                  hardware. */
+               pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+       }
+
        pvr2_hdw_commit_setup(hdw);
 
        hdw->vid_stream = pvr2_stream_create();
@@ -1916,6 +1916,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
        if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE;
        if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
        hdw->input_avail_mask = m;
+       hdw->input_allowed_mask = hdw->input_avail_mask;
 
        /* If not a hybrid device, pathway_state never changes.  So
           initialize it here to what it should forever be. */
@@ -2510,6 +2511,20 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
                hdw->active_stream_type = hdw->desired_stream_type;
        }
 
+       if (hdw->hdw_desc->signal_routing_scheme ==
+           PVR2_ROUTING_SCHEME_GOTVIEW) {
+               u32 b;
+               /* Handle GOTVIEW audio switching */
+               pvr2_hdw_gpio_get_out(hdw,&b);
+               if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+                       /* Set GPIO 11 */
+                       pvr2_hdw_gpio_chg_out(hdw,(1 << 11),~0);
+               } else {
+                       /* Clear GPIO 11 */
+                       pvr2_hdw_gpio_chg_out(hdw,(1 << 11),0);
+               }
+       }
+
        /* Now execute i2c core update */
        pvr2_i2c_core_sync(hdw);
 
@@ -3948,6 +3963,24 @@ static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
 }
 
 
+static unsigned int print_input_mask(unsigned int msk,
+                                    char *buf,unsigned int acnt)
+{
+       unsigned int idx,ccnt;
+       unsigned int tcnt = 0;
+       for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) {
+               if (!((1 << idx) & msk)) continue;
+               ccnt = scnprintf(buf+tcnt,
+                                acnt-tcnt,
+                                "%s%s",
+                                (tcnt ? ", " : ""),
+                                control_values_input[idx]);
+               tcnt += ccnt;
+       }
+       return tcnt;
+}
+
+
 static const char *pvr2_pathway_state_name(int id)
 {
        switch (id) {
@@ -4016,6 +4049,28 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
                        "state: %s",
                        pvr2_get_state_name(hdw->master_state));
        case 4: {
+               unsigned int tcnt = 0;
+               unsigned int ccnt;
+
+               ccnt = scnprintf(buf,
+                                acnt,
+                                "Hardware supported inputs: ");
+               tcnt += ccnt;
+               tcnt += print_input_mask(hdw->input_avail_mask,
+                                        buf+tcnt,
+                                        acnt-tcnt);
+               if (hdw->input_avail_mask != hdw->input_allowed_mask) {
+                       ccnt = scnprintf(buf+tcnt,
+                                        acnt-tcnt,
+                                        "; allowed inputs: ");
+                       tcnt += ccnt;
+                       tcnt += print_input_mask(hdw->input_allowed_mask,
+                                                buf+tcnt,
+                                                acnt-tcnt);
+               }
+               return tcnt;
+       }
+       case 5: {
                struct pvr2_stream_stats stats;
                if (!hdw->vid_stream) break;
                pvr2_stream_get_stats(hdw->vid_stream,
@@ -4210,6 +4265,74 @@ unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw)
 }
 
 
+unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw)
+{
+       return hdw->input_allowed_mask;
+}
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v)
+{
+       if (hdw->input_val != v) {
+               hdw->input_val = v;
+               hdw->input_dirty = !0;
+       }
+
+       /* Handle side effects - if we switch to a mode that needs the RF
+          tuner, then select the right frequency choice as well and mark
+          it dirty. */
+       if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+               hdw->freqSelector = 0;
+               hdw->freqDirty = !0;
+       } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) ||
+                  (hdw->input_val == PVR2_CVAL_INPUT_DTV)) {
+               hdw->freqSelector = 1;
+               hdw->freqDirty = !0;
+       }
+       return 0;
+}
+
+
+int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw,
+                              unsigned int change_mask,
+                              unsigned int change_val)
+{
+       int ret = 0;
+       unsigned int nv,m,idx;
+       LOCK_TAKE(hdw->big_lock);
+       do {
+               nv = hdw->input_allowed_mask & ~change_mask;
+               nv |= (change_val & change_mask);
+               nv &= hdw->input_avail_mask;
+               if (!nv) {
+                       /* No legal modes left; return error instead. */
+                       ret = -EPERM;
+                       break;
+               }
+               hdw->input_allowed_mask = nv;
+               if ((1 << hdw->input_val) & hdw->input_allowed_mask) {
+                       /* Current mode is still in the allowed mask, so
+                          we're done. */
+                       break;
+               }
+               /* Select and switch to a mode that is still in the allowed
+                  mask */
+               if (!hdw->input_allowed_mask) {
+                       /* Nothing legal; give up */
+                       break;
+               }
+               m = hdw->input_allowed_mask;
+               for (idx = 0; idx < (sizeof(m) << 3); idx++) {
+                       if (!((1 << idx) & m)) continue;
+                       pvr2_hdw_set_input(hdw,idx);
+                       break;
+               }
+       } while (0);
+       LOCK_GIVE(hdw->big_lock);
+       return ret;
+}
+
+
 /* Find I2C address of eeprom */
 static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
 {