summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorAndrew de Quincy <devnull@localhost>2004-02-25 15:46:25 +0000
committerAndrew de Quincy <devnull@localhost>2004-02-25 15:46:25 +0000
commita68f56427da49aa41827659280c8df810086bc0a (patch)
tree4139869cb08e1eea2a8192082a9f810476c816f5 /linux
parent11ce2f03c7eab083427dbf08a95789438504ae1f (diff)
downloadmediapointer-dvb-s2-a68f56427da49aa41827659280c8df810086bc0a.tar.gz
mediapointer-dvb-s2-a68f56427da49aa41827659280c8df810086bc0a.tar.bz2
Rewritten core tuning loop. Name of a few flags still to be changed.
Diffstat (limited to 'linux')
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c385
1 files changed, 250 insertions, 135 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index 5d60c518f..73ba050ab 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -37,9 +37,37 @@
#include "dvbdev.h"
#include "dvb_functions.h"
+#define FESTATE_IDLE 1
+#define FESTATE_RETUNE 2
+#define FESTATE_TUNING_FAST 4
+#define FESTATE_TUNING_SLOW 8
+#define FESTATE_TUNED 16
+#define FESTATE_ZIGZAG_FAST 32
+#define FESTATE_ZIGZAG_SLOW 64
+#define FESTATE_CLEAN_SETUP 128
+#define FESTATE_SEARCHING (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
+#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
+#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+/*
+ * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
+ * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
+ * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.
+ * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.
+ * FESTATE_TUNED. The frontend has successfully locked on.
+ * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.
+ * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.
+ * FESTATE_CLEAN_SETUP. Used for certain dodgy tuners which need special massaging to lock.
+ * FESTATE_SEARCHING. When we're searching for a signal using a zigzag scan of any sort.
+ * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.
+ * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.
+ * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
+ */
+
static int dvb_frontend_debug = 0;
static int dvb_shutdown_timeout = 5;
+static int dvb_frequency_bending = 1;
#define dprintk if (dvb_frontend_debug) printk
@@ -66,12 +94,12 @@ struct dvb_frontend_data {
wait_queue_head_t wait_queue;
pid_t thread_pid;
unsigned long release_jiffies;
- unsigned long lost_sync_jiffies;
- int acquire_signal;
+ int state;
int bending;
int lnb_drift;
- int timeout_count;
- int lost_sync_count;
+ int inversion;
+ int auto_count;
+ int started_auto_count;
int exit;
fe_status_t status;
};
@@ -170,7 +198,7 @@ static void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive
frequency += this_fe->lnb_drift;
frequency += this_fe->bending;
- if (this_fe != fe && fe->lost_sync_count != -1 &&
+ if (this_fe != fe && (fe->state != FESTATE_IDLE) &&
frequency > f - stepsize && frequency < f + stepsize)
{
if (recursive % 2)
@@ -193,9 +221,6 @@ static void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe,
{
dprintk ("%s\n", __FUNCTION__);
- if ((fe->status & FE_HAS_LOCK) && !(s & FE_HAS_LOCK))
- fe->lost_sync_jiffies = jiffies;
-
if (((s ^ fe->status) & FE_HAS_LOCK) && (s & FE_HAS_LOCK))
dvb_delay (fe->info->notifier_delay);
@@ -293,40 +318,6 @@ static int dvb_frontend_get_event (struct dvb_frontend_data *fe,
return 0;
}
-
-static int dvb_frontend_set_parameters (struct dvb_frontend_data *fe,
- struct dvb_frontend_parameters *param,
- int first_trial)
-{
- struct dvb_frontend *frontend = &fe->frontend;
- int err;
-
- if (first_trial) {
- fe->timeout_count = 0;
- fe->lost_sync_count = 0;
- fe->lost_sync_jiffies = jiffies;
- fe->lnb_drift = 0;
- fe->acquire_signal = 1;
- if (fe->status & ~FE_TIMEDOUT)
- dvb_frontend_add_event (fe, 0);
- memcpy (&fe->parameters, param,
- sizeof (struct dvb_frontend_parameters));
- }
-
- dvb_bend_frequency (fe, 0);
-
- dprintk ("%s: f == %i, drift == %i\n",
- __FUNCTION__, (int) param->frequency, (int) fe->lnb_drift);
-
- param->frequency += fe->lnb_drift + fe->bending;
- err = dvb_frontend_internal_ioctl (frontend, FE_SET_FRONTEND, param);
- param->frequency -= fe->lnb_drift + fe->bending;
-
- wake_up_interruptible (&fe->wait_queue);
-
- return err;
-}
-
static void dvb_frontend_init (struct dvb_frontend_data *fe)
{
struct dvb_frontend *frontend = &fe->frontend;
@@ -338,74 +329,129 @@ static void dvb_frontend_init (struct dvb_frontend_data *fe)
dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL);
}
-
static void update_delay (int *quality, int *delay, int locked)
{
- int q2;
-
- dprintk ("%s\n", __FUNCTION__);
-
- if (locked)
- (*quality) = (*quality * 220 + 36*256) / 256;
- else
- (*quality) = (*quality * 220 + 0) / 256;
-
- q2 = *quality - 128;
- q2 *= q2;
-
- *delay = HZ/20 + q2 * HZ / (128*128);
+ int q2;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (locked)
+ (*quality) = (*quality * 220 + 36*256) / 256;
+ else
+ (*quality) = (*quality * 220 + 0) / 256;
+
+ q2 = *quality - 128;
+ q2 *= q2;
+
+ *delay = HZ/20 + q2 * HZ / (128*128);
}
-
-#define LNB_DRIFT 1024 /* max. tolerated LNB drift, XXX FIXME: adjust! */
-#define TIMEOUT 2*HZ
-
/**
- * here we only come when we have lost the lock bit,
- * let's try to do something useful...
+ * Performs automatic twiddling of frontend parameters.
+ *
+ * @param fe The frontend concerned.
+ * @returns Number of complete iterations that have been performed.
*/
-static void dvb_frontend_recover (struct dvb_frontend_data *fe)
+static int dvb_frontend_autotune(struct dvb_frontend_data *fe)
{
- int j = fe->lost_sync_count;
- int stepsize;
+ int stepsize;
+ int maxdrift;
+ int autoinversion;
+ int ready = 0;
+ int wrapped = 0;
+ int original_inversion = fe->parameters.inversion;
+ u32 original_frequency = fe->parameters.frequency;
dprintk ("%s\n", __FUNCTION__);
-#if 0
- if (fe->timeout_count > 3) {
- printk ("%s: frontend seems dead, reinitializing...\n",
- __FUNCTION__);
- dvb_call_frontend_notifiers (fe, 0);
- dvb_frontend_internal_ioctl (&fe->frontend, FE_INIT, NULL);
- dvb_frontend_set_parameters (fe, &fe->parameters, 1);
- dvb_frontend_add_event (fe, FE_REINIT);
- fe->lost_sync_jiffies = jiffies;
- fe->timeout_count = 0;
- return;
+ // choose step size for zigzag scan
+ switch(fe->info->type) {
+ case FE_QPSK:
+ stepsize = fe->parameters.u.qpsk.symbol_rate / 64000;
+ maxdrift = fe->parameters.u.qpsk.symbol_rate / 1000;
+ break;
+
+ case FE_QAM:
+ stepsize = 1;
+ maxdrift = 0; // don't want any zigzagging under DVB-C frontends
+ break;
+
+ case FE_OFDM:
+ stepsize = fe->info->frequency_stepsize * 2;
+ maxdrift = (fe->info->frequency_stepsize * 2) + 1;
+ break;
+
+ default:
+ printk("Unknown frontend type %i\n", fe->info->type);
+ return 0;
}
-#endif
- /**
- * let's start a zigzag scan to compensate LNB drift...
- */
- if (fe->info->type == FE_QPSK)
- stepsize = fe->parameters.u.qpsk.symbol_rate / 16000;
- else if (fe->info->type == FE_QAM)
- stepsize = 0;
- else
- stepsize = fe->info->frequency_stepsize * 2;
-
- if (j % 32 == 0) {
- fe->lnb_drift = 0;
- } else {
- fe->lnb_drift = -fe->lnb_drift;
- if (j % 2)
- fe->lnb_drift += stepsize;
+ // are we using autoinversion?
+ autoinversion = ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO));
+
+ // setup parameters correctly
+ while(!ready) {
+ // wrap the count if we've reached the maximum drift
+ fe->lnb_drift = (fe->auto_count / 4) * stepsize;
+ if (fe->lnb_drift >= maxdrift) {
+ fe->auto_count = 0;
+ fe->lnb_drift = 0;
+ wrapped = 1;
+ }
+
+ // perform inversion and +/- zigzag
+ switch(fe->auto_count % 4) {
+ case 0:
+ fe->inversion = INVERSION_OFF;
+ ready = 1;
+ break;
+
+ case 1:
+ if (!autoinversion) break;
+
+ fe->inversion = INVERSION_ON;
+ ready = 1;
+ break;
+
+ case 2:
+ if (fe->lnb_drift == 0) break;
+
+ fe->inversion = INVERSION_OFF;
+ fe->lnb_drift = -fe->lnb_drift;
+ ready = 1;
+ break;
+
+ case 3:
+ if (fe->lnb_drift == 0) break;
+ if (!autoinversion) break;
+
+ fe->inversion = INVERSION_ON;
+ fe->lnb_drift = -fe->lnb_drift;
+ ready = 1;
+ break;
+ }
+
+ if (!ready) fe->auto_count++;
}
-
- dvb_frontend_set_parameters (fe, &fe->parameters, 0);
-
- dvb_frontend_internal_ioctl (&fe->frontend, FE_RESET, NULL);
+
+ // perform frequency bending if enabled
+ if (dvb_frequency_bending)
+ dvb_bend_frequency(fe, 0);
+
+ // set the frontend itself
+ fe->parameters.frequency += fe->lnb_drift + fe->bending;
+ if (autoinversion) fe->parameters.inversion = fe->inversion;
+ dvb_frontend_internal_ioctl (&fe->frontend, FE_SET_FRONTEND, &fe->parameters);
+ fe->parameters.frequency = original_frequency;
+ fe->parameters.inversion = original_inversion;
+
+ // reset frontend IRQ bits to clean error stats
+ dvb_frontend_internal_ioctl (&fe->frontend, FE_RESET, NULL);
+
+ // if we've hit where we started from, indicate a complete iteration has occurred
+ fe->auto_count++;
+ if ((fe->auto_count == fe->started_auto_count) || (fe->started_auto_count==0 && wrapped)) return 1;
+ return 0;
}
@@ -429,6 +475,7 @@ static int dvb_frontend_thread (void *data)
unsigned long timeout;
char name [15];
int quality = 0, delay = 3*HZ;
+ int clean_setup_count = 0;
fe_status_t s;
dprintk ("%s\n", __FUNCTION__);
@@ -438,8 +485,6 @@ static int dvb_frontend_thread (void *data)
dvb_kernel_thread_setup (name);
- fe->lost_sync_count = -1;
-
dvb_call_frontend_notifiers (fe, 0);
dvb_frontend_init (fe);
@@ -455,43 +500,97 @@ static int dvb_frontend_thread (void *data)
if (down_interruptible (&fe->sem))
break;
- if (fe->lost_sync_count == -1)
- continue;
-
+ // if we've got no parameters, just keep idling
+ if (fe->state & FESTATE_IDLE) {
+ delay = 3*HZ;
+ quality = 0;
+ continue;
+ }
+
+ // get the frontend status
dvb_frontend_internal_ioctl (&fe->frontend, FE_READ_STATUS, &s);
+ if (s != fe->status)
+ dvb_frontend_add_event (fe, s);
- update_delay (&quality, &delay, s & FE_HAS_LOCK);
-
- s &= ~FE_TIMEDOUT;
-
- if (s & FE_HAS_LOCK) {
- fe->timeout_count = 0;
- fe->lost_sync_count = 0;
- fe->acquire_signal = 0;
- } else {
- fe->lost_sync_count++;
- if (!(fe->info->caps & FE_CAN_RECOVER)) {
- if (!(fe->info->caps & FE_CAN_CLEAN_SETUP)) {
- if (fe->lost_sync_count < 10) {
- if (fe->acquire_signal)
- dvb_frontend_internal_ioctl(
- &fe->frontend,
- FE_RESET, NULL);
- continue;
- }
- }
- dvb_frontend_recover (fe);
- delay = HZ/5;
+ // if we're not tuned, and we have a lock, move to the TUNED state
+ if ((fe->state & FESTATE_SEARCHING) && (s & FE_HAS_LOCK)) {
+ update_delay(&quality, &delay, s & FE_HAS_LOCK);
+ fe->state = FESTATE_TUNED;
+
+ // if we're tuned, then we have determined the correct inversion
+ if ((!(fe->info->caps & FE_CAN_INVERSION_AUTO)) && (fe->parameters.inversion == INVERSION_AUTO)) {
+ fe->parameters.inversion = fe->inversion;
}
- if (jiffies - fe->lost_sync_jiffies > TIMEOUT) {
- s |= FE_TIMEDOUT;
- if ((fe->status & FE_TIMEDOUT) == 0)
- fe->timeout_count++;
+ continue;
+ }
+
+ // if we are tuned already, check we're still locked
+ if (fe->state & FESTATE_TUNED) {
+ update_delay(&quality, &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, need to zigzag
+ fe->state = FESTATE_ZIGZAG_FAST;
+ fe->started_auto_count = fe->auto_count;
+ // fallthrough
}
}
- if (s != fe->status)
- dvb_frontend_add_event (fe, s);
+ // don't actually do anything if we're in the LOSTLOCK state
+ // and the frontend can recover automatically
+ if ((fe->state & FESTATE_LOSTLOCK) && (fe->info->caps & FE_CAN_RECOVER)) {
+ update_delay(&quality, &delay, s & FE_HAS_LOCK);
+ continue;
+ }
+
+ // if we're in the RETUNE state, move immediately to the ZIGZAG_FAST state
+ // and, if we're sitting comfortably, begin
+ if (fe->state & FESTATE_RETUNE) {
+ fe->lnb_drift = 0;
+ fe->inversion = INVERSION_OFF;
+ fe->auto_count = 0;
+ fe->started_auto_count = 0;
+ fe->state = FESTATE_TUNING_FAST;
+ clean_setup_count = 0;
+ }
+
+ // fast zigzag
+ if (fe->state & FESTATE_SEARCHING_FAST) {
+ delay = (HZ * 30) / 1000; // hardcoded fast zigzag scan delay of 30ms
+
+ // OK, if we've run out of trials at the fast speed. Drop back to
+ // slow for the _next_ attempt
+ if (dvb_frontend_autotune(fe)) {
+ fe->state = FESTATE_SEARCHING_SLOW;
+ fe->started_auto_count = fe->auto_count;
+ continue;
+ }
+
+ // enter clean setup state after the first tune if necessary. yeuch
+ if ((!(fe->info->caps & FE_CAN_CLEAN_SETUP)) && (clean_setup_count == 0)) {
+ fe->state = FESTATE_CLEAN_SETUP;
+ }
+ }
+
+ // slow zigzag
+ if (fe->state & FESTATE_SEARCHING_SLOW) {
+ update_delay(&quality, &delay, s & FE_HAS_LOCK);
+ dvb_frontend_autotune(fe);
+ }
+
+ // clean setup
+ if (fe->state & FESTATE_CLEAN_SETUP) {
+ if ((clean_setup_count < 10) && (!(s & FE_LOCK))) {
+ dvb_internal_ioctl(&fe->frontend, FE_RESET, NULL);
+ } else {
+ // return to tuning state
+ fe->state = FESTATE_TUNING_FAST;
+ }
+ clean_setup_count++;
+ }
};
if (dvb_shutdown_timeout)
@@ -509,7 +608,7 @@ static int dvb_frontend_thread (void *data)
static void dvb_frontend_stop (struct dvb_frontend_data *fe)
{
- unsigned long ret;
+ unsigned long ret;
dprintk ("%s\n", __FUNCTION__);
@@ -562,6 +661,7 @@ static int dvb_frontend_start (struct dvb_frontend_data *fe)
if (down_interruptible (&fe->sem))
return -EINTR;
+ fe->state = FESTATE_IDLE;
fe->exit = 0;
fe->thread_pid = 0;
mb();
@@ -616,16 +716,23 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
if (fe->status)
dvb_call_frontend_notifiers (fe, 0);
dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);
+ fe->state = FESTATE_IDLE;
break;
+
case FE_SET_FRONTEND:
- err = dvb_frontend_set_parameters (fe, parg, 1);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ fe->state = FESTATE_RETUNE;
+
+ memcpy (&fe->parameters, parg,
+ sizeof (struct dvb_frontend_parameters));
+
+ dvb_frontend_add_event (fe, 0);
wake_up_interruptible(&fe->wait_queue);
break;
+
case FE_GET_EVENT:
err = dvb_frontend_get_event (fe, parg, file->f_flags);
break;
+
case FE_GET_FRONTEND:
memcpy (parg, &fe->parameters,
sizeof (struct dvb_frontend_parameters));
@@ -633,7 +740,13 @@ static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
default:
dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);
};
-
+
+ // Force the CAN_INVERSION_AUTO bit on
+ if (cmd == FE_GET_INFO) {
+ struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) parg;
+ tmp->caps |= FE_CAN_INVERSION_AUTO;
+ }
+
up (&fe->sem);
return err;
@@ -1007,5 +1120,7 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
MODULE_PARM(dvb_frontend_debug,"i");
MODULE_PARM(dvb_shutdown_timeout,"i");
+MODULE_PARM(dvb_frequency_bending,"i");
MODULE_PARM_DESC(dvb_frontend_debug, "enable verbose debug messages");
MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
+MODULE_PARM_DESC(dvb_frequency_bending, "0: disable frequency bending, 1: enable (default)");