diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index eefcb7f885a3..7f6ce06c7e46 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -150,6 +150,55 @@ static bool has_get_frontend(struct dvb_frontend *fe) return fe->ops.get_frontend; } +/* + * Due to DVBv3 API calls, a delivery system should be mapped into one of + * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC), + * otherwise, a DVBv3 call will fail. + */ +enum dvbv3_emulation_type { + DVBV3_UNKNOWN, + DVBV3_QPSK, + DVBV3_QAM, + DVBV3_OFDM, + DVBV3_ATSC, +}; + +static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system) +{ + switch (delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + return DVBV3_QAM; + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_ISDBS: + case SYS_DSS: + return DVBV3_QPSK; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_ISDBT: + case SYS_DMBTH: + return DVBV3_OFDM; + case SYS_ATSC: + case SYS_DVBC_ANNEX_B: + return DVBV3_ATSC; + case SYS_UNDEFINED: + case SYS_ISDBC: + case SYS_DVBH: + case SYS_DAB: + case SYS_ATSCMH: + default: + /* + * Doesn't know how to emulate those types and/or + * there's no frontend driver from this type yet + * with some emulation code, so, we're not sure yet how + * to handle them, or they're not compatible with a DVBv3 call. + */ + return DVBV3_UNKNOWN; + } +} + static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) { struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -814,52 +863,63 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, fe->dvb->num,fe->id); } -static int dvb_frontend_check_parameters(struct dvb_frontend *fe, - struct dvb_frontend_parameters *parms) +static int dvb_frontend_check_parameters(struct dvb_frontend *fe) { + struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 freq_min; u32 freq_max; /* range check: frequency */ dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max); - if ((freq_min && parms->frequency < freq_min) || - (freq_max && parms->frequency > freq_max)) { + if ((freq_min && c->frequency < freq_min) || + (freq_max && c->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); + fe->dvb->num, fe->id, c->frequency, freq_min, freq_max); return -EINVAL; } /* range check: symbol rate */ - if (fe->ops.info.type == FE_QPSK) { + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: if ((fe->ops.info.symbol_rate_min && - parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || + c->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)) { + c->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); + fe->dvb->num, fe->id, c->symbol_rate, + fe->ops.info.symbol_rate_min, + fe->ops.info.symbol_rate_max); return -EINVAL; } + default: + break; } - /* check for supported modulation */ - if (fe->ops.info.type == FE_QAM && - (parms->u.qam.modulation > QAM_AUTO || - !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) { - printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n", - fe->dvb->num, fe->id, parms->u.qam.modulation); + /* + * check for supported modulation + * + * This is currently hacky. Also, it only works for DVB-S & friends, + * and not all modulations has FE_CAN flags + */ + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + if ((c->modulation > QAM_AUTO || + !((1 << (c->modulation + 10)) & fe->ops.info.caps))) { + printk(KERN_WARNING + "DVB: adapter %i frontend %i modulation %u not supported\n", + fe->dvb->num, fe->id, c->modulation); return -EINVAL; + } + break; + default: + /* FIXME: it makes sense to validate othere delsys here */ + break; } return 0; @@ -875,6 +935,8 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) c->state = DTV_CLEAR; c->delivery_system = fe->ops.delsys[0]; + dprintk("%s() Clearing cache for delivery system %d\n", __func__, + c->delivery_system); c->transmission_mode = TRANSMISSION_MODE_AUTO; c->bandwidth_hz = 0; /* AUTO */ @@ -886,7 +948,6 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) c->fec_inner = FEC_AUTO; c->rolloff = ROLLOFF_AUTO; c->voltage = SEC_VOLTAGE_OFF; - c->modulation = QAM_AUTO; c->sectone = SEC_TONE_OFF; c->pilot = PILOT_AUTO; @@ -906,6 +967,21 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) c->isdbs_ts_id = 0; c->dvbt2_plp_id = 0; + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + c->modulation = QPSK; /* implied for DVB-S in legacy API */ + c->rolloff = ROLLOFF_35;/* implied for DVB-S */ + break; + case SYS_ATSC: + c->modulation = VSB_8; + break; + default: + c->modulation = QAM_AUTO; + break; + } + return 0; } @@ -1024,61 +1100,31 @@ static void dtv_property_dump(struct dtv_property *tvp) dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data); } -static int is_legacy_delivery_system(fe_delivery_system_t s) -{ - if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_A) || - (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || - (s == SYS_ATSC)) - return 1; - - return 0; -} - -/* Initialize the cache with some default values derived from the - * legacy frontend_info structure. - */ -static void dtv_property_cache_init(struct dvb_frontend *fe, - struct dtv_frontend_properties *c) -{ - 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->delivery_system = SYS_DVBS; - break; - case FE_QAM: - c->delivery_system = SYS_DVBC_ANNEX_A; - break; - case FE_OFDM: - c->delivery_system = SYS_DVBT; - break; - case FE_ATSC: - break; - } -} - /* 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. */ -static void dtv_property_cache_sync(struct dvb_frontend *fe, - struct dtv_frontend_properties *c, - const struct dvb_frontend_parameters *p) +static int dtv_property_cache_sync(struct dvb_frontend *fe, + struct dtv_frontend_properties *c, + const struct dvb_frontend_parameters *p) { c->frequency = p->frequency; c->inversion = p->inversion; - switch (fe->ops.info.type) { - case FE_QPSK: + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_QPSK: + dprintk("%s() Preparing QPSK req\n", __func__); c->symbol_rate = p->u.qpsk.symbol_rate; c->fec_inner = p->u.qpsk.fec_inner; break; - case FE_QAM: + case DVBV3_QAM: + dprintk("%s() Preparing QAM req\n", __func__); c->symbol_rate = p->u.qam.symbol_rate; c->fec_inner = p->u.qam.fec_inner; c->modulation = p->u.qam.modulation; break; - case FE_OFDM: + case DVBV3_OFDM: + dprintk("%s() Preparing OFDM req\n", __func__); switch (p->u.ofdm.bandwidth) { case BANDWIDTH_10_MHZ: c->bandwidth_hz = 10000000; @@ -1109,20 +1155,28 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe, c->guard_interval = p->u.ofdm.guard_interval; c->hierarchy = p->u.ofdm.hierarchy_information; break; - case FE_ATSC: + case DVBV3_ATSC: + dprintk("%s() Preparing ATSC req\n", __func__); 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; + case DVBV3_UNKNOWN: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + return -EINVAL; } + + return 0; } /* Ensure the cached values are set correctly in the frontend * legacy tuning structures, for the advanced tuning API. */ -static void dtv_property_legacy_params_sync(struct dvb_frontend *fe, +static int dtv_property_legacy_params_sync(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { const struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -1130,20 +1184,26 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe, p->frequency = c->frequency; p->inversion = c->inversion; - switch (fe->ops.info.type) { - case FE_QPSK: + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_UNKNOWN: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + return -EINVAL; + case DVBV3_QPSK: dprintk("%s() Preparing QPSK req\n", __func__); p->u.qpsk.symbol_rate = c->symbol_rate; p->u.qpsk.fec_inner = c->fec_inner; break; - case FE_QAM: + case DVBV3_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; break; - case FE_OFDM: + case DVBV3_OFDM: dprintk("%s() Preparing OFDM req\n", __func__); + switch (c->bandwidth_hz) { case 10000000: p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ; @@ -1174,116 +1234,12 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe, p->u.ofdm.guard_interval = c->guard_interval; p->u.ofdm.hierarchy_information = c->hierarchy; break; - case FE_ATSC: + case DVBV3_ATSC: dprintk("%s() Preparing VSB req\n", __func__); p->u.vsb.modulation = c->modulation; break; } -} - -/* Ensure the cached values are set correctly in the frontend - * legacy tuning structures, for the legacy tuning API. - */ -static 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_in; - u32 rolloff = 0; - - p->frequency = c->frequency; - p->inversion = c->inversion; - - if (c->delivery_system == SYS_DSS || - c->delivery_system == SYS_DVBS || - c->delivery_system == SYS_DVBS2 || - c->delivery_system == SYS_ISDBS || - c->delivery_system == SYS_TURBO) { - p->u.qpsk.symbol_rate = c->symbol_rate; - p->u.qpsk.fec_inner = c->fec_inner; - } - - /* Fake out a generic DVB-T request so we pass validation in the ioctl */ - if ((c->delivery_system == SYS_ISDBT) || - (c->delivery_system == SYS_DVBT2)) { - 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.transmission_mode = TRANSMISSION_MODE_AUTO; - p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; - p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; - if (c->bandwidth_hz == 8000000) - p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; - else if (c->bandwidth_hz == 7000000) - p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; - else if (c->bandwidth_hz == 6000000) - p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; - else - p->u.ofdm.bandwidth = BANDWIDTH_AUTO; - } - - /* - * Be sure that the bandwidth will be filled for all - * non-satellite systems, as tuners need to know what - * low pass/Nyquist half filter should be applied, in - * order to avoid inter-channel noise. - * - * ISDB-T and DVB-T/T2 already sets bandwidth. - * ATSC and DVB-C don't set, so, the core should fill it. - * - * On DVB-C Annex A and C, the bandwidth is a function of - * the roll-off and symbol rate. Annex B defines different - * roll-off factors depending on the modulation. Fortunately, - * Annex B is only used with 6MHz, so there's no need to - * calculate it. - * - * While not officially supported, a side effect of handling it at - * the cache level is that a program could retrieve the bandwidth - * via DTV_BANDWIDTH_HZ, which may be useful for test programs. - */ - switch (c->delivery_system) { - case SYS_ATSC: - case SYS_DVBC_ANNEX_B: - c->bandwidth_hz = 6000000; - break; - case SYS_DVBC_ANNEX_A: - rolloff = 115; - break; - case SYS_DVBC_ANNEX_C: - rolloff = 113; - break; - default: - break; - } - if (rolloff) - c->bandwidth_hz = (c->symbol_rate * rolloff) / 100; -} - -static void dtv_property_cache_submit(struct dvb_frontend *fe) -{ - const struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - /* 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, &fepriv->parameters_in); - - } 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); - } + return 0; } /** @@ -1319,59 +1275,21 @@ static int dvb_frontend_ioctl_legacy(struct file *file, static int dvb_frontend_ioctl_properties(struct file *file, unsigned int cmd, void *parg); -static void dtv_set_default_delivery_caps(const struct dvb_frontend *fe, struct dtv_property *p) -{ - const struct dvb_frontend_info *info = &fe->ops.info; - u32 ncaps = 0; - - /* - * If the frontend explicitly sets a list, use it, instead of - * filling based on the info->type - */ - if (fe->ops.delsys[ncaps]) { - while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { - p->u.buffer.data[ncaps] = fe->ops.delsys[ncaps]; - ncaps++; - } - p->u.buffer.len = ncaps; - return; - } - switch (info->type) { - case FE_QPSK: - p->u.buffer.data[ncaps++] = SYS_DVBS; - if (info->caps & FE_CAN_2G_MODULATION) - p->u.buffer.data[ncaps++] = SYS_DVBS2; - if (info->caps & FE_CAN_TURBO_FEC) - p->u.buffer.data[ncaps++] = SYS_TURBO; - break; - case FE_QAM: - p->u.buffer.data[ncaps++] = SYS_DVBC_ANNEX_A; - break; - case FE_OFDM: - p->u.buffer.data[ncaps++] = SYS_DVBT; - if (info->caps & FE_CAN_2G_MODULATION) - p->u.buffer.data[ncaps++] = SYS_DVBT2; - break; - case FE_ATSC: - if (info->caps & (FE_CAN_8VSB | FE_CAN_16VSB)) - p->u.buffer.data[ncaps++] = SYS_ATSC; - if (info->caps & (FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256)) - p->u.buffer.data[ncaps++] = SYS_DVBC_ANNEX_B; - break; - } - p->u.buffer.len = ncaps; -} - static int dtv_property_process_get(struct dvb_frontend *fe, const struct dtv_frontend_properties *c, struct dtv_property *tvp, struct file *file) { - int r; + int r, ncaps; switch(tvp->cmd) { case DTV_ENUM_DELSYS: - dtv_set_default_delivery_caps(fe, tvp); + ncaps = 0; + while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { + tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps]; + ncaps++; + } + tvp->u.buffer.len = ncaps; break; case DTV_FREQUENCY: tvp->u.data = c->frequency; @@ -1502,6 +1420,8 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return 0; } +static int dtv_set_frontend(struct dvb_frontend *fe); + static int dtv_property_process_set(struct dvb_frontend *fe, struct dtv_property *tvp, struct file *file) @@ -1520,11 +1440,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe, switch(tvp->cmd) { case DTV_CLEAR: - /* Reset a cache of data specific to the frontend here. This does + /* + * Reset a cache of data specific to the frontend here. This does * not effect hardware. */ dvb_frontend_clear_cache(fe); - dprintk("%s() Flushing property cache\n", __func__); break; case DTV_TUNE: /* interpret the cache of data, build either a traditional frontend @@ -1533,10 +1453,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe, */ c->state = tvp->cmd; dprintk("%s() Finalised property cache\n", __func__); - dtv_property_cache_submit(fe); - r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND, - &fepriv->parameters_in); + /* Needed, due to status update */ + dtv_property_legacy_params_sync(fe, &fepriv->parameters_in); + + r = dtv_set_frontend(fe); break; case DTV_FREQUENCY: c->frequency = tvp->u.data; @@ -1786,76 +1707,102 @@ static int dvb_frontend_ioctl_properties(struct file *file, return err; } -static int dtv_set_frontend(struct file *file, unsigned int cmd, void *parg) +static int dtv_set_frontend(struct dvb_frontend *fe) { - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_tune_settings fetunesettings; + u32 rolloff = 0; - if (c->state == DTV_TUNE) { - if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) - return -EINVAL; - } else { - if (dvb_frontend_check_parameters(fe, parg) < 0) - return -EINVAL; - - memcpy (&fepriv->parameters_in, parg, - sizeof (struct dvb_frontend_parameters)); - dtv_property_cache_init(fe, c); - dtv_property_cache_sync(fe, c, &fepriv->parameters_in); - } + if (dvb_frontend_check_parameters(fe) < 0) + return -EINVAL; /* - * Initialize output parameters to match the values given by - * the user. FE_SET_FRONTEND triggers an initial frontend event - * with status = 0, which copies output parameters to userspace. - */ + * Initialize output parameters to match the values given by + * the user. FE_SET_FRONTEND triggers an initial frontend event + * with status = 0, which copies output parameters to userspace. + * + * This is still needed for DVBv5 calls, due to event state update. + */ fepriv->parameters_out = fepriv->parameters_in; - memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); + /* + * Be sure that the bandwidth will be filled for all + * non-satellite systems, as tuners need to know what + * low pass/Nyquist half filter should be applied, in + * order to avoid inter-channel noise. + * + * ISDB-T and DVB-T/T2 already sets bandwidth. + * ATSC and DVB-C don't set, so, the core should fill it. + * + * On DVB-C Annex A and C, the bandwidth is a function of + * the roll-off and symbol rate. Annex B defines different + * roll-off factors depending on the modulation. Fortunately, + * Annex B is only used with 6MHz, so there's no need to + * calculate it. + * + * While not officially supported, a side effect of handling it at + * the cache level is that a program could retrieve the bandwidth + * via DTV_BANDWIDTH_HZ, which may be useful for test programs. + */ + switch (c->delivery_system) { + case SYS_ATSC: + case SYS_DVBC_ANNEX_B: + c->bandwidth_hz = 6000000; + break; + case SYS_DVBC_ANNEX_A: + rolloff = 115; + break; + case SYS_DVBC_ANNEX_C: + rolloff = 113; + break; + default: + break; + } + if (rolloff) + c->bandwidth_hz = (c->symbol_rate * rolloff) / 100; /* force auto frequency inversion if requested */ - if (dvb_force_auto_inversion) { + if (dvb_force_auto_inversion) c->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 (c->hierarchy == HIERARCHY_NONE && - c->code_rate_LP == FEC_NONE) - c->code_rate_LP = FEC_AUTO; - } + + /* + * without hierarchical coding code_rate_LP is irrelevant, + * so we tolerate the otherwise invalid FEC_NONE setting + */ + if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE) + c->code_rate_LP = FEC_AUTO; /* get frontend-specific tuning settings */ + memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_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; + switch (c->delivery_system) { + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + fepriv->min_delay = HZ / 20; fepriv->step_size = c->symbol_rate / 16000; fepriv->max_drift = c->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; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_ISDBT: + case SYS_DMBTH: + 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; + default: + /* + * FIXME: This sounds wrong! if freqency_stepsize is + * defined by the frontend, why not use it??? + */ + fepriv->min_delay = HZ / 20; + fepriv->step_size = 0; /* no zigzag */ fepriv->max_drift = 0; break; } @@ -1883,6 +1830,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int cb_err, err = -EOPNOTSUPP; if (fe->dvb->fe_ioctl_override) { @@ -1902,6 +1850,37 @@ static int dvb_frontend_ioctl_legacy(struct file *file, memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); + /* + * Associate the 4 delivery systems supported by DVBv3 + * API with their DVBv5 counterpart. For the other standards, + * use the closest type, assuming that it would hopefully + * work with a DVBv3 application. + * It should be noticed that, on multi-frontend devices with + * different types (terrestrial and cable, for example), + * a pure DVBv3 application won't be able to use all delivery + * systems. Yet, changing the DVBv5 cache to the other delivery + * system should be enough for making it work. + */ + switch (dvbv3_type(c->delivery_system)) { + case DVBV3_QPSK: + fe->ops.info.type = FE_QPSK; + break; + case DVBV3_ATSC: + fe->ops.info.type = FE_ATSC; + break; + case DVBV3_QAM: + fe->ops.info.type = FE_QAM; + break; + case DVBV3_OFDM: + fe->ops.info.type = FE_OFDM; + break; + default: + printk(KERN_ERR + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + fe->ops.info.type = FE_OFDM; + } + /* 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; @@ -2061,7 +2040,13 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; case FE_SET_FRONTEND: - err = dtv_set_frontend(file, cmd, parg); + /* Synchronise DVBv5 parameters from DVBv3 */ + memcpy (&fepriv->parameters_in, parg, + sizeof (struct dvb_frontend_parameters)); + err = dtv_property_cache_sync(fe, c, &fepriv->parameters_in); + if (err) + break; + err = dtv_set_frontend(fe); break; case FE_GET_EVENT: err = dvb_frontend_get_event (fe, parg, file->f_flags); @@ -2281,6 +2266,12 @@ int dvb_register_frontend(struct dvb_adapter* dvb, dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND); + /* + * Initialize the cache to the proper values according with the + * first supported delivery system (ops->delsys[0]) + */ + dvb_frontend_clear_cache(fe); + mutex_unlock(&frontend_mutex); return 0; }