V4L/DVB (5081): Pvrusb2: VIDIOC_G_TUNER cleanup
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>
This commit is contained in:
parent
af78a48b69
commit
18103c57b0
12 changed files with 144 additions and 165 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -44,12 +44,6 @@
|
|||
#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 *);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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: ***
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)/
|
||||
|
|
Loading…
Reference in a new issue