dvb_frontend.c

来自「V4l driver for DVB HD」· C语言 代码 · 共 1,104 行 · 第 1/3 页

C
1,104
字号
	} else {		if (fe->ops->read_status)			fe->ops->read_status(fe, &s);		if (s != fepriv->status) {			dvb_frontend_add_event(fe, s);			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)) {		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 */		if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&		    (fepriv->parameters.inversion == INVERSION_AUTO)) {			fepriv->parameters.inversion = fepriv->inversion;		}		return;	}	/* if we are tuned already, check we're still locked */	if (fepriv->state & FESTATE_TUNED) {		dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);		/* we're tuned, and the lock is still good... */		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;			fepriv->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 ((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;	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 = 1;	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;		}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)		try_to_freeze();#else		if (current->flags & PF_FREEZE) {			refrigerator (PF_FREEZE);		}#endif		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->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);		}	}	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);	}	fepriv->thread_pid = 0;	mb();	dvb_frontend_wakeup(fe);	return 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);}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;	dprintk ("%s\n", __FUNCTION__);	if (fepriv->thread_pid) {		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_pid = 0;	mb();	ret = kernel_thread (dvb_frontend_thread, fe, 0);	if (ret < 0) {		printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret);		up(&fepriv->sem);		return ret;	}	fepriv->thread_pid = ret;	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 (!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. */

⌨️ 快捷键说明

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