Commit 36cb557a authored by Andrew de Quincey's avatar Andrew de Quincey Committed by Mauro Carvalho Chehab

DVB (2444): Implement frontend-specific tuning and the ability to disable zigzag

- Implement frontend-specific tuning and the ability to disable zigzag
Signed-off-by: default avatarAndrew de Quincey <adq_dvb@lidskialf.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
parent 47f36920
......@@ -1341,30 +1341,40 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
return 0;
}
static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
static int dst_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters* p,
unsigned int mode_flags,
int *delay,
fe_status_t *status)
{
struct dst_state *state = fe->demodulator_priv;
dst_set_freq(state, p->frequency);
dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
if (p != NULL) {
dst_set_freq(state, p->frequency);
dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
if (state->dst_type == DST_TYPE_IS_SAT) {
if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
dst_set_inversion(state, p->inversion);
dst_set_fec(state, p->u.qpsk.fec_inner);
dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
dst_set_polarization(state);
dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
} else if (state->dst_type == DST_TYPE_IS_TERR)
dst_set_bandwidth(state, p->u.ofdm.bandwidth);
else if (state->dst_type == DST_TYPE_IS_CABLE) {
dst_set_fec(state, p->u.qam.fec_inner);
dst_set_symbolrate(state, p->u.qam.symbol_rate);
dst_set_modulation(state, p->u.qam.modulation);
if (state->dst_type == DST_TYPE_IS_SAT) {
if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
dst_set_inversion(state, p->inversion);
dst_set_fec(state, p->u.qpsk.fec_inner);
dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
dst_set_polarization(state);
dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
} else if (state->dst_type == DST_TYPE_IS_TERR)
dst_set_bandwidth(state, p->u.ofdm.bandwidth);
else if (state->dst_type == DST_TYPE_IS_CABLE) {
dst_set_fec(state, p->u.qam.fec_inner);
dst_set_symbolrate(state, p->u.qam.symbol_rate);
dst_set_modulation(state, p->u.qam.modulation);
}
dst_write_tuna(fe);
}
dst_write_tuna(fe);
if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
dst_read_status(fe, status);
*delay = HZ/10;
return 0;
}
......@@ -1445,7 +1455,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
.release = dst_release,
.init = dst_init,
.set_frontend = dst_set_frontend,
.tune = dst_set_frontend,
.get_frontend = dst_get_frontend,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
......@@ -1469,7 +1479,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
.release = dst_release,
.init = dst_init,
.set_frontend = dst_set_frontend,
.tune = dst_set_frontend,
.get_frontend = dst_get_frontend,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
......@@ -1496,7 +1506,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
.release = dst_release,
.init = dst_init,
.set_frontend = dst_set_frontend,
.tune = dst_set_frontend,
.get_frontend = dst_get_frontend,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
......
......@@ -92,6 +92,7 @@ static DECLARE_MUTEX(frontend_mutex);
struct dvb_frontend_private {
/* thread/frontend values */
struct dvb_device *dvbdev;
struct dvb_frontend_parameters parameters;
struct dvb_fe_events events;
......@@ -100,20 +101,25 @@ struct dvb_frontend_private {
wait_queue_head_t wait_queue;
pid_t thread_pid;
unsigned long release_jiffies;
int state;
int bending;
int lnb_drift;
int inversion;
int auto_step;
int auto_sub_step;
int started_auto_step;
int min_delay;
int max_drift;
int step_size;
int exit;
int wakeup;
unsigned int exit;
unsigned int wakeup;
fe_status_t status;
fe_sec_tone_mode_t tone;
unsigned int tune_mode_flags;
unsigned int delay;
/* swzigzag values */
unsigned int state;
unsigned int bending;
int lnb_drift;
unsigned int inversion;
unsigned int auto_step;
unsigned int auto_sub_step;
unsigned int started_auto_step;
unsigned int min_delay;
unsigned int max_drift;
unsigned int step_size;
int quality;
unsigned int check_wrapped;
};
......@@ -208,21 +214,21 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
fe->ops->init(fe);
}
static void update_delay(int *quality, int *delay, int min_delay, int locked)
static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
{
int q2;
int q2;
dprintk ("%s\n", __FUNCTION__);
dprintk ("%s\n", __FUNCTION__);
if (locked)
(*quality) = (*quality * 220 + 36*256) / 256;
else
(*quality) = (*quality * 220 + 0) / 256;
if (locked)
(fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
else
(fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
q2 = *quality - 128;
q2 *= q2;
q2 = fepriv->quality - 128;
q2 *= q2;
*delay = min_delay + q2 * HZ / (128*128);
fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
}
/**
......@@ -232,7 +238,7 @@ static void update_delay(int *quality, int *delay, int min_delay, int locked)
* @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
* @returns Number of complete iterations that have been performed.
*/
static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
{
int autoinversion;
int ready = 0;
......@@ -321,6 +327,129 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
return 0;
}
static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
{
fe_status_t s;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
/* if we've got no parameters, just keep idling */
if (fepriv->state & FESTATE_IDLE) {
fepriv->delay = 3*HZ;
fepriv->quality = 0;
return;
}
/* in SCAN mode, we just set the frontend when asked and leave it alone */
if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
if (fepriv->state & FESTATE_RETUNE) {
if (fe->ops->set_frontend)
fe->ops->set_frontend(fe, &fepriv->parameters);
fepriv->state = FESTATE_TUNED;
}
fepriv->delay = 3*HZ;
fepriv->quality = 0;
return;
}
/* get the frontend status */
if (fepriv->state & FESTATE_RETUNE) {
s = 0;
} else {
if (fe->ops->read_status)
fe->ops->read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
}
}
/* if we're not tuned, and we have a lock, move to the TUNED state */
if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
fepriv->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */
if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO)) {
fepriv->parameters.inversion = fepriv->inversion;
}
return;
}
/* if we are tuned already, check we're still locked */
if (fepriv->state & FESTATE_TUNED) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
/* we're tuned, and the lock is still good... */
if (s & FE_HAS_LOCK) {
return;
} else { /* if we _WERE_ tuned, but now don't have a lock */
fepriv->state = FESTATE_ZIGZAG_FAST;
fepriv->started_auto_step = fepriv->auto_step;
fepriv->check_wrapped = 0;
}
}
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fepriv->state & FESTATE_LOSTLOCK) &&
(fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
return;
}
/* don't do anything if we're in the DISEQC state, since this
* might be someone with a motorized dish controlled by DISEQC.
* If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
if (fepriv->state & FESTATE_DISEQC) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
return;
}
/* if we're in the RETUNE state, set everything up for a brand
* new scan, keeping the current inversion setting, as the next
* tune is _very_ likely to require the same */
if (fepriv->state & FESTATE_RETUNE) {
fepriv->lnb_drift = 0;
fepriv->auto_step = 0;
fepriv->auto_sub_step = 0;
fepriv->started_auto_step = 0;
fepriv->check_wrapped = 0;
}
/* fast zigzag. */
if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
fepriv->delay = fepriv->min_delay;
/* peform a tune */
if (dvb_frontend_swzigzag_autotune(fe, fepriv->check_wrapped)) {
/* OK, if we've run out of trials at the fast speed.
* Drop back to slow for the _next_ attempt */
fepriv->state = FESTATE_SEARCHING_SLOW;
fepriv->started_auto_step = fepriv->auto_step;
return;
}
fepriv->check_wrapped = 1;
/* if we've just retuned, enter the ZIGZAG_FAST state.
* This ensures we cannot return from an
* FE_SET_FRONTEND ioctl before the first frontend tune
* occurs */
if (fepriv->state & FESTATE_RETUNE) {
fepriv->state = FESTATE_TUNING_FAST;
}
}
/* slow zigzag */
if (fepriv->state & FESTATE_SEARCHING_SLOW) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
/* Note: don't bother checking for wrapping; we stay in this
* state until we get a lock */
dvb_frontend_swzigzag_autotune(fe, 0);
}
}
static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
......@@ -330,7 +459,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
if (fepriv->dvbdev->writers == 1)
if (time_after(jiffies, fepriv->release_jiffies +
dvb_shutdown_timeout * HZ))
dvb_shutdown_timeout * HZ))
return 1;
return 0;
......@@ -355,18 +484,14 @@ static void dvb_frontend_wakeup(struct dvb_frontend *fe)
wake_up_interruptible(&fepriv->wait_queue);
}
/*
* FIXME: use linux/kthread.h
*/
static int dvb_frontend_thread(void *data)
{
struct dvb_frontend *fe = data;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
unsigned long timeout;
char name [15];
int quality = 0, delay = 3*HZ;
fe_status_t s;
int check_wrapped = 0;
struct dvb_frontend_parameters *params;
dprintk("%s\n", __FUNCTION__);
......@@ -377,6 +502,9 @@ static int dvb_frontend_thread(void *data)
sigfillset(&current->blocked);
unlock_kernel();
fepriv->check_wrapped = 0;
fepriv->quality = 0;
fepriv->delay = 3*HZ;
fepriv->status = 0;
dvb_frontend_init(fe);
fepriv->wakeup = 0;
......@@ -386,7 +514,7 @@ static int dvb_frontend_thread(void *data)
timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
dvb_frontend_should_wakeup(fe),
delay);
fepriv->delay);
if (0 != dvb_frontend_is_exiting(fe)) {
/* got signal or quitting */
break;
......@@ -397,108 +525,22 @@ static int dvb_frontend_thread(void *data)
if (down_interruptible(&fepriv->sem))
break;
/* if we've got no parameters, just keep idling */
if (fepriv->state & FESTATE_IDLE) {
delay = 3*HZ;
quality = 0;
continue;
}
/* do an iteration of the tuning loop */
if (fe->ops->tune) {
/* have we been asked to retune? */
params = NULL;
if (fepriv->state & FESTATE_RETUNE) {
params = &fepriv->parameters;
fepriv->state = FESTATE_TUNED;
}
/* get the frontend status */
if (fepriv->state & FESTATE_RETUNE) {
s = 0;
} else {
if (fe->ops->read_status)
fe->ops->read_status(fe, &s);
fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
}
}
/* if we're not tuned, and we have a lock, move to the TUNED state */
if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
fepriv->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */
if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO)) {
fepriv->parameters.inversion = fepriv->inversion;
}
continue;
}
/* if we are tuned already, check we're still locked */
if (fepriv->state & FESTATE_TUNED) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
/* we're tuned, and the lock is still good... */
if (s & FE_HAS_LOCK)
continue;
else { /* if we _WERE_ tuned, but now don't have a lock */
fepriv->state = FESTATE_ZIGZAG_FAST;
fepriv->started_auto_step = fepriv->auto_step;
check_wrapped = 0;
}
}
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fepriv->state & FESTATE_LOSTLOCK) &&
(fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
continue;
}
/* don't do anything if we're in the DISEQC state, since this
* might be someone with a motorized dish controlled by DISEQC.
* If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
if (fepriv->state & FESTATE_DISEQC) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
continue;
}
/* if we're in the RETUNE state, set everything up for a brand
* new scan, keeping the current inversion setting, as the next
* tune is _very_ likely to require the same */
if (fepriv->state & FESTATE_RETUNE) {
fepriv->lnb_drift = 0;
fepriv->auto_step = 0;
fepriv->auto_sub_step = 0;
fepriv->started_auto_step = 0;
check_wrapped = 0;
}
/* fast zigzag. */
if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
delay = fepriv->min_delay;
/* peform a tune */
if (dvb_frontend_autotune(fe, check_wrapped)) {
/* OK, if we've run out of trials at the fast speed.
* Drop back to slow for the _next_ attempt */
fepriv->state = FESTATE_SEARCHING_SLOW;
fepriv->started_auto_step = fepriv->auto_step;
continue;
}
check_wrapped = 1;
/* if we've just retuned, enter the ZIGZAG_FAST state.
* This ensures we cannot return from an
* FE_SET_FRONTEND ioctl before the first frontend tune
* occurs */
if (fepriv->state & FESTATE_RETUNE) {
fepriv->state = FESTATE_TUNING_FAST;
}
}
/* slow zigzag */
if (fepriv->state & FESTATE_SEARCHING_SLOW) {
update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
/* Note: don't bother checking for wrapping; we stay in this
* state until we get a lock */
dvb_frontend_autotune(fe, 0);
} else {
dvb_frontend_swzigzag(fe);
}
}
......@@ -733,7 +775,6 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
fepriv->tone = (fe_sec_tone_mode_t) parg;
}
break;
......@@ -891,6 +932,10 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
}
break;
case FE_SET_FRONTEND_TUNE_MODE:
fepriv->tune_mode_flags = (unsigned int) parg;
break;
};
up (&fepriv->sem);
......@@ -932,6 +977,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
/* normal tune mode when opened R/W */
fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
}
return ret;
......@@ -990,7 +1038,6 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
init_MUTEX (&fepriv->events.sem);
fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF;
fepriv->tone = SEC_TONE_OFF;
printk ("DVB: registering frontend %i (%s)...\n",
fe->dvb->num,
......
......@@ -58,10 +58,19 @@ struct dvb_frontend_ops {
int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe);
/* if this is set, it overrides the default swzigzag */
int (*tune)(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
int *delay,
fe_status_t *status);
/* these two are only used for the swzigzag code */
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
int (*read_ber)(struct dvb_frontend* fe, u32* ber);
int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
......
......@@ -240,6 +240,15 @@ struct dvb_frontend_event {
};
/**
* When set, this flag will disable any zigzagging or other "normal" tuning
* behaviour. Additionally, there will be no automatic monitoring of the lock
* status, and hence no frontend events will be generated. If a frontend device
* is closed, this flag will be automatically turned off when the device is
* reopened read-write.
*/
#define FE_TUNE_MODE_ONESHOT 0x01
#define FE_GET_INFO _IOR('o', 61, struct dvb_frontend_info)
......@@ -260,6 +269,7 @@ struct dvb_frontend_event {
#define FE_SET_FRONTEND _IOW('o', 76, struct dvb_frontend_parameters)
#define FE_GET_FRONTEND _IOR('o', 77, struct dvb_frontend_parameters)
#define FE_SET_FRONTEND_TUNE_MODE _IO('o', 81) /* unsigned int */
#define FE_GET_EVENT _IOR('o', 78, struct dvb_frontend_event)
#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment