Пример #1
0
void dvb_frontend_reinitialise(struct dvb_frontend *fe)
{
	struct dvb_frontend_private *fepriv = fe->frontend_priv;

	fepriv->reinitialise = 1;
	dvb_frontend_wakeup(fe);
}
Пример #2
0
static void dvb_frontend_stop(struct dvb_frontend *fe)
{
	unsigned long ret;
	struct dvb_frontend_private *fepriv = fe->frontend_priv;

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

	fepriv->exit = 1;
	mb();

	if (!fepriv->thread_pid)
		return;

	/* check if the thread is really alive */
	if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) {
		printk("dvb_frontend_stop: thread PID %d already died\n",
				fepriv->thread_pid);
		/* make sure the mutex was not held by the thread */
		init_MUTEX (&fepriv->sem);
		return;
	}

	/* wake up the frontend thread, so it notices that fe->exit == 1 */
	dvb_frontend_wakeup(fe);

	/* wait until the frontend thread has exited */
	ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid);
	if (-ERESTARTSYS != ret) {
		fepriv->state = FESTATE_IDLE;
		return;
	}
	fepriv->state = FESTATE_IDLE;

	/* paranoia check in case a signal arrived */
	if (fepriv->thread_pid)
		printk("dvb_frontend_stop: warning: thread PID %d won't exit\n",
				fepriv->thread_pid);
}
Пример #3
0
static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
			unsigned int cmd, void *parg)
{
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_frontend *fe = dvbdev->priv;
	struct dvb_frontend_private *fepriv = fe->frontend_priv;
	int err = -EOPNOTSUPP;

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

	if (!fe || fepriv->exit)
		return -ENODEV;

	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
	    (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
	     cmd == FE_DISEQC_RECV_SLAVE_REPLY))
		return -EPERM;

	if (down_interruptible (&fepriv->sem))
		return -ERESTARTSYS;

	switch (cmd) {
	case FE_GET_INFO: {
		struct dvb_frontend_info* info = parg;
		memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));

		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
		 * do it, it is done for it. */
		info->caps |= FE_CAN_INVERSION_AUTO;
		err = 0;
		break;
	}

	case FE_READ_STATUS: {
		fe_status_t* status = parg;

		/* if retune was requested but hasn't occured yet, prevent
		 * that user get signal state from previous tuning */
		if(fepriv->state == FESTATE_RETUNE) {
			err=0;
			*status = 0;
			break;
		}

		if (fe->ops.read_status)
			err = fe->ops.read_status(fe, status);
		break;
	}
	case FE_READ_BER:
		if (fe->ops.read_ber)
			err = fe->ops.read_ber(fe, (__u32*) parg);
		break;

	case FE_READ_SIGNAL_STRENGTH:
		if (fe->ops.read_signal_strength)
			err = fe->ops.read_signal_strength(fe, (__u16*) parg);
		break;

	case FE_READ_SNR:
		if (fe->ops.read_snr)
			err = fe->ops.read_snr(fe, (__u16*) parg);
		break;

	case FE_READ_UNCORRECTED_BLOCKS:
		if (fe->ops.read_ucblocks)
			err = fe->ops.read_ucblocks(fe, (__u32*) parg);
		break;


	case FE_DISEQC_RESET_OVERLOAD:
		if (fe->ops.diseqc_reset_overload) {
			err = fe->ops.diseqc_reset_overload(fe);
			fepriv->state = FESTATE_DISEQC;
			fepriv->status = 0;
		}
		break;

	case FE_DISEQC_SEND_MASTER_CMD:
		if (fe->ops.diseqc_send_master_cmd) {
			err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
			fepriv->state = FESTATE_DISEQC;
			fepriv->status = 0;
		}
		break;

	case FE_DISEQC_SEND_BURST:
		if (fe->ops.diseqc_send_burst) {
			err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
			fepriv->state = FESTATE_DISEQC;
			fepriv->status = 0;
		}
		break;

	case FE_SET_TONE:
		if (fe->ops.set_tone) {
			err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
			fepriv->tone = (fe_sec_tone_mode_t) parg;
			fepriv->state = FESTATE_DISEQC;
			fepriv->status = 0;
		}
		break;

	case FE_SET_VOLTAGE:
		if (fe->ops.set_voltage) {
			err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
			fepriv->voltage = (fe_sec_voltage_t) parg;
			fepriv->state = FESTATE_DISEQC;
			fepriv->status = 0;
		}
		break;

	case FE_DISHNETWORK_SEND_LEGACY_CMD:
		if (fe->ops.dishnetwork_send_legacy_command) {
			err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
			fepriv->state = FESTATE_DISEQC;
			fepriv->status = 0;
		} else if (fe->ops.set_voltage) {
			/*
			 * NOTE: This is a fallback condition.  Some frontends
			 * (stv0299 for instance) take longer than 8msec to
			 * respond to a set_voltage command.  Those switches
			 * need custom routines to switch properly.  For all
			 * other frontends, the following shoule work ok.
			 * Dish network legacy switches (as used by Dish500)
			 * are controlled by sending 9-bit command words
			 * spaced 8msec apart.
			 * the actual command word is switch/port dependant
			 * so it is up to the userspace application to send
			 * the right command.
			 * The command must always start with a '0' after
			 * initialization, so parg is 8 bits and does not
			 * include the initialization or start bit
			 */
			unsigned long cmd = ((unsigned long) parg) << 1;
			struct timeval nexttime;
			struct timeval tv[10];
			int i;
			u8 last = 1;
			if (dvb_frontend_debug)
				printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd);
			do_gettimeofday(&nexttime);
			if (dvb_frontend_debug)
				memcpy(&tv[0], &nexttime, sizeof(struct timeval));
			/* before sending a command, initialize by sending
			 * a 32ms 18V to the switch
			 */
			fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
			dvb_frontend_sleep_until(&nexttime, 32000);

			for (i = 0; i < 9; i++) {
				if (dvb_frontend_debug)
					do_gettimeofday(&tv[i + 1]);
				if ((cmd & 0x01) != last) {
					/* set voltage to (last ? 13V : 18V) */
					fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
					last = (last) ? 0 : 1;
				}
				cmd = cmd >> 1;
				if (i != 8)
					dvb_frontend_sleep_until(&nexttime, 8000);
			}
			if (dvb_frontend_debug) {
				printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
					__FUNCTION__, fe->dvb->num);
				for (i = 1; i < 10; i++)
					printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
			}
			err = 0;
			fepriv->state = FESTATE_DISEQC;
			fepriv->status = 0;
		}
		break;

	case FE_DISEQC_RECV_SLAVE_REPLY:
		if (fe->ops.diseqc_recv_slave_reply)
			err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
		break;

	case FE_ENABLE_HIGH_LNB_VOLTAGE:
		if (fe->ops.enable_high_lnb_voltage)
			err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
		break;

	case FE_SET_FRONTEND: {
		struct dvb_frontend_tune_settings fetunesettings;

		memcpy (&fepriv->parameters, parg,
			sizeof (struct dvb_frontend_parameters));

		memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
		memcpy(&fetunesettings.parameters, parg,
		       sizeof (struct dvb_frontend_parameters));

		/* force auto frequency inversion if requested */
		if (dvb_force_auto_inversion) {
			fepriv->parameters.inversion = INVERSION_AUTO;
			fetunesettings.parameters.inversion = INVERSION_AUTO;
		}
		if (fe->ops.info.type == FE_OFDM) {
			/* without hierachical coding code_rate_LP is irrelevant,
			 * so we tolerate the otherwise invalid FEC_NONE setting */
			if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
			    fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
				fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
		}

		/* get frontend-specific tuning settings */
		if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
			fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
			fepriv->max_drift = fetunesettings.max_drift;
			fepriv->step_size = fetunesettings.step_size;
		} else {
			/* default values */
			switch(fe->ops.info.type) {
			case FE_QPSK:
				fepriv->min_delay = HZ/20;
				fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
				fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
				break;

			case FE_QAM:
				fepriv->min_delay = HZ/20;
				fepriv->step_size = 0; /* no zigzag */
				fepriv->max_drift = 0;
				break;

			case FE_OFDM:
				fepriv->min_delay = HZ/20;
				fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
				fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
				break;
			case FE_ATSC:
				fepriv->min_delay = HZ/20;
				fepriv->step_size = 0;
				fepriv->max_drift = 0;
				break;
			}
		}
		if (dvb_override_tune_delay > 0)
			fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;

		fepriv->state = FESTATE_RETUNE;
		dvb_frontend_wakeup(fe);
		dvb_frontend_add_event(fe, 0);
		fepriv->status = 0;
		err = 0;
		break;
	}

	case FE_GET_EVENT:
		err = dvb_frontend_get_event (fe, parg, file->f_flags);
		break;

	case FE_GET_FRONTEND:
		if (fe->ops.get_frontend) {
			memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
			err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
		}
		break;

	case FE_SET_FRONTEND_TUNE_MODE:
		fepriv->tune_mode_flags = (unsigned long) parg;
		err = 0;
		break;
	};
