Ejemplo n.º 1
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;
	int err = -EOPNOTSUPP;

	dprintk ("%s\n", __FUNCTION__);

	if (!fe || fe->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 (&fe->sem))
		return -ERESTARTSYS;

	switch (cmd) {
	case FE_GET_INFO: {
		struct dvb_frontend_info* info = (struct dvb_frontend_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. */
		info->caps |= FE_CAN_INVERSION_AUTO;
		err = 0;
		break;
	}

	case FE_READ_STATUS:
		if (fe->ops->read_status)
			err = fe->ops->read_status(fe, (fe_status_t*) parg);
		break;

	case FE_READ_BER:
		if (fe->ops->read_ber)
			err = fe->ops->read_ber(fe, (__u32*) parg);
		break;

	case FE_READ_SIGNAL_STRENGTH:
		if (fe->ops->read_signal_strength)
			err = fe->ops->read_signal_strength(fe, (__u16*) parg);
		break;

	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);
			fe->state = FESTATE_DISEQC;
			fe->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);
			fe->state = FESTATE_DISEQC;
			fe->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);
			fe->state = FESTATE_DISEQC;
			fe->status = 0;
		}
		break;

	case FE_SET_TONE:
		if (fe->ops->set_tone) {
			err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
			fe->state = FESTATE_DISEQC;
			fe->status = 0;
		}
		break;

	case FE_SET_VOLTAGE:
		if (fe->ops->set_voltage) {
			err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
		fe->state = FESTATE_DISEQC;
			fe->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 int) parg);
			fe->state = FESTATE_DISEQC;
			fe->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, (int) parg);
		break;

	case FE_SET_FRONTEND: {
		struct dvb_frontend_tune_settings fetunesettings;
	    
		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;
		}
		if (fe->ops->info.type == FE_OFDM) {
			/* without hierachical coding code_rate_LP is irrelevant,
			 * so we tolerate the otherwise invalid FEC_NONE setting */
			if (fe->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
			    fe->parameters.u.ofdm.code_rate_LP == FEC_NONE)
				fe->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)) {
			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->ops->info.type) {
			case FE_QPSK:
				fe->min_delay = HZ/20;
				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;
				fe->step_size = 0; /* no zigzag */
				fe->max_drift = 0;
				break;
			    
			case FE_OFDM:
				fe->min_delay = HZ/20;
				fe->step_size = fe->ops->info.frequency_stepsize * 2;
				fe->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
				break;
			case FE_ATSC:
				printk("dvb-core: FE_ATSC not handled yet.\n");
				break;
			}
		}
		if (dvb_override_tune_delay > 0)
		       fe->min_delay = (dvb_override_tune_delay * HZ) / 1000;

		fe->state = FESTATE_RETUNE;
		dvb_frontend_wakeup(fe);
		dvb_frontend_add_event (fe, 0);	    
		fe->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, &fe->parameters, sizeof (struct dvb_frontend_parameters));
			err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
		}
		break;
	};

	up (&fe->sem);
	return err;
}
Ejemplo n.º 2
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. */
		info->caps |= FE_CAN_INVERSION_AUTO;
		err = 0;
		break;
	}

	case FE_READ_STATUS: {
		fe_status_t* status = parg;

		/* if retune was requested but hasn't occured yet, prevent
		 * that user get signal state from previous tuning */
		if(fepriv->state == FESTATE_RETUNE) {
			err=0;
			*status = 0;
			break;
		}

		if (fe->ops.read_status)
			err = fe->ops.read_status(fe, status);
		break;
	}
	case FE_READ_BER:
		if (fe->ops.read_ber)
			err = fe->ops.read_ber(fe, (__u32*) parg);
		break;

	case FE_READ_SIGNAL_STRENGTH:
		if (fe->ops.read_signal_strength)
			err = fe->ops.read_signal_strength(fe, (__u16*) parg);
		break;

	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;

		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 hierachical 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;
	};
