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>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
d3f8d8fb30
commit
1cb03b76d0
@@ -245,6 +245,22 @@ struct pvr2_context *pvr2_context_create(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
|
||||||
|
{
|
||||||
|
unsigned int tmsk,mmsk;
|
||||||
|
struct pvr2_channel *cp;
|
||||||
|
struct pvr2_hdw *hdw = mp->hdw;
|
||||||
|
mmsk = pvr2_hdw_get_input_available(hdw);
|
||||||
|
tmsk = mmsk;
|
||||||
|
for (cp = mp->mc_first; cp; cp = cp->mc_next) {
|
||||||
|
if (!cp->input_mask) continue;
|
||||||
|
tmsk &= cp->input_mask;
|
||||||
|
}
|
||||||
|
pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
|
||||||
|
pvr2_hdw_commit_ctl(hdw);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void pvr2_context_enter(struct pvr2_context *mp)
|
static void pvr2_context_enter(struct pvr2_context *mp)
|
||||||
{
|
{
|
||||||
mutex_lock(&mp->mutex);
|
mutex_lock(&mp->mutex);
|
||||||
@@ -300,7 +316,9 @@ void pvr2_channel_done(struct pvr2_channel *cp)
|
|||||||
{
|
{
|
||||||
struct pvr2_context *mp = cp->mc_head;
|
struct pvr2_context *mp = cp->mc_head;
|
||||||
pvr2_context_enter(mp);
|
pvr2_context_enter(mp);
|
||||||
|
cp->input_mask = 0;
|
||||||
pvr2_channel_disclaim_stream(cp);
|
pvr2_channel_disclaim_stream(cp);
|
||||||
|
pvr2_context_reset_input_limits(mp);
|
||||||
if (cp->mc_next) {
|
if (cp->mc_next) {
|
||||||
cp->mc_next->mc_prev = cp->mc_prev;
|
cp->mc_next->mc_prev = cp->mc_prev;
|
||||||
} else {
|
} else {
|
||||||
@@ -316,6 +334,57 @@ void pvr2_channel_done(struct pvr2_channel *cp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
|
||||||
|
{
|
||||||
|
unsigned int tmsk,mmsk;
|
||||||
|
int ret = 0;
|
||||||
|
struct pvr2_channel *p2;
|
||||||
|
struct pvr2_hdw *hdw = cp->hdw;
|
||||||
|
|
||||||
|
mmsk = pvr2_hdw_get_input_available(hdw);
|
||||||
|
cmsk &= mmsk;
|
||||||
|
if (cmsk == cp->input_mask) {
|
||||||
|
/* No change; nothing to do */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pvr2_context_enter(cp->mc_head);
|
||||||
|
do {
|
||||||
|
if (!cmsk) {
|
||||||
|
cp->input_mask = 0;
|
||||||
|
pvr2_context_reset_input_limits(cp->mc_head);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tmsk = mmsk;
|
||||||
|
for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
|
||||||
|
if (p2 == cp) continue;
|
||||||
|
if (!p2->input_mask) continue;
|
||||||
|
tmsk &= p2->input_mask;
|
||||||
|
}
|
||||||
|
if (!(tmsk & cmsk)) {
|
||||||
|
ret = -EPERM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tmsk &= cmsk;
|
||||||
|
if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
|
||||||
|
/* Internal failure changing allowed list; probably
|
||||||
|
should not happen, but react if it does. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cp->input_mask = cmsk;
|
||||||
|
pvr2_hdw_commit_ctl(hdw);
|
||||||
|
} while (0);
|
||||||
|
pvr2_context_exit(cp->mc_head);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
|
||||||
|
{
|
||||||
|
return cp->input_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int pvr2_channel_claim_stream(struct pvr2_channel *cp,
|
int pvr2_channel_claim_stream(struct pvr2_channel *cp,
|
||||||
struct pvr2_context_stream *sp)
|
struct pvr2_context_stream *sp)
|
||||||
{
|
{
|
||||||
|
@@ -62,6 +62,7 @@ struct pvr2_channel {
|
|||||||
struct pvr2_channel *mc_prev;
|
struct pvr2_channel *mc_prev;
|
||||||
struct pvr2_context_stream *stream;
|
struct pvr2_context_stream *stream;
|
||||||
struct pvr2_hdw *hdw;
|
struct pvr2_hdw *hdw;
|
||||||
|
unsigned int input_mask;
|
||||||
void (*check_func)(struct pvr2_channel *);
|
void (*check_func)(struct pvr2_channel *);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -72,6 +73,8 @@ void pvr2_context_disconnect(struct pvr2_context *);
|
|||||||
|
|
||||||
void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *);
|
void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *);
|
||||||
void pvr2_channel_done(struct pvr2_channel *);
|
void pvr2_channel_done(struct pvr2_channel *);
|
||||||
|
int pvr2_channel_limit_inputs(struct pvr2_channel *,unsigned int);
|
||||||
|
unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *);
|
||||||
int pvr2_channel_claim_stream(struct pvr2_channel *,
|
int pvr2_channel_claim_stream(struct pvr2_channel *,
|
||||||
struct pvr2_context_stream *);
|
struct pvr2_context_stream *);
|
||||||
struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
|
struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
|
||||||
|
@@ -244,13 +244,10 @@ static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
|||||||
|
|
||||||
static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
|
static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
|
||||||
{
|
{
|
||||||
/* TO DO: This function will call into the core and request for
|
struct pvr2_dvb_adapter *adap = fe->dvb->priv;
|
||||||
* input to be set to 'dtv' if (acquire) and if it isn't set already.
|
return pvr2_channel_limit_inputs(
|
||||||
*
|
&adap->channel,
|
||||||
* If (!acquire) then we should do nothing -- don't switch inputs
|
(acquire ? (1 << PVR2_CVAL_INPUT_DTV) : 0));
|
||||||
* again unless the analog side of the driver requests the bus.
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap)
|
static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap)
|
||||||
@@ -320,32 +317,26 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
|
|||||||
{
|
{
|
||||||
struct pvr2_hdw *hdw = adap->channel.hdw;
|
struct pvr2_hdw *hdw = adap->channel.hdw;
|
||||||
struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
|
struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
|
||||||
int ret;
|
int ret = 0;
|
||||||
|
|
||||||
if (dvb_props == NULL) {
|
if (dvb_props == NULL) {
|
||||||
err("fe_props not defined!");
|
err("fe_props not defined!");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: This code should be moved into the core,
|
ret = pvr2_channel_limit_inputs(
|
||||||
* and should only be called if we don't already have
|
&adap->channel,
|
||||||
* control of the bus.
|
(1 << PVR2_CVAL_INPUT_DTV));
|
||||||
*
|
if (ret) {
|
||||||
* We can't call "pvr2_dvb_bus_ctrl(adap->fe, 1)" from here,
|
err("failed to grab control of dtv input (code=%d)",
|
||||||
* because adap->fe isn't defined yet.
|
ret);
|
||||||
*/
|
|
||||||
ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_by_id(hdw,
|
|
||||||
PVR2_CID_INPUT),
|
|
||||||
PVR2_CVAL_INPUT_DTV);
|
|
||||||
if (ret != 0)
|
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
pvr2_hdw_commit_ctl(hdw);
|
|
||||||
|
|
||||||
|
|
||||||
if (dvb_props->frontend_attach == NULL) {
|
if (dvb_props->frontend_attach == NULL) {
|
||||||
err("frontend_attach not defined!");
|
err("frontend_attach not defined!");
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
|
if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
|
||||||
@@ -354,7 +345,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
|
|||||||
err("frontend registration failed!");
|
err("frontend registration failed!");
|
||||||
dvb_frontend_detach(adap->fe);
|
dvb_frontend_detach(adap->fe);
|
||||||
adap->fe = NULL;
|
adap->fe = NULL;
|
||||||
return -ENODEV;
|
ret = -ENODEV;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dvb_props->tuner_attach)
|
if (dvb_props->tuner_attach)
|
||||||
@@ -368,10 +360,13 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
err("no frontend was attached!");
|
err("no frontend was attached!");
|
||||||
return -ENODEV;
|
ret = -ENODEV;
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
done:
|
||||||
|
pvr2_channel_limit_inputs(&adap->channel, 0);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap)
|
static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap)
|
||||||
|
@@ -336,8 +336,10 @@ struct pvr2_hdw {
|
|||||||
int v4l_minor_number_vbi;
|
int v4l_minor_number_vbi;
|
||||||
int v4l_minor_number_radio;
|
int v4l_minor_number_radio;
|
||||||
|
|
||||||
/* Bit mask of PVR2_CVAL_INPUT choices which are valid */
|
/* Bit mask of PVR2_CVAL_INPUT choices which are valid for the hardware */
|
||||||
unsigned int input_avail_mask;
|
unsigned int input_avail_mask;
|
||||||
|
/* Bit mask of PVR2_CVAL_INPUT choices which are currenly allowed */
|
||||||
|
unsigned int input_allowed_mask;
|
||||||
|
|
||||||
/* Location of eeprom or a negative number if none */
|
/* Location of eeprom or a negative number if none */
|
||||||
int eeprom_addr;
|
int eeprom_addr;
|
||||||
|
@@ -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 void pvr2_hdw_state_sched(struct pvr2_hdw *);
|
||||||
static int pvr2_hdw_state_eval(struct pvr2_hdw *);
|
static int pvr2_hdw_state_eval(struct pvr2_hdw *);
|
||||||
static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
|
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)
|
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)
|
static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
|
||||||
{
|
{
|
||||||
struct pvr2_hdw *hdw = cptr->hdw;
|
return pvr2_hdw_set_input(cptr->hdw,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
|
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_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE;
|
||||||
if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
|
if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
|
||||||
hdw->input_avail_mask = m;
|
hdw->input_avail_mask = m;
|
||||||
|
hdw->input_allowed_mask = hdw->input_avail_mask;
|
||||||
|
|
||||||
/* If not a hybrid device, pathway_state never changes. So
|
/* If not a hybrid device, pathway_state never changes. So
|
||||||
initialize it here to what it should forever be. */
|
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)
|
static const char *pvr2_pathway_state_name(int id)
|
||||||
{
|
{
|
||||||
switch (id) {
|
switch (id) {
|
||||||
@@ -4016,6 +4018,28 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
|
|||||||
"state: %s",
|
"state: %s",
|
||||||
pvr2_get_state_name(hdw->master_state));
|
pvr2_get_state_name(hdw->master_state));
|
||||||
case 4: {
|
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;
|
struct pvr2_stream_stats stats;
|
||||||
if (!hdw->vid_stream) break;
|
if (!hdw->vid_stream) break;
|
||||||
pvr2_stream_get_stats(hdw->vid_stream,
|
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 */
|
/* Find I2C address of eeprom */
|
||||||
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
|
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
|
||||||
{
|
{
|
||||||
|
@@ -149,6 +149,19 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
|
|||||||
* will be according to PVR_CVAL_INPUT_xxxx definitions. */
|
* will be according to PVR_CVAL_INPUT_xxxx definitions. */
|
||||||
unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *);
|
unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *);
|
||||||
|
|
||||||
|
/* Return a bit mask of allowed input selections for this device. Mask bits
|
||||||
|
* will be according to PVR_CVAL_INPUT_xxxx definitions. */
|
||||||
|
unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *);
|
||||||
|
|
||||||
|
/* Change the set of allowed input selections for this device. Both
|
||||||
|
change_mask and change_valu are mask bits according to
|
||||||
|
PVR_CVAL_INPUT_xxxx definitions. The change_mask parameter indicate
|
||||||
|
which settings are being changed and the change_val parameter indicates
|
||||||
|
whether corresponding settings are being set or cleared. */
|
||||||
|
int pvr2_hdw_set_input_allowed(struct pvr2_hdw *,
|
||||||
|
unsigned int change_mask,
|
||||||
|
unsigned int change_val);
|
||||||
|
|
||||||
/* Return name for this driver instance */
|
/* Return name for this driver instance */
|
||||||
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
|
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
|
||||||
|
|
||||||
|
@@ -57,7 +57,6 @@ struct pvr2_v4l2_fh {
|
|||||||
struct pvr2_v4l2_fh *vprev;
|
struct pvr2_v4l2_fh *vprev;
|
||||||
wait_queue_head_t wait_data;
|
wait_queue_head_t wait_data;
|
||||||
int fw_mode_flag;
|
int fw_mode_flag;
|
||||||
int prev_input_val;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pvr2_v4l2 {
|
struct pvr2_v4l2 {
|
||||||
@@ -900,20 +899,6 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
|
|||||||
v4l2_prio_close(&vp->prio, &fhp->prio);
|
v4l2_prio_close(&vp->prio, &fhp->prio);
|
||||||
file->private_data = NULL;
|
file->private_data = NULL;
|
||||||
|
|
||||||
/* Restore the previous input selection, if it makes sense
|
|
||||||
to do so. */
|
|
||||||
if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
|
|
||||||
struct pvr2_ctrl *cp;
|
|
||||||
int pval;
|
|
||||||
cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
|
|
||||||
pvr2_ctrl_get_value(cp,&pval);
|
|
||||||
/* Only restore if we're still selecting the radio */
|
|
||||||
if (pval == PVR2_CVAL_INPUT_RADIO) {
|
|
||||||
pvr2_ctrl_set_value(cp,fhp->prev_input_val);
|
|
||||||
pvr2_hdw_commit_ctl(hdw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fhp->vnext) {
|
if (fhp->vnext) {
|
||||||
fhp->vnext->vprev = fhp->vprev;
|
fhp->vnext->vprev = fhp->vprev;
|
||||||
} else {
|
} else {
|
||||||
@@ -944,6 +929,8 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
|
|||||||
struct pvr2_v4l2_fh *fhp;
|
struct pvr2_v4l2_fh *fhp;
|
||||||
struct pvr2_v4l2 *vp;
|
struct pvr2_v4l2 *vp;
|
||||||
struct pvr2_hdw *hdw;
|
struct pvr2_hdw *hdw;
|
||||||
|
unsigned int input_mask = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
|
dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
|
||||||
|
|
||||||
@@ -969,6 +956,29 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
|
|||||||
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
|
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
|
||||||
pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
|
pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
|
||||||
|
|
||||||
|
if (dip->v4l_type == VFL_TYPE_RADIO) {
|
||||||
|
/* Opening device as a radio, legal input selection subset
|
||||||
|
is just the radio. */
|
||||||
|
input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
|
||||||
|
} else {
|
||||||
|
/* Opening the main V4L device, legal input selection
|
||||||
|
subset includes all analog inputs. */
|
||||||
|
input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
|
||||||
|
(1 << PVR2_CVAL_INPUT_TV) |
|
||||||
|
(1 << PVR2_CVAL_INPUT_COMPOSITE) |
|
||||||
|
(1 << PVR2_CVAL_INPUT_SVIDEO));
|
||||||
|
}
|
||||||
|
ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
|
||||||
|
if (ret) {
|
||||||
|
pvr2_channel_done(&fhp->channel);
|
||||||
|
pvr2_trace(PVR2_TRACE_STRUCT,
|
||||||
|
"Destroying pvr_v4l2_fh id=%p (input mask error)",
|
||||||
|
fhp);
|
||||||
|
|
||||||
|
kfree(fhp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
fhp->vnext = NULL;
|
fhp->vnext = NULL;
|
||||||
fhp->vprev = vp->vlast;
|
fhp->vprev = vp->vlast;
|
||||||
if (vp->vlast) {
|
if (vp->vlast) {
|
||||||
@@ -979,18 +989,6 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
|
|||||||
vp->vlast = fhp;
|
vp->vlast = fhp;
|
||||||
fhp->vhead = vp;
|
fhp->vhead = vp;
|
||||||
|
|
||||||
/* Opening the /dev/radioX device implies a mode switch.
|
|
||||||
So execute that here. Note that you can get the
|
|
||||||
IDENTICAL effect merely by opening the normal video
|
|
||||||
device and setting the input appropriately. */
|
|
||||||
if (dip->v4l_type == VFL_TYPE_RADIO) {
|
|
||||||
struct pvr2_ctrl *cp;
|
|
||||||
cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
|
|
||||||
pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
|
|
||||||
pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
|
|
||||||
pvr2_hdw_commit_ctl(hdw);
|
|
||||||
}
|
|
||||||
|
|
||||||
fhp->file = file;
|
fhp->file = file;
|
||||||
file->private_data = fhp;
|
file->private_data = fhp;
|
||||||
v4l2_prio_open(&vp->prio,&fhp->prio);
|
v4l2_prio_open(&vp->prio,&fhp->prio);
|
||||||
|
Reference in New Issue
Block a user