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; }
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; };
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(¶, parg, sizeof(para))) return -EFAULT; return dvb_frontend_tune(dvb->frontend, ¶); } 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; }