aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/pvrusb2/pvrusb2-hdw.c
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2008-04-21 03:47:43 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 14:09:49 -0300
commit1cb03b76d09d20accfa5c1664c16ba6566f539a0 (patch)
tree8c58f23151ab54f71472b80f6d0d29df25ddbb9f /drivers/media/video/pvrusb2/pvrusb2-hdw.c
parentd3f8d8fb304a8b9a81eae16ff7b50f5379f2437e (diff)
V4L/DVB (7719): pvrusb2: Implement input selection enforcement
In the pvrusb2 driver, different interfaces (e.g. V4L, DVB) have Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-hdw.c')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c132
1 files changed, 112 insertions, 20 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 63d0af759ed..72e9056557b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -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)
@@ -1916,6 +1899,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. */
@@ -3948,6 +3932,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 +4018,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 +4234,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)
{