Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+31 −21
Original line number Diff line number Diff line
@@ -1341,10 +1341,15 @@ 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;

	if (p != NULL) {
		dst_set_freq(state, p->frequency);
		dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);

@@ -1364,7 +1369,12 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
			dst_set_modulation(state, p->u.qam.modulation);
		}
		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,
+177 −130
Original line number Diff line number Diff line
@@ -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;

	dprintk ("%s\n", __FUNCTION__);

	if (locked)
		      (*quality) = (*quality * 220 + 36*256) / 256;
		(fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
	else
		      (*quality) = (*quality * 220 + 0) / 256;
		(fepriv->quality) = (fepriv->quality * 220 + 0) / 256;

	    q2 = *quality - 128;
	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,87 +327,28 @@ static int dvb_frontend_autotune(struct dvb_frontend *fe, int check_wrapped)
	return 0;
}

static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
{
	struct dvb_frontend_private *fepriv = fe->frontend_priv;

	if (fepriv->exit)
		return 1;

	if (fepriv->dvbdev->writers == 1)
		if (time_after(jiffies, fepriv->release_jiffies +
					dvb_shutdown_timeout * HZ))
			return 1;

	return 0;
}

static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
{
	struct dvb_frontend_private *fepriv = fe->frontend_priv;

	if (fepriv->wakeup) {
		fepriv->wakeup = 0;
		return 1;
	}
	return dvb_frontend_is_exiting(fe);
}

static void dvb_frontend_wakeup(struct dvb_frontend *fe)
static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
{
	fe_status_t s;
	struct dvb_frontend_private *fepriv = fe->frontend_priv;

	fepriv->wakeup = 1;
	wake_up_interruptible(&fepriv->wait_queue);
	/* if we've got no parameters, just keep idling */
	if (fepriv->state & FESTATE_IDLE) {
		fepriv->delay = 3*HZ;
		fepriv->quality = 0;
		return;
	}

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

	dprintk("%s\n", __FUNCTION__);

	snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num);

	lock_kernel();
	daemonize(name);
	sigfillset(&current->blocked);
	unlock_kernel();

	fepriv->status = 0;
	dvb_frontend_init(fe);
	fepriv->wakeup = 0;

	while (1) {
		up(&fepriv->sem);	    /* is locked when we enter the thread... */

		timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
							   dvb_frontend_should_wakeup(fe),
							   delay);
		if (0 != dvb_frontend_is_exiting(fe)) {
			/* got signal or quitting */
			break;
	/* 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;
		}

		try_to_freeze();

		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;
		fepriv->delay = 3*HZ;
		fepriv->quality = 0;
		return;
	}

	/* get the frontend status */
@@ -415,9 +362,10 @@ static int dvb_frontend_thread(void *data)
			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);
		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 */
@@ -425,20 +373,20 @@ static int dvb_frontend_thread(void *data)
		    (fepriv->parameters.inversion == INVERSION_AUTO)) {
			fepriv->parameters.inversion = fepriv->inversion;
		}
			continue;
		return;
	}

	/* 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);
		dvb_frontend_swzigzag_update_delay(fepriv, 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 */
		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;
				check_wrapped = 0;
			fepriv->check_wrapped = 0;
		}
	}

@@ -446,16 +394,16 @@ static int dvb_frontend_thread(void *data)
	 * 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;
		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) {
			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
			continue;
		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
		return;
	}

	/* if we're in the RETUNE state, set everything up for a brand
@@ -466,22 +414,22 @@ static int dvb_frontend_thread(void *data)
		fepriv->auto_step = 0;
		fepriv->auto_sub_step = 0;
		fepriv->started_auto_step = 0;
			check_wrapped = 0;
		fepriv->check_wrapped = 0;
	}

	/* fast zigzag. */
	if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
			delay = fepriv->min_delay;
		fepriv->delay = fepriv->min_delay;

		/* peform a tune */
			if (dvb_frontend_autotune(fe, check_wrapped)) {
		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;
				continue;
			return;
		}
			check_wrapped = 1;
		fepriv->check_wrapped = 1;

		/* if we've just retuned, enter the ZIGZAG_FAST state.
		 * This ensures we cannot return from an
@@ -494,11 +442,105 @@ static int dvb_frontend_thread(void *data)

	/* slow zigzag */
	if (fepriv->state & FESTATE_SEARCHING_SLOW) {
			update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK);
		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_autotune(fe, 0);
		dvb_frontend_swzigzag_autotune(fe, 0);
	}
}

static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
{
	struct dvb_frontend_private *fepriv = fe->frontend_priv;

	if (fepriv->exit)
		return 1;

	if (fepriv->dvbdev->writers == 1)
		if (time_after(jiffies, fepriv->release_jiffies +
				  dvb_shutdown_timeout * HZ))
			return 1;

	return 0;
}

static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
{
	struct dvb_frontend_private *fepriv = fe->frontend_priv;

	if (fepriv->wakeup) {
		fepriv->wakeup = 0;
		return 1;
	}
	return dvb_frontend_is_exiting(fe);
}

static void dvb_frontend_wakeup(struct dvb_frontend *fe)
{
	struct dvb_frontend_private *fepriv = fe->frontend_priv;

	fepriv->wakeup = 1;
	wake_up_interruptible(&fepriv->wait_queue);
}

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];
	fe_status_t s;
	struct dvb_frontend_parameters *params;

	dprintk("%s\n", __FUNCTION__);

	snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num);

	lock_kernel();
	daemonize(name);
	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;

	while (1) {
		up(&fepriv->sem);	    /* is locked when we enter the thread... */

		timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
							   dvb_frontend_should_wakeup(fe),
							   fepriv->delay);
		if (0 != dvb_frontend_is_exiting(fe)) {
			/* got signal or quitting */
			break;
		}

		try_to_freeze();

		if (down_interruptible(&fepriv->sem))
			break;

		/* 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;
			}

			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;
			}
		} 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,
+10 −1
Original line number Diff line number Diff line
@@ -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);
+10 −0
Original line number Diff line number Diff line
@@ -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 */