Ejemplo n.º 3
0
static int
frontend_ioctl(struct dvb_device *dvbdev, struct file *file,
               unsigned int cmd, unsigned long arg)
{
	struct dvb_struct *dvb=(struct dvb_struct *) dvbdev->priv;
	void *parg=(void *)arg;

	switch (cmd) {
	case FE_SELFTEST:
		break;

	case FE_SET_POWER_STATE:
		switch (arg) {
		case FE_POWER_ON:
			dvb->powerstate=arg;
			break;
		case FE_POWER_SUSPEND:
		case FE_POWER_STANDBY:
		case FE_POWER_OFF:
			dvb->powerstate=FE_POWER_OFF;
			break;
		default:
			return -EINVAL;
		}
		dvb_frontend_demod_command(dvb->frontend, FE_SET_POWER_STATE, &arg);
		break;

	case FE_GET_POWER_STATE:
		if(copy_to_user(parg, &dvb->powerstate, sizeof(u32)))
			return -EFAULT;
		break;

	case FE_READ_STATUS:
	{
		FrontendStatus stat=0;

		dvb_frontend_demod_command(dvb->frontend, FE_READ_STATUS, &stat);
		if (dvb->sec.power)
			stat|=FE_HAS_POWER;
		if(copy_to_user(parg, &stat, sizeof(stat)))
			return -EFAULT;
		break;
	}

	case FE_READ_BER:
	{
		uint32_t ber;
		
		if (!dvb->sec.power)
			return -ENOSIGNAL;
		dvb_frontend_demod_command(dvb->frontend, FE_READ_BER, &ber);
		if(copy_to_user(parg, &ber, sizeof(ber)))
			return -EFAULT;
		break;
	}

	case FE_READ_SIGNAL_STRENGTH:
	{
		int32_t signal;
		
		if (!dvb->sec.power)
			return -ENOSIGNAL;
		dvb_frontend_demod_command(dvb->frontend, FE_READ_SIGNAL_STRENGTH, &signal);
		if(copy_to_user(parg, &signal, sizeof(signal)))
			return -EFAULT;
		break;
	}

	case FE_READ_SNR:
	{
		int32_t snr;
		
		if (!dvb->sec.power)
			return -ENOSIGNAL;
		dvb_frontend_demod_command(dvb->frontend, FE_READ_SNR, &snr);
		if(copy_to_user(parg, &snr, sizeof(snr)))
			return -EFAULT;
		break;
	}

	case FE_READ_UNCORRECTED_BLOCKS:
	{
		u32 ublocks;

		if (!dvb->sec.power)
			return -ENOSIGNAL;
		if (dvb_frontend_demod_command(dvb->frontend, FE_READ_UNCORRECTED_BLOCKS,
					&ublocks) < 0)
			return -ENOSYS;
		if(copy_to_user(parg, &ublocks, sizeof(ublocks)))
			return -EFAULT;
		break;
	}

	case FE_GET_NEXT_FREQUENCY:
	{
		uint32_t freq;

		if (copy_from_user(&freq, parg, sizeof(freq)))
			return -EFAULT;
		
		if (dvb->frontend->type==DVB_S)
			// FIXME: how does one calculate this?
			freq+=1000; //FIXME: KHz like in QPSK_TUNE??
		else
			freq+=1000000;

		if (copy_to_user(parg, &freq, sizeof(freq)))
			return -EFAULT;
		break;
	}

	case FE_GET_NEXT_SYMBOL_RATE:
	{
		uint32_t rate;

		if(copy_from_user(&rate, parg, sizeof(rate)))
			return -EFAULT;

		if (dvb->frontend->type==DVB_C) {
			if (rate < 1725000)
				rate = 1725000;
			else if (rate < 3450000)
				rate = 3450000;
			else if (rate < 5175000)
				rate = 5175000;
			else if (rate < 5500000)
				rate = 5500000;
			else if (rate < 6875000)
				rate = 6875000;
			else if (rate < 6900000)
				rate = 6900000;
			else
				return -EINVAL;
		}
		// FIXME: how does one really calculate this?
		else if (rate<5000000)
			rate+=500000;
		else if(rate<10000000)
			rate+=1000000;
		else if(rate<30000000)
			rate+=2000000;
		else
			return -EINVAL;

		if (copy_to_user(parg, &rate, sizeof(rate)))
			return -EFAULT;
		break;
	}

	case FE_GET_FRONTEND:
		if(copy_to_user(parg, &dvb->frontend->param,
				sizeof(FrontendParameters)))
			return -EFAULT;
		break;

	case FE_SET_FRONTEND:
	{
		FrontendParameters para;

		if ((file->f_flags&O_ACCMODE)==O_RDONLY)
			return -EPERM;
		if(copy_from_user(&para, parg, sizeof(para)))
			return -EFAULT;

		return dvb_frontend_tune(dvb->frontend, &para);
	}

	case FE_GET_EVENT:
	{
		FrontendEvent event;
		int ret;
		
		ret=dvb_frontend_get_event(dvb->frontend, &event,
					   file->f_flags&O_NONBLOCK);
		if (ret<0)
			return ret;
		if(copy_to_user(parg, &event, sizeof(event)))
			return -EFAULT;
		break;
	}

	case FE_GET_INFO:
		return dvb_frontend_demod_command(dvb->frontend, FE_GET_INFO, parg);

	default:
		return -ENOIOCTLCMD;
	}
	return 0;
}