static int dtv_set_frontend(struct dvb_frontend *fe);
+static bool is_dvbv3_delsys(u32 delsys)
+{
+ bool status;
+
+ status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
+ (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
+
+ return status;
+}
+
+static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
+{
+ int ncaps, i;
+ u32 delsys = SYS_UNDEFINED;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ enum dvbv3_emulation_type type;
+
+ if (desired_system == SYS_UNDEFINED) {
+ /*
+ * A DVBv3 call doesn't know what's the desired system.
+ * So, don't change the current delivery system. Instead,
+ * find the closest DVBv3 system that matches the delivery
+ * system.
+ */
+ if (is_dvbv3_delsys(c->delivery_system)) {
+ dprintk("%s() Using delivery system to %d\n",
+ __func__, c->delivery_system);
+ return 0;
+ }
+ type = dvbv3_type(c->delivery_system);
+ switch (type) {
+ case DVBV3_QPSK:
+ desired_system = FE_QPSK;
+ break;
+ case DVBV3_QAM:
+ desired_system = FE_QAM;
+ break;
+ case DVBV3_ATSC:
+ desired_system = FE_ATSC;
+ break;
+ case DVBV3_OFDM:
+ desired_system = FE_OFDM;
+ break;
+ default:
+ dprintk("%s(): This frontend doesn't support DVBv3 calls\n",
+ __func__);
+ return -EINVAL;
+ }
+ delsys = c->delivery_system;
+ } else {
+ /*
+ * Check if the desired delivery system is supported
+ */
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ if (fe->ops.delsys[ncaps] == desired_system) {
+ c->delivery_system = desired_system;
+ dprintk("%s() Changing delivery system to %d\n",
+ __func__, desired_system);
+ return 0;
+ }
+ }
+ type = dvbv3_type(desired_system);
+
+ /*
+ * The delivery system is not supported. See if it can be
+ * emulated.
+ * The emulation only works if the desired system is one of the
+ * DVBv3 delivery systems
+ */
+ if (!is_dvbv3_delsys(desired_system)) {
+ dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Get the last non-DVBv3 delivery system that has the same type
+ * of the desired system
+ */
+ ncaps = 0;
+ while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+ if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
+ !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
+ delsys = fe->ops.delsys[ncaps];
+ ncaps++;
+ }
+ /* There's nothing compatible with the desired delivery system */
+ if (delsys == SYS_UNDEFINED) {
+ dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
+ __func__);
+ return -EINVAL;
+ }
+ c->delivery_system = delsys;
+ }
+
+ /*
+ * Emulate newer delivery systems like ISDBT, DVBT and DMBTH
+ * for older DVBv5 applications. The emulation will try to use
+ * the auto mode for most things, and will assume that the desired
+ * delivery system is the last one at the ops.delsys[] array
+ */
+ dprintk("%s() Using delivery system %d emulated as if it were a %d\n",
+ __func__, delsys, desired_system);
+
+ /*
+ * For now, uses it for ISDB-T, DMBTH and DVB-T2
+ * For DVB-S2 and DVB-TURBO, assumes that the DVB-S parameters are enough.
+ */
+ if (type == DVBV3_OFDM) {
+ c->modulation = QAM_AUTO;
+ c->code_rate_HP = FEC_AUTO;
+ c->code_rate_LP = FEC_AUTO;
+ c->transmission_mode = TRANSMISSION_MODE_AUTO;
+ c->guard_interval = GUARD_INTERVAL_AUTO;
+ c->hierarchy = HIERARCHY_AUTO;
+
+ c->isdbt_partial_reception = -1;
+ c->isdbt_sb_mode = -1;
+ c->isdbt_sb_subchannel = -1;
+ c->isdbt_sb_segment_idx = -1;
+ c->isdbt_sb_segment_count = -1;
+ c->isdbt_layer_enabled = 0x7;
+ for (i = 0; i < 3; i++) {
+ c->layer[i].fec = FEC_AUTO;
+ c->layer[i].modulation = QAM_AUTO;
+ c->layer[i].interleaving = -1;
+ c->layer[i].segment_count = -1;
+ }
+ }
+ return 0;
+}
+
static int dtv_property_process_set(struct dvb_frontend *fe,
struct dtv_property *tvp,
struct file *file)
c->rolloff = tvp->u.data;
break;
case DTV_DELIVERY_SYSTEM:
- c->delivery_system = tvp->u.data;
+ r = set_delivery_system(fe, tvp->u.data);
break;
case DTV_VOLTAGE:
c->voltage = tvp->u.data;
/* Synchronise DVBv5 parameters from DVBv3 */
memcpy (&fepriv->parameters_in, parg,
sizeof (struct dvb_frontend_parameters));
+
+ err = set_delivery_system(fe, SYS_UNDEFINED);
+ if (err)
+ break;
+
err = dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
if (err)
break;