diff options
author | Andrew de Quincy <devnull@localhost> | 2004-02-25 15:46:25 +0000 |
---|---|---|
committer | Andrew de Quincy <devnull@localhost> | 2004-02-25 15:46:25 +0000 |
commit | a68f56427da49aa41827659280c8df810086bc0a (patch) | |
tree | 4139869cb08e1eea2a8192082a9f810476c816f5 /linux | |
parent | 11ce2f03c7eab083427dbf08a95789438504ae1f (diff) | |
download | mediapointer-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.c | 385 |
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)"); |