⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dvb_frontend.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		}	}	/* 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;	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;	fe_status_t s;	struct dvb_frontend_parameters *params;	dprintk("%s\n", __FUNCTION__);	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;}static void dvb_frontend_stop(struct dvb_frontend *fe){	struct dvb_frontend_private *fepriv = fe->frontend_priv;	dprintk ("%s\n", __FUNCTION__);	fepriv->exit = 1;	mb();	if (!fepriv->thread)		return;	kthread_stop(fepriv->thread);	init_MUTEX (&fepriv->sem);	fepriv->state = FESTATE_IDLE;	/* paranoia check in case a signal arrived */	if (fepriv->thread)		printk("dvb_frontend_stop: warning: thread %p won't exit\n",				fepriv->thread);}s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime){	return ((curtime.tv_usec < lasttime.tv_usec) ?		1000000 - lasttime.tv_usec + curtime.tv_usec :		curtime.tv_usec - lasttime.tv_usec);}EXPORT_SYMBOL(timeval_usec_diff);static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec){	curtime->tv_usec += add_usec;	if (curtime->tv_usec >= 1000000) {		curtime->tv_usec -= 1000000;		curtime->tv_sec++;	}}/* * Sleep until gettimeofday() > waketime + add_usec * This needs to be as precise as possible, but as the delay is * usually between 2ms and 32ms, it is done using a scheduled msleep * followed by usleep (normally a busy-wait loop) for the remainder */void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec){	struct timeval lasttime;	s32 delta, newdelta;	timeval_usec_add(waketime, add_usec);	do_gettimeofday(&lasttime);	delta = timeval_usec_diff(lasttime, *waketime);	if (delta > 2500) {		msleep((delta - 1500) / 1000);		do_gettimeofday(&lasttime);		newdelta = timeval_usec_diff(lasttime, *waketime);		delta = (newdelta > delta) ? 0 : newdelta;	}	if (delta > 0)		udelay(delta);}EXPORT_SYMBOL(dvb_frontend_sleep_until);static int dvb_frontend_start(struct dvb_frontend *fe){	int ret;	struct dvb_frontend_private *fepriv = fe->frontend_priv;	struct task_struct *fe_thread;	dprintk ("%s\n", __FUNCTION__);	if (fepriv->thread) {		if (!fepriv->exit)			return 0;		else			dvb_frontend_stop (fe);	}	if (signal_pending(current))		return -EINTR;	if (down_interruptible (&fepriv->sem))		return -EINTR;	fepriv->state = FESTATE_IDLE;	fepriv->exit = 0;	fepriv->thread = NULL;	mb();	fe_thread = kthread_run(dvb_frontend_thread, fe,		"kdvb-fe-%i", fe->dvb->num);	if (IS_ERR(fe_thread)) {		ret = PTR_ERR(fe_thread);		printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);		up(&fepriv->sem);		return ret;	}	fepriv->thread = fe_thread;	return 0;}static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,					u32 *freq_min, u32 *freq_max){	*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);	if (fe->ops.info.frequency_max == 0)		*freq_max = fe->ops.tuner_ops.info.frequency_max;	else if (fe->ops.tuner_ops.info.frequency_max == 0)		*freq_max = fe->ops.info.frequency_max;	else		*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);	if (*freq_min == 0 || *freq_max == 0)		printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",		       fe->dvb->num);}static int dvb_frontend_check_parameters(struct dvb_frontend *fe,				struct dvb_frontend_parameters *parms){	u32 freq_min;	u32 freq_max;	/* range check: frequency */	dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);	if ((freq_min && parms->frequency < freq_min) ||	    (freq_max && parms->frequency > freq_max)) {		printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",		       fe->dvb->num, parms->frequency, freq_min, freq_max);		return -EINVAL;	}	/* range check: symbol rate */	if (fe->ops.info.type == FE_QPSK) {		if ((fe->ops.info.symbol_rate_min &&		     parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||		    (fe->ops.info.symbol_rate_max &&		     parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {			printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",			       fe->dvb->num, parms->u.qpsk.symbol_rate,			       fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);			return -EINVAL;		}	} else if (fe->ops.info.type == FE_QAM) {		if ((fe->ops.info.symbol_rate_min &&		     parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||		    (fe->ops.info.symbol_rate_max &&		     parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {			printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",			       fe->dvb->num, parms->u.qam.symbol_rate,			       fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);			return -EINVAL;		}	}	return 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 (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));		dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);		/* 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -