dvb_frontend.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,190 行 · 第 1/3 页

C
1,190
字号
			fe->inversion = (fe->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;			ready = 1;			break;		case 2:			if (fe->lnb_drift == 0) break;		    			fe->lnb_drift = -fe->lnb_drift;			ready = 1;			break;	    		case 3:			if (fe->lnb_drift == 0) break;			if (!autoinversion) break;		    			fe->inversion = (fe->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;			fe->lnb_drift = -fe->lnb_drift;			ready = 1;			break;		    		default:			fe->auto_step++;			fe->auto_sub_step = -1; // it'll be incremented to 0 in a moment			break;		}	    		if (!ready) fe->auto_sub_step++;	}	// if this attempt would hit where we started, indicate a complete iteration has occurred	if ((fe->auto_step == fe->started_auto_step) && (fe->auto_sub_step == 0) && check_wrapped) {		return 1;		}	// perform frequency bending if necessary	if ((dvb_override_frequency_bending != 1) && do_frequency_bending)		dvb_bend_frequency(fe, 0);	// instrumentation	dprintk("%s: drift:%i bending:%i inversion:%i auto_step:%i auto_sub_step:%i started_auto_step:%i\n", 		__FUNCTION__, fe->lnb_drift, fe->bending, fe->inversion, fe->auto_step, fe->auto_sub_step,		fe->started_auto_step);    	// 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;	// normal return	fe->auto_sub_step++;	return 0;}static int dvb_frontend_is_exiting (struct dvb_frontend_data *fe){	if (fe->exit)		return 1;	if (fe->dvbdev->writers == 1)		if (jiffies - fe->release_jiffies > dvb_shutdown_timeout * HZ)			return 1;	return 0;}static int dvb_frontend_should_wakeup (struct dvb_frontend_data *fe){	if (fe->wakeup) {		fe->wakeup = 0;		return 1;	}	return dvb_frontend_is_exiting(fe);}static void dvb_frontend_wakeup (struct dvb_frontend_data *fe) {	fe->wakeup = 1;	wake_up_interruptible(&fe->wait_queue);}static int dvb_frontend_thread (void *data){	struct dvb_frontend_data *fe = (struct dvb_frontend_data *) 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:%i",		  fe->frontend.i2c->adapter->num, fe->frontend.i2c->id);	dvb_kernel_thread_setup (name);	dvb_call_frontend_notifiers (fe, 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,0 != dvb_frontend_should_wakeup (fe), delay);		if (-ERESTARTSYS == timeout || 0 != dvb_frontend_is_exiting (fe)) {			/* got signal or quitting */			break;		}		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;		}		// get the frontend status		dvb_frontend_internal_ioctl (&fe->frontend, FE_READ_STATUS, &s);		if (s != fe->status)			dvb_frontend_add_event (fe, 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->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;				// fallthrough			}		}		// 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->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;				wake_up_interruptible(&fe->wait_queue);			}		}		// 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)		dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL); 	up (&fe->sem);	fe->thread_pid = 0;	mb();	dvb_frontend_wakeup(fe);	return 0;}static void dvb_frontend_stop (struct dvb_frontend_data *fe){	unsigned long ret;	dprintk ("%s\n", __FUNCTION__);		fe->exit = 1;	mb();	if (!fe->thread_pid)		return;	/* check if the thread is really alive */	if (kill_proc(fe->thread_pid, 0, 1) == -ESRCH) {		printk("dvb_frontend_stop: thread PID %d already died\n",				fe->thread_pid);		/* make sure the mutex was not held by the thread */		init_MUTEX (&fe->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(fe->wait_queue,0 == fe->thread_pid);	if (-ERESTARTSYS != ret) {		fe->state = FESTATE_IDLE;		return;	}	fe->state = FESTATE_IDLE;	/* paranoia check in case a signal arrived */	if (fe->thread_pid)		printk("dvb_frontend_stop: warning: thread PID %d won't exit\n",				fe->thread_pid);}static int dvb_frontend_start (struct dvb_frontend_data *fe){	int ret;	dprintk ("%s\n", __FUNCTION__);	if (fe->thread_pid) {		if (!fe->exit)			return 0;		else		dvb_frontend_stop (fe);	}	if (signal_pending(current))		return -EINTR;	if (down_interruptible (&fe->sem))		return -EINTR;	fe->state = FESTATE_IDLE;	fe->exit = 0;	fe->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(&fe->sem);		return ret;	}	fe->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_data *fe = dvbdev->priv;	struct dvb_frontend_tune_settings fetunesettings;	int err = 0;	dprintk ("%s\n", __FUNCTION__);	if (!fe || !fe->frontend.ioctl || fe->exit)		return -ENODEV;	if (down_interruptible (&fe->sem))		return -ERESTARTSYS;	switch (cmd) {	case FE_DISEQC_SEND_MASTER_CMD:	case FE_DISEQC_SEND_BURST:	case FE_SET_TONE:		if (fe->status)			dvb_call_frontend_notifiers (fe, 0);		dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);		fe->state = FESTATE_DISEQC;		break;	case FE_SET_FRONTEND:		fe->state = FESTATE_RETUNE;	    		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;		}		// get frontend-specific tuning settings		if (dvb_frontend_internal_ioctl(&fe->frontend, FE_GET_TUNE_SETTINGS, &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->info->type) {			case FE_QPSK:				fe->min_delay = HZ/20; // default mindelay of 50ms				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; // default mindelay of 50ms				fe->step_size = 0;				fe->max_drift = 0; // don't want any zigzagging under DVB-C frontends				break;			    			case FE_OFDM:				fe->min_delay = HZ/20; // default mindelay of 50ms				fe->step_size = fe->info->frequency_stepsize * 2;				fe->max_drift = (fe->info->frequency_stepsize * 2) + 1;				break;			}		}		if (dvb_override_tune_delay > 0) {		       fe->min_delay = (dvb_override_tune_delay * HZ) / 1000;		}		dvb_frontend_add_event (fe, 0);	    		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));		/*  fall-through... */	default:		err = dvb_frontend_internal_ioctl (&fe->frontend, cmd, parg);	};	up (&fe->sem);	if (err < 0)		return err;	// Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't do it, it is done for it.	if ((cmd == FE_GET_INFO) && (err == 0)) {		struct dvb_frontend_info* tmp = (struct dvb_frontend_info*) parg;

⌨️ 快捷键说明

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