dvb_frontend.c

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

C
2,092
字号
		dprintk("%s() tvp.u.buffer.len = 0x%02x\n"			,__func__			,tvp->u.buffer.len);		for(i = 0; i < tvp->u.buffer.len; i++)			dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"				,__func__				,i				,tvp->u.buffer.data[i]);	} else		dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);}int is_legacy_delivery_system(fe_delivery_system_t s){	if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) ||		(s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS))		return 1;	return 0;}/* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. */void dtv_property_cache_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p){	struct dtv_frontend_properties *c = &fe->dtv_property_cache;	c->frequency = p->frequency;	c->inversion = p->inversion;	switch (fe->ops.info.type) {	case FE_QPSK:		c->modulation = QPSK;   /* implied for DVB-S in legacy API */		c->rolloff = ROLLOFF_35;/* implied for DVB-S */		c->symbol_rate = p->u.qpsk.symbol_rate;		c->fec_inner = p->u.qpsk.fec_inner;		c->delivery_system = SYS_DVBS;		break;	case FE_QAM:		c->symbol_rate = p->u.qam.symbol_rate;		c->fec_inner = p->u.qam.fec_inner;		c->modulation = p->u.qam.modulation;		c->delivery_system = SYS_DVBC_ANNEX_AC;		break;	case FE_OFDM:		if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ)			c->bandwidth_hz = 6000000;		else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)			c->bandwidth_hz = 7000000;		else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)			c->bandwidth_hz = 8000000;		else			/* Including BANDWIDTH_AUTO */			c->bandwidth_hz = 0;		c->code_rate_HP = p->u.ofdm.code_rate_HP;		c->code_rate_LP = p->u.ofdm.code_rate_LP;		c->modulation = p->u.ofdm.constellation;		c->transmission_mode = p->u.ofdm.transmission_mode;		c->guard_interval = p->u.ofdm.guard_interval;		c->hierarchy = p->u.ofdm.hierarchy_information;		c->delivery_system = SYS_DVBT;		break;	case FE_ATSC:		c->modulation = p->u.vsb.modulation;		if ((c->modulation == VSB_8) || (c->modulation == VSB_16))			c->delivery_system = SYS_ATSC;		else			c->delivery_system = SYS_DVBC_ANNEX_B;		break;	}}/* Ensure the cached values are set correctly in the frontend * legacy tuning structures, for the advanced tuning API. */void dtv_property_legacy_params_sync(struct dvb_frontend *fe){	struct dtv_frontend_properties *c = &fe->dtv_property_cache;	struct dvb_frontend_private *fepriv = fe->frontend_priv;	struct dvb_frontend_parameters *p = &fepriv->parameters;	p->frequency = c->frequency;	p->inversion = c->inversion;	switch (fe->ops.info.type) {	case FE_QPSK:		dprintk("%s() Preparing QPSK req\n", __func__);		p->u.qpsk.symbol_rate = c->symbol_rate;		p->u.qpsk.fec_inner = c->fec_inner;		c->delivery_system = SYS_DVBS;		break;	case FE_QAM:		dprintk("%s() Preparing QAM req\n", __func__);		p->u.qam.symbol_rate = c->symbol_rate;		p->u.qam.fec_inner = c->fec_inner;		p->u.qam.modulation = c->modulation;		c->delivery_system = SYS_DVBC_ANNEX_AC;		break;	case FE_OFDM:		dprintk("%s() Preparing OFDM req\n", __func__);		if (c->bandwidth_hz == 6000000)			p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;		else if (c->bandwidth_hz == 7000000)			p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;		else if (c->bandwidth_hz == 8000000)			p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;		else			p->u.ofdm.bandwidth = BANDWIDTH_AUTO;		p->u.ofdm.code_rate_HP = c->code_rate_HP;		p->u.ofdm.code_rate_LP = c->code_rate_LP;		p->u.ofdm.constellation = c->modulation;		p->u.ofdm.transmission_mode = c->transmission_mode;		p->u.ofdm.guard_interval = c->guard_interval;		p->u.ofdm.hierarchy_information = c->hierarchy;		c->delivery_system = SYS_DVBT;		break;	case FE_ATSC:		dprintk("%s() Preparing VSB req\n", __func__);		p->u.vsb.modulation = c->modulation;		if ((c->modulation == VSB_8) || (c->modulation == VSB_16))			c->delivery_system = SYS_ATSC;		else			c->delivery_system = SYS_DVBC_ANNEX_B;		break;	}}/* Ensure the cached values are set correctly in the frontend * legacy tuning structures, for the legacy tuning API. */void dtv_property_adv_params_sync(struct dvb_frontend *fe){	struct dtv_frontend_properties *c = &fe->dtv_property_cache;	struct dvb_frontend_private *fepriv = fe->frontend_priv;	struct dvb_frontend_parameters *p = &fepriv->parameters;	p->frequency = c->frequency;	p->inversion = c->inversion;	switch(c->modulation) {	case PSK_8:	case APSK_16:	case APSK_32:	case QPSK:		p->u.qpsk.symbol_rate = c->symbol_rate;		p->u.qpsk.fec_inner = c->fec_inner;		break;	default:		break;	}	if(c->delivery_system == SYS_ISDBT) {		/* Fake out a generic DVB-T request so we pass validation in the ioctl */		p->frequency = c->frequency;		p->inversion = INVERSION_AUTO;		p->u.ofdm.constellation = QAM_AUTO;		p->u.ofdm.code_rate_HP = FEC_AUTO;		p->u.ofdm.code_rate_LP = FEC_AUTO;		p->u.ofdm.bandwidth = BANDWIDTH_AUTO;		p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;		p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;		p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;	}}void dtv_property_cache_submit(struct dvb_frontend *fe){	struct dtv_frontend_properties *c = &fe->dtv_property_cache;	/* For legacy delivery systems we don't need the delivery_system to	 * be specified, but we populate the older structures from the cache	 * so we can call set_frontend on older drivers.	 */	if(is_legacy_delivery_system(c->delivery_system)) {		dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation);		dtv_property_legacy_params_sync(fe);	} else {		dprintk("%s() adv, modulation = %d\n", __func__, c->modulation);		/* For advanced delivery systems / modulation types ...		 * we seed the lecacy dvb_frontend_parameters structure		 * so that the sanity checking code later in the IOCTL processing		 * can validate our basic frequency ranges, symbolrates, modulation		 * etc.		 */		dtv_property_adv_params_sync(fe);	}}static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file,			unsigned int cmd, void *parg);static int dvb_frontend_ioctl_properties(struct inode *inode, struct file *file,			unsigned int cmd, void *parg);int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp,	struct inode *inode, struct file *file){	int r = 0;	dtv_property_dump(tvp);	/* Allow the frontend to validate incoming properties */	if (fe->ops.get_property)		r = fe->ops.get_property(fe, tvp);	if (r < 0)		return r;	switch(tvp->cmd) {	case DTV_FREQUENCY:		tvp->u.data = fe->dtv_property_cache.frequency;		break;	case DTV_MODULATION:		tvp->u.data = fe->dtv_property_cache.modulation;		break;	case DTV_BANDWIDTH_HZ:		tvp->u.data = fe->dtv_property_cache.bandwidth_hz;		break;	case DTV_INVERSION:		tvp->u.data = fe->dtv_property_cache.inversion;		break;	case DTV_SYMBOL_RATE:		tvp->u.data = fe->dtv_property_cache.symbol_rate;		break;	case DTV_INNER_FEC:		tvp->u.data = fe->dtv_property_cache.fec_inner;		break;	case DTV_PILOT:		tvp->u.data = fe->dtv_property_cache.pilot;		break;	case DTV_ROLLOFF:		tvp->u.data = fe->dtv_property_cache.rolloff;		break;	case DTV_DELIVERY_SYSTEM:		tvp->u.data = fe->dtv_property_cache.delivery_system;		break;#if 0	/* ISDB-T Support here */	case DTV_ISDB_SEGMENT_IDX:		tvp->u.data = fe->dtv_property_cache.isdb_segment_idx;		break;	case DTV_ISDB_SEGMENT_WIDTH:		tvp->u.data = fe->dtv_property_cache.isdb_segment_width;		break;	case DTV_ISDB_LAYERA_FEC:		tvp->u.data = fe->dtv_property_cache.isdb_layera_fec;		break;	case DTV_ISDB_LAYERA_MODULATION:		tvp->u.data = fe->dtv_property_cache.isdb_layera_modulation;		break;	case DTV_ISDB_LAYERA_SEGMENT_WIDTH:		tvp->u.data = fe->dtv_property_cache.isdb_layera_segment_width;		break;	case DTV_ISDB_LAYERB_FEC:		tvp->u.data = fe->dtv_property_cache.isdb_layerb_fec;		break;	case DTV_ISDB_LAYERB_MODULATION:		tvp->u.data = fe->dtv_property_cache.isdb_layerb_modulation;		break;	case DTV_ISDB_LAYERB_SEGMENT_WIDTH:		tvp->u.data = fe->dtv_property_cache.isdb_layerb_segment_width;		break;	case DTV_ISDB_LAYERC_FEC:		tvp->u.data = fe->dtv_property_cache.isdb_layerc_fec;		break;	case DTV_ISDB_LAYERC_MODULATION:		tvp->u.data = fe->dtv_property_cache.isdb_layerc_modulation;		break;	case DTV_ISDB_LAYERC_SEGMENT_WIDTH:		tvp->u.data = fe->dtv_property_cache.isdb_layerc_segment_width;		break;#endif	case DTV_VOLTAGE:		tvp->u.data = fe->dtv_property_cache.voltage;		break;	case DTV_TONE:		tvp->u.data = fe->dtv_property_cache.sectone;		break;	case DTV_API_VERSION:		tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;		break;	case DTV_CODE_RATE_HP:		tvp->u.data = fe->dtv_property_cache.code_rate_HP;		break;	case DTV_CODE_RATE_LP:		tvp->u.data = fe->dtv_property_cache.code_rate_LP;		break;	case DTV_GUARD_INTERVAL:		tvp->u.data = fe->dtv_property_cache.guard_interval;		break;	case DTV_TRANSMISSION_MODE:		tvp->u.data = fe->dtv_property_cache.transmission_mode;		break;	case DTV_HIERARCHY:		tvp->u.data = fe->dtv_property_cache.hierarchy;		break;	default:		r = -1;	}	return r;}int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp,	struct inode *inode, struct file *file){	int r = 0;	struct dvb_frontend_private *fepriv = fe->frontend_priv;	dtv_property_dump(tvp);	/* Allow the frontend to validate incoming properties */	if (fe->ops.set_property)		r = fe->ops.set_property(fe, tvp);	if (r < 0)		return r;	switch(tvp->cmd) {	case DTV_CLEAR:		/* Reset a cache of data specific to the frontend here. This does		 * not effect hardware.		 */		dprintk("%s() Flushing property cache\n", __func__);		memset(&fe->dtv_property_cache, 0, sizeof(struct dtv_frontend_properties));		fe->dtv_property_cache.state = tvp->cmd;		fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;		break;	case DTV_TUNE:		/* interpret the cache of data, build either a traditional frontend		 * tunerequest so we can pass validation in the FE_SET_FRONTEND		 * ioctl.		 */		fe->dtv_property_cache.state = tvp->cmd;		dprintk("%s() Finalised property cache\n", __func__);		dtv_property_cache_submit(fe);		r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND,			&fepriv->parameters);		break;	case DTV_FREQUENCY:		fe->dtv_property_cache.frequency = tvp->u.data;		break;	case DTV_MODULATION:		fe->dtv_property_cache.modulation = tvp->u.data;		break;	case DTV_BANDWIDTH_HZ:		fe->dtv_property_cache.bandwidth_hz = tvp->u.data;		break;	case DTV_INVERSION:		fe->dtv_property_cache.inversion = tvp->u.data;		break;	case DTV_SYMBOL_RATE:		fe->dtv_property_cache.symbol_rate = tvp->u.data;		break;	case DTV_INNER_FEC:		fe->dtv_property_cache.fec_inner = tvp->u.data;		break;	case DTV_PILOT:		fe->dtv_property_cache.pilot = tvp->u.data;		break;	case DTV_ROLLOFF:		fe->dtv_property_cache.rolloff = tvp->u.data;		break;	case DTV_DELIVERY_SYSTEM:		fe->dtv_property_cache.delivery_system = tvp->u.data;		break;#if 0	/* ISDB-T Support here */	case DTV_ISDB_SEGMENT_IDX:		fe->dtv_property_cache.isdb_segment_idx = tvp->u.data;		break;	case DTV_ISDB_SEGMENT_WIDTH:		fe->dtv_property_cache.isdb_segment_width = tvp->u.data;		break;#endif	case DTV_VOLTAGE:		fe->dtv_property_cache.voltage = tvp->u.data;		r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_VOLTAGE,			(void *)fe->dtv_property_cache.voltage);		break;	case DTV_TONE:		fe->dtv_property_cache.sectone = tvp->u.data;		r = dvb_frontend_ioctl_legacy(inode, file, FE_SET_TONE,			(void *)fe->dtv_property_cache.sectone);		break;	case DTV_CODE_RATE_HP:		fe->dtv_property_cache.code_rate_HP = tvp->u.data;		break;	case DTV_CODE_RATE_LP:		fe->dtv_property_cache.code_rate_LP = tvp->u.data;		break;	case DTV_GUARD_INTERVAL:		fe->dtv_property_cache.guard_interval = tvp->u.data;		break;	case DTV_TRANSMISSION_MODE:		fe->dtv_property_cache.transmission_mode = tvp->u.data;		break;	case DTV_HIERARCHY:		fe->dtv_property_cache.hierarchy = tvp->u.data;		break;	default:		r = -1;	}	return r;}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", __func__);	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;	if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))		err = dvb_frontend_ioctl_properties(inode, file, cmd, parg);	else {		fe->dtv_property_cache.state = DTV_UNDEFINED;		err = dvb_frontend_ioctl_legacy(inode, file, cmd, parg);	}	up(&fepriv->sem);	return err;}static int dvb_frontend_ioctl_properties(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 = 0;	struct dtv_properties *tvps = NULL;	struct dtv_property *tvp = NULL;	int i;	dprintk("%s\n", __func__);	if(cmd == FE_SET_PROPERTY) {		tvps = (struct dtv_properties __user *)parg;		dprintk("%s() properties.num = %d\n", __func__, tvps->num);		dprintk("%s() properties.props = %p\n", __func__, tvps->props);		/* Put an arbitrary limit on the number of messages that can		 * be sent at once */		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))			return -EINVAL;		tvp = (struct dtv_property *) kmalloc(tvps->num *			sizeof(struct dtv_property), GFP_KERNEL);		if (!tvp) {			err = -ENOMEM;			goto out;		}		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {			err = -EFAULT;			goto out;		}		for (i = 0; i < tvps->num; i++) {			(tvp + i)->result = dtv_property_process_set(fe, tvp + i, inode, file);			err |= (tvp + i)->result;		}		if(fe->dtv_property_cache.state == DTV_TUNE)			dprintk("%s() Property cache is full, tuning\n", __func__);	} else	if(cmd == FE_GET_PROPERTY) {		tvps = (struct dtv_properties __user *)parg;		dprintk("%s() properties.num = %d\n", __func__, tvps->num);		dprintk("%s() properties.props = %p\n", __func__, tvps->props);		/* Put an arbitrary limit on the number of messages that can		 * be sent at once */		if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))			return -EINVAL;		tvp = (struct dtv_property *) kmalloc(tvps->num *			sizeof(struct dtv_property), GFP_KERNEL);		if (!tvp) {			err = -ENOMEM;			goto out;		}		if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {			err = -EFAULT;			goto out;		}		for (i = 0; i < tvps->num; i++) {			(tvp + i)->result = dtv_property_process_get(fe, tvp + i, inode, file);			err |= (tvp + i)->result;		}		if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {			err = -EFAULT;			goto out;

⌨️ 快捷键说明

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