Пример #4
0
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;
	fepriv->wakeup = 0;
	fepriv->reinitialise = 0;

	dvb_frontend_init(fe);

	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;

		if (fepriv->reinitialise) {
			dvb_frontend_init(fe);
			if (fepriv->tone != -1) {
				fe->ops.set_tone(fe, fepriv->tone);
			}
			if (fepriv->voltage != -1) {
				fe->ops.set_voltage(fe, fepriv->voltage);
			}
			fepriv->reinitialise = 0;
		}

		/* do an iteration of the tuning loop */
		if (fe->ops.get_frontend_algo) {
			if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
				/* 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);
		} else
			dvb_frontend_swzigzag(fe);
	}

	if (dvb_shutdown_timeout) {
		if (dvb_powerdown_on_sleep)
			if (fe->ops.set_voltage)
				fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
		if (fe->ops.tuner_ops.sleep) {
			fe->ops.tuner_ops.sleep(fe);
			if (fe->ops.i2c_gate_ctrl)
				fe->ops.i2c_gate_ctrl(fe, 0);
		}
		if (fe->ops.sleep)
			fe->ops.sleep(fe);
	}

	fepriv->thread_pid = 0;
	mb();

	dvb_frontend_wakeup(fe);
	return 0;
}
Пример #5
0
static int dvb_frontend_ioctl (struct inode *inode, struct file *file,
			unsigned int cmd, void *parg)
{
	struct dvb_device *dvbdev = file->private_data;
	struct dvb_frontend *fe = dvbdev->priv;
	int err = -EOPNOTSUPP;

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

	if (!fe || fe->exit)
		return -ENODEV;

	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
	    (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
	     cmd == FE_DISEQC_RECV_SLAVE_REPLY))
		return -EPERM;

	if (down_interruptible (&fe->sem))
		return -ERESTARTSYS;

	switch (cmd) {
	case FE_GET_INFO: {
		struct dvb_frontend_info* info = (struct dvb_frontend_info*) parg;
		memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));

		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
		 * do it, it is done for it. */
		info->caps |= FE_CAN_INVERSION_AUTO;
		err = 0;
		break;
	}

	case FE_READ_STATUS:
		if (fe->ops->read_status)
			err = fe->ops->read_status(fe, (fe_status_t*) parg);
		break;

	case FE_READ_BER:
		if (fe->ops->read_ber)
			err = fe->ops->read_ber(fe, (__u32*) parg);
		break;

	case FE_READ_SIGNAL_STRENGTH:
		if (fe->ops->read_signal_strength)
			err = fe->ops->read_signal_strength(fe, (__u16*) parg);
		break;

	case FE_READ_SNR:
		if (fe->ops->read_snr)
			err = fe->ops->read_snr(fe, (__u16*) parg);
		break;

	case FE_READ_UNCORRECTED_BLOCKS:
		if (fe->ops->read_ucblocks)
			err = fe->ops->read_ucblocks(fe, (__u32*) parg);
		break;


	case FE_DISEQC_RESET_OVERLOAD:
		if (fe->ops->diseqc_reset_overload) {
			err = fe->ops->diseqc_reset_overload(fe);
			fe->state = FESTATE_DISEQC;
			fe->status = 0;
		}
		break;

	case FE_DISEQC_SEND_MASTER_CMD:
		if (fe->ops->diseqc_send_master_cmd) {
			err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
			fe->state = FESTATE_DISEQC;
			fe->status = 0;
		}
		break;

	case FE_DISEQC_SEND_BURST:
		if (fe->ops->diseqc_send_burst) {
			err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
			fe->state = FESTATE_DISEQC;
			fe->status = 0;
		}
		break;

	case FE_SET_TONE:
		if (fe->ops->set_tone) {
			err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
			fe->state = FESTATE_DISEQC;
			fe->status = 0;
		}
		break;

	case FE_SET_VOLTAGE:
		if (fe->ops->set_voltage) {
			err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
		fe->state = FESTATE_DISEQC;
			fe->status = 0;
		}
		break;

	case FE_DISHNETWORK_SEND_LEGACY_CMD:
		if (fe->ops->dishnetwork_send_legacy_command) {
			err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned int) parg);
			fe->state = FESTATE_DISEQC;
			fe->status = 0;
		}
		break;

	case FE_DISEQC_RECV_SLAVE_REPLY:
		if (fe->ops->diseqc_recv_slave_reply)
			err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
		break;

	case FE_ENABLE_HIGH_LNB_VOLTAGE:
		if (fe->ops->enable_high_lnb_voltage);
			err = fe->ops->enable_high_lnb_voltage(fe, (int) parg);
		break;

	case FE_SET_FRONTEND: {
		struct dvb_frontend_tune_settings fetunesettings;
	    
		memcpy (&fe->parameters, parg,
			sizeof (struct dvb_frontend_parameters));

		memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
		memcpy(&fetunesettings.parameters, parg,
		       sizeof (struct dvb_frontend_parameters));
		    
		/* force auto frequency inversion if requested */
		if (dvb_force_auto_inversion) {
			fe->parameters.inversion = INVERSION_AUTO;
			fetunesettings.parameters.inversion = INVERSION_AUTO;
		}
		if (fe->ops->info.type == FE_OFDM) {
			/* without hierachical coding code_rate_LP is irrelevant,
			 * so we tolerate the otherwise invalid FEC_NONE setting */
			if (fe->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
			    fe->parameters.u.ofdm.code_rate_LP == FEC_NONE)
				fe->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
		}

		/* get frontend-specific tuning settings */
		if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
			fe->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
			fe->max_drift = fetunesettings.max_drift;
			fe->step_size = fetunesettings.step_size;
		} else {
			/* default values */
			switch(fe->ops->info.type) {
			case FE_QPSK:
				fe->min_delay = HZ/20;
				fe->step_size = fe->parameters.u.qpsk.symbol_rate / 16000;
				fe->max_drift = fe->parameters.u.qpsk.symbol_rate / 2000;
		break;
			    
			case FE_QAM:
				fe->min_delay = HZ/20;
				fe->step_size = 0; /* no zigzag */
				fe->max_drift = 0;
				break;
			    
			case FE_OFDM:
				fe->min_delay = HZ/20;
				fe->step_size = fe->ops->info.frequency_stepsize * 2;
				fe->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
				break;
			case FE_ATSC:
				printk("dvb-core: FE_ATSC not handled yet.\n");
				break;
			}
		}
		if (dvb_override_tune_delay > 0)
		       fe->min_delay = (dvb_override_tune_delay * HZ) / 1000;

		fe->state = FESTATE_RETUNE;
		dvb_frontend_wakeup(fe);
		dvb_frontend_add_event (fe, 0);	    
		fe->status = 0;
		err = 0;
		break;
	}

	case FE_GET_EVENT:
		err = dvb_frontend_get_event (fe, parg, file->f_flags);
		break;

	case FE_GET_FRONTEND:
		if (fe->ops->get_frontend) {
			memcpy (parg, &fe->parameters, sizeof (struct dvb_frontend_parameters));
			err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
		}
		break;
	};

	up (&fe->sem);
	return err;
}
Пример #6
0
/*
 * FIXME: use linux/kthread.h
 */
