dvb_frontend.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,092 行 · 第 1/4 页

C
2,092
字号
	fe_status_t s;	enum dvbfe_algo algo;	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:#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)		timeout = wait_event_interruptible_timeout(fepriv->wait_queue,			dvb_frontend_should_wakeup(fe) || kthread_should_stop(),			fepriv->delay);#else		timeout = wait_event_interruptible_timeout(fepriv->wait_queue,			dvb_frontend_should_wakeup(fe) || kthread_should_stop()				|| freezing(current),			fepriv->delay);#endif		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) {			algo = fe->ops.get_frontend_algo(fe);			switch (algo) {			case DVBFE_ALGO_HW:				dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);				params = NULL; /* have we been asked to RETUNE ? */				if (fepriv->state & FESTATE_RETUNE) {					dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);					fepriv->state = FESTATE_TUNED;				}				if (fe->ops.tune)					fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);				if (s != fepriv->status) {					dprintk("%s: state changed, adding current state\n", __func__);					dvb_frontend_add_event(fe, s);					fepriv->status = s;				}				break;			case DVBFE_ALGO_SW:				dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);				dvb_frontend_swzigzag(fe);				break;			case DVBFE_ALGO_CUSTOM:				params = NULL; /* have we been asked to RETUNE ?	*/				dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);				if (fepriv->state & FESTATE_RETUNE) {					dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);					fepriv->state = FESTATE_TUNED;				}				/* Case where we are going to search for a carrier				 * User asked us to retune again for some reason, possibly				 * requesting a search with a new set of parameters				 */				if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {					if (fe->ops.search) {						fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);						/* We did do a search as was requested, the flags are						 * now unset as well and has the flags wrt to search.						 */					} else {						fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;					}				}				/* Track the carrier if the search was successful */				if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {					if (fe->ops.track)						fe->ops.track(fe, &fepriv->parameters);				} else {					fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;					fepriv->delay = HZ / 2;				}				fe->ops.read_status(fe, &s);				if (s != fepriv->status) {					dvb_frontend_add_event(fe, s); /* update event list */					fepriv->status = s;					if (!(s & FE_HAS_LOCK)) {						fepriv->delay = HZ / 10;						fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;					} else {						fepriv->delay = 60 * HZ;					}				}				break;			default:				dprintk("%s: UNDEFINED ALGO !\n", __func__);				break;			}		} 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", __func__);	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", __func__);	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-ad-%i-fe-%i", fe->dvb->num,fe->id);	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: adapter %i frontend %u frequency limits undefined - fix the driver\n",		       fe->dvb->num,fe->id);}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: adapter %i frontend %i frequency %u out of range (%u..%u)\n",		       fe->dvb->num, fe->id, 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: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",			       fe->dvb->num, fe->id, 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: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",			       fe->dvb->num, fe->id, parms->u.qam.symbol_rate,			       fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);			return -EINVAL;		}	}	return 0;}struct dtv_cmds_h dtv_cmds[] = {	[DTV_TUNE] = {		.name	= "DTV_TUNE",		.cmd	= DTV_TUNE,		.set	= 1,	},	[DTV_CLEAR] = {		.name	= "DTV_CLEAR",		.cmd	= DTV_CLEAR,		.set	= 1,	},	/* Set */	[DTV_FREQUENCY] = {		.name	= "DTV_FREQUENCY",		.cmd	= DTV_FREQUENCY,		.set	= 1,	},	[DTV_BANDWIDTH_HZ] = {		.name	= "DTV_BANDWIDTH_HZ",		.cmd	= DTV_BANDWIDTH_HZ,		.set	= 1,	},	[DTV_MODULATION] = {		.name	= "DTV_MODULATION",		.cmd	= DTV_MODULATION,		.set	= 1,	},	[DTV_INVERSION] = {		.name	= "DTV_INVERSION",		.cmd	= DTV_INVERSION,		.set	= 1,	},	[DTV_DISEQC_MASTER] = {		.name	= "DTV_DISEQC_MASTER",		.cmd	= DTV_DISEQC_MASTER,		.set	= 1,		.buffer	= 1,	},	[DTV_SYMBOL_RATE] = {		.name	= "DTV_SYMBOL_RATE",		.cmd	= DTV_SYMBOL_RATE,		.set	= 1,	},	[DTV_INNER_FEC] = {		.name	= "DTV_INNER_FEC",		.cmd	= DTV_INNER_FEC,		.set	= 1,	},	[DTV_VOLTAGE] = {		.name	= "DTV_VOLTAGE",		.cmd	= DTV_VOLTAGE,		.set	= 1,	},	[DTV_TONE] = {		.name	= "DTV_TONE",		.cmd	= DTV_TONE,		.set	= 1,	},	[DTV_PILOT] = {		.name	= "DTV_PILOT",		.cmd	= DTV_PILOT,		.set	= 1,	},	[DTV_ROLLOFF] = {		.name	= "DTV_ROLLOFF",		.cmd	= DTV_ROLLOFF,		.set	= 1,	},	[DTV_DELIVERY_SYSTEM] = {		.name	= "DTV_DELIVERY_SYSTEM",		.cmd	= DTV_DELIVERY_SYSTEM,		.set	= 1,	},	[DTV_HIERARCHY] = {		.name	= "DTV_HIERARCHY",		.cmd	= DTV_HIERARCHY,		.set	= 1,	},#if 0	[DTV_ISDB_SEGMENT_IDX] = {		.name	= "DTV_ISDB_SEGMENT_IDX",		.cmd	= DTV_ISDB_SEGMENT_IDX,		.set	= 1,	},	[DTV_ISDB_SEGMENT_WIDTH] = {		.name	= "DTV_ISDB_SEGMENT_WIDTH",		.cmd	= DTV_ISDB_SEGMENT_WIDTH,		.set	= 1,	},#endif	[DTV_CODE_RATE_HP] = {		.name	= "DTV_CODE_RATE_HP",		.cmd	= DTV_CODE_RATE_HP,		.set	= 1,	},	[DTV_CODE_RATE_LP] = {		.name	= "DTV_CODE_RATE_LP",		.cmd	= DTV_CODE_RATE_LP,		.set	= 1,	},	[DTV_GUARD_INTERVAL] = {		.name	= "DTV_GUARD_INTERVAL",		.cmd	= DTV_GUARD_INTERVAL,		.set	= 1,	},	[DTV_TRANSMISSION_MODE] = {		.name	= "DTV_TRANSMISSION_MODE",		.cmd	= DTV_TRANSMISSION_MODE,		.set	= 1,	},	/* Get */	[DTV_DISEQC_SLAVE_REPLY] = {		.name	= "DTV_DISEQC_SLAVE_REPLY",		.cmd	= DTV_DISEQC_SLAVE_REPLY,		.set	= 0,		.buffer	= 1,	},#if 0	[DTV_ISDB_LAYERA_FEC] = {		.name	= "DTV_ISDB_LAYERA_FEC",		.cmd	= DTV_ISDB_LAYERA_FEC,		.set	= 0,	},	[DTV_ISDB_LAYERA_MODULATION] = {		.name	= "DTV_ISDB_LAYERA_MODULATION",		.cmd	= DTV_ISDB_LAYERA_MODULATION,		.set	= 0,	},	[DTV_ISDB_LAYERA_SEGMENT_WIDTH] = {		.name	= "DTV_ISDB_LAYERA_SEGMENT_WIDTH",		.cmd	= DTV_ISDB_LAYERA_SEGMENT_WIDTH,		.set	= 0,	},	[DTV_ISDB_LAYERB_FEC] = {		.name	= "DTV_ISDB_LAYERB_FEC",		.cmd	= DTV_ISDB_LAYERB_FEC,		.set	= 0,	},	[DTV_ISDB_LAYERB_MODULATION] = {		.name	= "DTV_ISDB_LAYERB_MODULATION",		.cmd	= DTV_ISDB_LAYERB_MODULATION,		.set	= 0,	},	[DTV_ISDB_LAYERB_SEGMENT_WIDTH] = {		.name	= "DTV_ISDB_LAYERB_SEGMENT_WIDTH",		.cmd	= DTV_ISDB_LAYERB_SEGMENT_WIDTH,		.set	= 0,	},	[DTV_ISDB_LAYERC_FEC] = {		.name	= "DTV_ISDB_LAYERC_FEC",		.cmd	= DTV_ISDB_LAYERC_FEC,		.set	= 0,	},	[DTV_ISDB_LAYERC_MODULATION] = {		.name	= "DTV_ISDB_LAYERC_MODULATION",		.cmd	= DTV_ISDB_LAYERC_MODULATION,		.set	= 0,	},	[DTV_ISDB_LAYERC_SEGMENT_WIDTH] = {		.name	= "DTV_ISDB_LAYERC_SEGMENT_WIDTH",		.cmd	= DTV_ISDB_LAYERC_SEGMENT_WIDTH,		.set	= 0,	},#endif	[DTV_API_VERSION] = {		.name	= "DTV_API_VERSION",		.cmd	= DTV_API_VERSION,		.set	= 0,	},	[DTV_CODE_RATE_HP] = {		.name	= "DTV_CODE_RATE_HP",		.cmd	= DTV_CODE_RATE_HP,		.set	= 0,	},	[DTV_CODE_RATE_LP] = {		.name	= "DTV_CODE_RATE_LP",		.cmd	= DTV_CODE_RATE_LP,		.set	= 0,	},	[DTV_GUARD_INTERVAL] = {		.name	= "DTV_GUARD_INTERVAL",		.cmd	= DTV_GUARD_INTERVAL,		.set	= 0,	},	[DTV_TRANSMISSION_MODE] = {		.name	= "DTV_TRANSMISSION_MODE",		.cmd	= DTV_TRANSMISSION_MODE,		.set	= 0,	},	[DTV_HIERARCHY] = {		.name	= "DTV_HIERARCHY",		.cmd	= DTV_HIERARCHY,		.set	= 0,	},};void dtv_property_dump(struct dtv_property *tvp){	int i;	if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {		printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",			__func__, tvp->cmd);		return;	}	dprintk("%s() tvp.cmd    = 0x%08x (%s)\n"		,__func__		,tvp->cmd		,dtv_cmds[ tvp->cmd ].name);	if(dtv_cmds[ tvp->cmd ].buffer) {

⌨️ 快捷键说明

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