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:
Mike Isely 2007-01-20 00:09:47 -03:00 committed by Mauro Carvalho Chehab
parent af78a48b69
commit 18103c57b0
12 changed files with 144 additions and 165 deletions

View 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;

View 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;

View 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;

View 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;
}

View file

@ -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 *);

View 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)) {

View 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: ***

View 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 */

View 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 {

View 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

View 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;
}

View 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)/