static int dvb_frontend_thread (void *data)
{
	struct dvb_frontend *fe = (struct dvb_frontend *) data;
	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 ();

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

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

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

		if (current->flags & PF_FREEZE)
			refrigerator(PF_FREEZE);

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

		/* if we've got no parameters, just keep idling */
		if (fe->state & FESTATE_IDLE) {
			delay = 3*HZ;
			quality = 0;
			continue;
		}

retune:
		/* get the frontend status */
		if (fe->state & FESTATE_RETUNE) {
			s = 0;
		} else {
			if (fe->ops->read_status)
				fe->ops->read_status(fe, &s);
			if (s != fe->status) {
			dvb_frontend_add_event (fe, s);
				fe->status = s;
			}
		}
		/* if we're not tuned, and we have a lock, move to the TUNED state */
		if ((fe->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
			update_delay(&quality, &delay, fe->min_delay, s & FE_HAS_LOCK);
			fe->state = FESTATE_TUNED;

			/* if we're tuned, then we have determined the correct inversion */
			if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
			    (fe->parameters.inversion == INVERSION_AUTO)) {
				fe->parameters.inversion = fe->inversion;
			}
			continue;
		}

		/* if we are tuned already, check we're still locked */
		if (fe->state & FESTATE_TUNED) {
			update_delay(&quality, &delay, fe->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,
				 * need to zigzag */
				fe->state = FESTATE_ZIGZAG_FAST;
				fe->started_auto_step = fe->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 ((fe->state & FESTATE_LOSTLOCK) && 
		    (fe->ops->info.caps & FE_CAN_RECOVER) && (fe->max_drift == 0)) {
			update_delay(&quality, &delay, fe->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 (fe->state & FESTATE_DISEQC) {
			update_delay(&quality, &delay, fe->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 (fe->state & FESTATE_RETUNE) {
			fe->lnb_drift = 0;
			fe->auto_step = 0;
			fe->auto_sub_step = 0;
			fe->started_auto_step = 0;
			check_wrapped = 0;
		}

		/* fast zigzag. */
		if ((fe->state & FESTATE_SEARCHING_FAST) || (fe->state & FESTATE_RETUNE)) {
			delay = fe->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 */
				fe->state = FESTATE_SEARCHING_SLOW;
				fe->started_auto_step = fe->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 (fe->state & FESTATE_RETUNE) {
				fe->state = FESTATE_TUNING_FAST;
				goto retune;
			}
		}

		/* slow zigzag */
		if (fe->state & FESTATE_SEARCHING_SLOW) {
			update_delay(&quality, &delay, fe->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);
		}
	}

	if (dvb_shutdown_timeout) {
		if (dvb_powerdown_on_sleep)
			if (fe->ops->set_voltage)
				fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF);
		if (fe->ops->sleep)
			fe->ops->sleep(fe);
	}

	fe->thread_pid = 0;
	mb();

	dvb_frontend_wakeup(fe);
	return 0;
}
Пример #7
0
static int dvb_frontend_thread(void *data)
{
    struct dvb_frontend *fe = data;
    struct dvb_frontend_private *fepriv = fe->frontend_priv;
    unsigned long timeout;
    fe_status_t s;
    struct dvb_frontend_parameters *params;

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

    fepriv->check_wrapped = 0;
    fepriv->quality = 0;
    fepriv->delay = 3*HZ;
    fepriv->status = 0;
    fepriv->wakeup = 0;
    fepriv->reinitialise = 0;

    dvb_frontend_init(fe);

    set_freezable();
    while (1) {
        up(&fepriv->sem);        /* is locked when we enter the thread... */
restart:
        timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
            dvb_frontend_should_wakeup(fe) || kthread_should_stop()
                || freezing(current),
            fepriv->delay);

        if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
            /* got signal or quitting */
            break;
        }

        if (try_to_freeze())
            goto restart;

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

        if (fepriv->reinitialise) {
            dvb_frontend_init(fe);
            if (fepriv->tone != -1) {
                fe->ops.set_tone(fe, fepriv->tone);
            }
            if (fepriv->voltage != -1) {
                fe->ops.set_voltage(fe, fepriv->voltage);
            }
            fepriv->reinitialise = 0;
        }

        /* do an iteration of the tuning loop */
        if (fe->ops.get_frontend_algo) {
            if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
                /* 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);
        } else
            dvb_frontend_swzigzag(fe);
    }

    if (dvb_powerdown_on_sleep) {
        if (fe->ops.set_voltage)
            fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
        if (fe->ops.tuner_ops.sleep) {
            fe->ops.tuner_ops.sleep(fe);
            if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
        }
        if (fe->ops.sleep)
            fe->ops.sleep(fe);
    }

    fepriv->thread = NULL;
    mb();

    dvb_frontend_wakeup(fe);
    return 0;
}