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

📄 dvb_frontend.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	case FE_READ_SNR:		if (fe->ops.read_snr)			err = fe->ops.read_snr(fe, (__u16*) parg);		break;	case FE_READ_UNCORRECTED_BLOCKS:		if (fe->ops.read_ucblocks)			err = fe->ops.read_ucblocks(fe, (__u32*) parg);		break;	case FE_DISEQC_RESET_OVERLOAD:		if (fe->ops.diseqc_reset_overload) {			err = fe->ops.diseqc_reset_overload(fe);			fepriv->state = FESTATE_DISEQC;			fepriv->status = 0;		}		break;	case FE_DISEQC_SEND_MASTER_CMD:		if (fe->ops.diseqc_send_master_cmd) {			err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);			fepriv->state = FESTATE_DISEQC;			fepriv->status = 0;		}		break;	case FE_DISEQC_SEND_BURST:		if (fe->ops.diseqc_send_burst) {			err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);			fepriv->state = FESTATE_DISEQC;			fepriv->status = 0;		}		break;	case FE_SET_TONE:		if (fe->ops.set_tone) {			err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);			fepriv->tone = (fe_sec_tone_mode_t) parg;			fepriv->state = FESTATE_DISEQC;			fepriv->status = 0;		}		break;	case FE_SET_VOLTAGE:		if (fe->ops.set_voltage) {			err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);			fepriv->voltage = (fe_sec_voltage_t) parg;			fepriv->state = FESTATE_DISEQC;			fepriv->status = 0;		}		break;	case FE_DISHNETWORK_SEND_LEGACY_CMD:		if (fe->ops.dishnetwork_send_legacy_command) {			err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);			fepriv->state = FESTATE_DISEQC;			fepriv->status = 0;		} else if (fe->ops.set_voltage) {			/*			 * NOTE: This is a fallback condition.  Some frontends			 * (stv0299 for instance) take longer than 8msec to			 * respond to a set_voltage command.  Those switches			 * need custom routines to switch properly.  For all			 * other frontends, the following shoule work ok.			 * Dish network legacy switches (as used by Dish500)			 * are controlled by sending 9-bit command words			 * spaced 8msec apart.			 * the actual command word is switch/port dependant			 * so it is up to the userspace application to send			 * the right command.			 * The command must always start with a '0' after			 * initialization, so parg is 8 bits and does not			 * include the initialization or start bit			 */			unsigned long cmd = ((unsigned long) parg) << 1;			struct timeval nexttime;			struct timeval tv[10];			int i;			u8 last = 1;			if (dvb_frontend_debug)				printk("%s switch command: 0x%04lx\n", __FUNCTION__, cmd);			do_gettimeofday(&nexttime);			if (dvb_frontend_debug)				memcpy(&tv[0], &nexttime, sizeof(struct timeval));			/* before sending a command, initialize by sending			 * a 32ms 18V to the switch			 */			fe->ops.set_voltage(fe, SEC_VOLTAGE_18);			dvb_frontend_sleep_until(&nexttime, 32000);			for (i = 0; i < 9; i++) {				if (dvb_frontend_debug)					do_gettimeofday(&tv[i + 1]);				if ((cmd & 0x01) != last) {					/* set voltage to (last ? 13V : 18V) */					fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);					last = (last) ? 0 : 1;				}				cmd = cmd >> 1;				if (i != 8)					dvb_frontend_sleep_until(&nexttime, 8000);			}			if (dvb_frontend_debug) {				printk("%s(%d): switch delay (should be 32k followed by all 8k\n",					__FUNCTION__, fe->dvb->num);				for (i = 1; i < 10; i++)					printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));			}			err = 0;			fepriv->state = FESTATE_DISEQC;			fepriv->status = 0;		}		break;	case FE_DISEQC_RECV_SLAVE_REPLY:		if (fe->ops.diseqc_recv_slave_reply)			err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);		break;	case FE_ENABLE_HIGH_LNB_VOLTAGE:		if (fe->ops.enable_high_lnb_voltage)			err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);		break;	case FE_SET_FRONTEND: {		struct dvb_frontend_tune_settings fetunesettings;		if (dvb_frontend_check_parameters(fe, parg) < 0) {			err = -EINVAL;			break;		}		memcpy (&fepriv->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) {			fepriv->parameters.inversion = INVERSION_AUTO;			fetunesettings.parameters.inversion = INVERSION_AUTO;		}		if (fe->ops.info.type == FE_OFDM) {			/* without hierarchical coding code_rate_LP is irrelevant,			 * so we tolerate the otherwise invalid FEC_NONE setting */			if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&			    fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)				fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;		}		/* get frontend-specific tuning settings */		if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {			fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;			fepriv->max_drift = fetunesettings.max_drift;			fepriv->step_size = fetunesettings.step_size;		} else {			/* default values */			switch(fe->ops.info.type) {			case FE_QPSK:				fepriv->min_delay = HZ/20;				fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;				fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;				break;			case FE_QAM:				fepriv->min_delay = HZ/20;				fepriv->step_size = 0; /* no zigzag */				fepriv->max_drift = 0;				break;			case FE_OFDM:				fepriv->min_delay = HZ/20;				fepriv->step_size = fe->ops.info.frequency_stepsize * 2;				fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;				break;			case FE_ATSC:				fepriv->min_delay = HZ/20;				fepriv->step_size = 0;				fepriv->max_drift = 0;				break;			}		}		if (dvb_override_tune_delay > 0)			fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;		fepriv->state = FESTATE_RETUNE;		dvb_frontend_wakeup(fe);		dvb_frontend_add_event(fe, 0);		fepriv->status = 0;		err = 0;		break;	}	case FE_GET_EVENT:		err = dvb_frontend_get_event (fe, parg, file->f_flags);		break;	case FE_GET_FRONTEND:		if (fe->ops.get_frontend) {			memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));			err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);		}		break;	case FE_SET_FRONTEND_TUNE_MODE:		fepriv->tune_mode_flags = (unsigned long) parg;		err = 0;		break;	};	up (&fepriv->sem);	return err;}static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait){	struct dvb_device *dvbdev = file->private_data;	struct dvb_frontend *fe = dvbdev->priv;	struct dvb_frontend_private *fepriv = fe->frontend_priv;	dprintk ("%s\n", __FUNCTION__);	poll_wait (file, &fepriv->events.wait_queue, wait);	if (fepriv->events.eventw != fepriv->events.eventr)		return (POLLIN | POLLRDNORM | POLLPRI);	return 0;}static int dvb_frontend_open(struct inode *inode, struct file *file){	struct dvb_device *dvbdev = file->private_data;	struct dvb_frontend *fe = dvbdev->priv;	struct dvb_frontend_private *fepriv = fe->frontend_priv;	int ret;	dprintk ("%s\n", __FUNCTION__);	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {		if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)			return ret;	}	if ((ret = dvb_generic_open (inode, file)) < 0)		goto err1;	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {		/* normal tune mode when opened R/W */		fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;		fepriv->tone = -1;		fepriv->voltage = -1;		ret = dvb_frontend_start (fe);		if (ret)			goto err2;		/*  empty event queue */		fepriv->events.eventr = fepriv->events.eventw = 0;	}	return ret;err2:	dvb_generic_release(inode, file);err1:	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)		fe->ops.ts_bus_ctrl(fe, 0);	return ret;}static int dvb_frontend_release(struct inode *inode, struct file *file){	struct dvb_device *dvbdev = file->private_data;	struct dvb_frontend *fe = dvbdev->priv;	struct dvb_frontend_private *fepriv = fe->frontend_priv;	int ret;	dprintk ("%s\n", __FUNCTION__);	if ((file->f_flags & O_ACCMODE) != O_RDONLY)		fepriv->release_jiffies = jiffies;	ret = dvb_generic_release (inode, file);	if (dvbdev->users == -1) {		if (fepriv->exit == 1) {			fops_put(file->f_op);			file->f_op = NULL;			wake_up(&dvbdev->wait_queue);		}		if (fe->ops.ts_bus_ctrl)			fe->ops.ts_bus_ctrl(fe, 0);	}	return ret;}static struct file_operations dvb_frontend_fops = {	.owner		= THIS_MODULE,	.ioctl		= dvb_generic_ioctl,	.poll		= dvb_frontend_poll,	.open		= dvb_frontend_open,	.release	= dvb_frontend_release};int dvb_register_frontend(struct dvb_adapter* dvb,			  struct dvb_frontend* fe){	struct dvb_frontend_private *fepriv;	static const struct dvb_device dvbdev_template = {		.users = ~0,		.writers = 1,		.readers = (~0)-1,		.fops = &dvb_frontend_fops,		.kernel_ioctl = dvb_frontend_ioctl	};	dprintk ("%s\n", __FUNCTION__);	if (mutex_lock_interruptible(&frontend_mutex))		return -ERESTARTSYS;	fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);	if (fe->frontend_priv == NULL) {		mutex_unlock(&frontend_mutex);		return -ENOMEM;	}	fepriv = fe->frontend_priv;	init_MUTEX (&fepriv->sem);	init_waitqueue_head (&fepriv->wait_queue);	init_waitqueue_head (&fepriv->events.wait_queue);	mutex_init(&fepriv->events.mtx);	fe->dvb = dvb;	fepriv->inversion = INVERSION_OFF;	printk ("DVB: registering frontend %i (%s)...\n",		fe->dvb->num,		fe->ops.info.name);	dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,			     fe, DVB_DEVICE_FRONTEND);	mutex_unlock(&frontend_mutex);	return 0;}EXPORT_SYMBOL(dvb_register_frontend);int dvb_unregister_frontend(struct dvb_frontend* fe){	struct dvb_frontend_private *fepriv = fe->frontend_priv;	dprintk ("%s\n", __FUNCTION__);	mutex_lock(&frontend_mutex);	dvb_frontend_stop (fe);	mutex_unlock(&frontend_mutex);	if (fepriv->dvbdev->users < -1)		wait_event(fepriv->dvbdev->wait_queue,				fepriv->dvbdev->users==-1);	mutex_lock(&frontend_mutex);	dvb_unregister_device (fepriv->dvbdev);	/* fe is invalid now */	kfree(fepriv);	mutex_unlock(&frontend_mutex);	return 0;}EXPORT_SYMBOL(dvb_unregister_frontend);#ifdef CONFIG_DVB_CORE_ATTACHvoid dvb_frontend_detach(struct dvb_frontend* fe){	void *ptr;	if (fe->ops.release_sec) {		fe->ops.release_sec(fe);		symbol_put_addr(fe->ops.release_sec);	}	if (fe->ops.tuner_ops.release) {		fe->ops.tuner_ops.release(fe);		symbol_put_addr(fe->ops.tuner_ops.release);	}	ptr = (void*)fe->ops.release;	if (ptr) {		fe->ops.release(fe);		symbol_put_addr(ptr);	}}#elsevoid dvb_frontend_detach(struct dvb_frontend* fe){	if (fe->ops.release_sec)		fe->ops.release_sec(fe);	if (fe->ops.tuner_ops.release)		fe->ops.tuner_ops.release(fe);	if (fe->ops.release)		fe->ops.release(fe);}#endifEXPORT_SYMBOL(dvb_frontend_detach);

⌨️ 快捷键说明

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