提交 52dee392 编写于 作者: M Mauro Carvalho Chehab

[media] dvb_frontend: Simplify the emulation logic

The current logic was broken and too complex; while it works
fine for DVB-S2/DVB-S, it is broken for ISDB-T.
Make the logic simpler, fixes it for ISDB-T and make it clearer.
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 be431b16
...@@ -1509,9 +1509,17 @@ static bool is_dvbv3_delsys(u32 delsys) ...@@ -1509,9 +1509,17 @@ static bool is_dvbv3_delsys(u32 delsys)
return status; return status;
} }
static int emulate_delivery_system(struct dvb_frontend *fe, /**
enum dvbv3_emulation_type type, * emulate_delivery_system - emulate a DVBv5 delivery system with a DVBv3 type
u32 delsys, u32 desired_system) * @fe: struct frontend;
* @delsys: DVBv5 type that will be used for emulation
*
* Provides emulation for delivery systems that are compatible with the old
* DVBv3 call. Among its usages, it provices support for ISDB-T, and allows
* using a DVB-S2 only frontend just like it were a DVB-S, if the frontent
* parameters are compatible with DVB-S spec.
*/
static int emulate_delivery_system(struct dvb_frontend *fe, u32 delsys)
{ {
int i; int i;
struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dtv_frontend_properties *c = &fe->dtv_property_cache;
...@@ -1519,51 +1527,52 @@ static int emulate_delivery_system(struct dvb_frontend *fe, ...@@ -1519,51 +1527,52 @@ static int emulate_delivery_system(struct dvb_frontend *fe,
c->delivery_system = delsys; c->delivery_system = delsys;
/* /*
* The DVBv3 or DVBv5 call is requesting a different system. So, * If the call is for ISDB-T, put it into full-seg, auto mode, TV
* emulation is needed.
*
* Emulate newer delivery systems like ISDBT, DVBT and DTMB
* 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
*/ */
dev_dbg(fe->dvb->device, if (c->delivery_system == SYS_ISDBT) {
"%s: Using delivery system %d emulated as if it were a %d\n", dev_dbg(fe->dvb->device,
__func__, delsys, desired_system); "%s: Using defaults for SYS_ISDBT\n",
__func__);
/* if (!c->bandwidth_hz)
* For now, handles ISDB-T calls. More code may be needed here for the c->bandwidth_hz = 6000000;
* other emulated stuff
*/ c->isdbt_partial_reception = 0;
if (type == DVBV3_OFDM) { c->isdbt_sb_mode = 0;
if (c->delivery_system == SYS_ISDBT) { c->isdbt_sb_subchannel = 0;
dev_dbg(fe->dvb->device, c->isdbt_sb_segment_idx = 0;
"%s: Using defaults for SYS_ISDBT\n", c->isdbt_sb_segment_count = 0;
__func__); c->isdbt_layer_enabled = 7;
for (i = 0; i < 3; i++) {
if (!c->bandwidth_hz) c->layer[i].fec = FEC_AUTO;
c->bandwidth_hz = 6000000; c->layer[i].modulation = QAM_AUTO;
c->layer[i].interleaving = 0;
c->isdbt_partial_reception = 0; c->layer[i].segment_count = 0;
c->isdbt_sb_mode = 0;
c->isdbt_sb_subchannel = 0;
c->isdbt_sb_segment_idx = 0;
c->isdbt_sb_segment_count = 0;
c->isdbt_layer_enabled = 0;
for (i = 0; i < 3; i++) {
c->layer[i].fec = FEC_AUTO;
c->layer[i].modulation = QAM_AUTO;
c->layer[i].interleaving = 0;
c->layer[i].segment_count = 0;
}
} }
} }
dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n", dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n",
__func__, c->delivery_system); __func__, c->delivery_system);
return 0; return 0;
} }
/**
* dvbv5_set_delivery_system - Sets the delivery system for a DVBv5 API call
* @fe: frontend struct
* @desired_system: delivery system requested by the user
*
* A DVBv5 call know what's the desired system it wants. So, set it.
*
* There are, however, a few known issues with early DVBv5 applications that
* are also handled by this logic:
*
* 1) Some early apps use SYS_UNDEFINED as the desired delivery system.
* This is an API violation, but, as we don't want to break userspace,
* convert it to the first supported delivery system.
* 2) Some apps might be using a DVBv5 call in a wrong way, passing, for
* example, SYS_DVBT instead of SYS_ISDBT. This is because early usage of
* ISDB-T provided backward compat with DVB-T.
*/
static int dvbv5_set_delivery_system(struct dvb_frontend *fe, static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
u32 desired_system) u32 desired_system)
{ {
...@@ -1578,15 +1587,14 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, ...@@ -1578,15 +1587,14 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
* assume that the application wants to use the first supported * assume that the application wants to use the first supported
* delivery system. * delivery system.
*/ */
if (c->delivery_system == SYS_UNDEFINED) if (desired_system == SYS_UNDEFINED)
c->delivery_system = fe->ops.delsys[0]; desired_system = fe->ops.delsys[0];
/* /*
* This is a DVBv5 call. So, it likely knows the supported * This is a DVBv5 call. So, it likely knows the supported
* delivery systems. * delivery systems. So, check if the desired delivery system is
*/ * supported
*/
/* Check if the desired delivery system is supported */
ncaps = 0; ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
if (fe->ops.delsys[ncaps] == desired_system) { if (fe->ops.delsys[ncaps] == desired_system) {
...@@ -1600,69 +1608,85 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, ...@@ -1600,69 +1608,85 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
} }
/* /*
* Need to emulate a delivery system * The requested delivery system isn't supported. Maybe userspace
* is requesting a DVBv3 compatible delivery system.
*
* The emulation only works if the desired system is one of the
* delivery systems supported by DVBv3 API
*/ */
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)) { if (!is_dvbv3_delsys(desired_system)) {
dev_dbg(fe->dvb->device, dev_dbg(fe->dvb->device,
"%s: can't use a DVBv3 FE_SET_FRONTEND call for this frontend\n", "%s: Delivery system %d not supported.\n",
__func__); __func__, desired_system);
return -EINVAL; return -EINVAL;
} }
type = dvbv3_type(desired_system);
/* /*
* Get the last non-DVBv3 delivery system that has the same type * Get the last non-DVBv3 delivery system that has the same type
* of the desired system * of the desired system
*/ */
ncaps = 0; ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) && if (dvbv3_type(fe->ops.delsys[ncaps]) == type)
!is_dvbv3_delsys(fe->ops.delsys[ncaps]))
delsys = fe->ops.delsys[ncaps]; delsys = fe->ops.delsys[ncaps];
ncaps++; ncaps++;
} }
/* There's nothing compatible with the desired delivery system */ /* There's nothing compatible with the desired delivery system */
if (delsys == SYS_UNDEFINED) { if (delsys == SYS_UNDEFINED) {
dev_dbg(fe->dvb->device, dev_dbg(fe->dvb->device,
"%s: Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n", "%s: Delivery system %d not supported on emulation mode.\n",
__func__); __func__, desired_system);
return -EINVAL; return -EINVAL;
} }
return emulate_delivery_system(fe, type, delsys, desired_system); dev_dbg(fe->dvb->device,
"%s: Using delivery system %d emulated as if it were %d\n",
__func__, delsys, desired_system);
return emulate_delivery_system(fe, desired_system);
} }
/**
* dvbv3_set_delivery_system - Sets the delivery system for a DVBv3 API call
* @fe: frontend struct
*
* A DVBv3 call doesn't know what's the desired system it wants. It also
* doesn't allow to switch between different types. Due to that, userspace
* should use DVBv5 instead.
* However, in order to avoid breaking userspace API, limited backward
* compatibility support is provided.
*
* There are some delivery systems that are incompatible with DVBv3 calls.
*
* This routine should work fine for frontends that support just one delivery
* system.
*
* For frontends that support multiple frontends:
* 1) It defaults to use the first supported delivery system. There's an
* userspace application that allows changing it at runtime;
*
* 2) If the current delivery system is not compatible with DVBv3, it gets
* the first one that it is compatible.
*
* NOTE: in order for this to work with applications like Kaffeine that
* uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
* DVB-S, drivers that support both DVB-S and DVB-S2 should have the
* SYS_DVBS entry before the SYS_DVBS2, otherwise it won't switch back
* to DVB-S.
*/
static int dvbv3_set_delivery_system(struct dvb_frontend *fe) static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
{ {
int ncaps; int ncaps;
u32 desired_system;
u32 delsys = SYS_UNDEFINED; u32 delsys = SYS_UNDEFINED;
struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dtv_frontend_properties *c = &fe->dtv_property_cache;
enum dvbv3_emulation_type type;
/* If not set yet, defaults to the first supported delivery system */ /* If not set yet, defaults to the first supported delivery system */
if (c->delivery_system == SYS_UNDEFINED) if (c->delivery_system == SYS_UNDEFINED)
c->delivery_system = fe->ops.delsys[0]; c->delivery_system = fe->ops.delsys[0];
/*
* A DVBv3 call doesn't know what's the desired system.
* Also, DVBv3 applications don't know that ops.info->type
* could be changed, and they simply don't tune when it doesn't
* match.
* So, don't change the current delivery system, as it
* may be trying to do the wrong thing, like setting an
* ISDB-T frontend as DVB-T. Instead, find the closest
* DVBv3 system that matches the delivery system.
*/
/* /*
* Trivial case: just use the current one, if it already a DVBv3 * Trivial case: just use the current one, if it already a DVBv3
* delivery system * delivery system
...@@ -1674,50 +1698,25 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) ...@@ -1674,50 +1698,25 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
return 0; return 0;
} }
/* Convert from DVBv3 into DVBv5 namespace */
type = dvbv3_type(c->delivery_system);
switch (type) {
case DVBV3_QPSK:
desired_system = SYS_DVBS;
break;
case DVBV3_QAM:
desired_system = SYS_DVBC_ANNEX_A;
break;
case DVBV3_ATSC:
desired_system = SYS_ATSC;
break;
case DVBV3_OFDM:
desired_system = SYS_DVBT;
break;
default:
dev_dbg(fe->dvb->device, "%s: This frontend doesn't support DVBv3 calls\n",
__func__);
return -EINVAL;
}
/* /*
* Get a delivery system that is compatible with DVBv3 * Seek for the first delivery system that it is compatible with a
* NOTE: in order for this to work with softwares like Kaffeine that * DVBv3 standard
* uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
* DVB-S, drivers that support both should put the SYS_DVBS entry
* before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
* The real fix is that userspace applications should not use DVBv3
* and not trust on calling FE_SET_FRONTEND to switch the delivery
* system.
*/ */
ncaps = 0; ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) { while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
if (fe->ops.delsys[ncaps] == desired_system) { if (dvbv3_type(fe->ops.delsys[ncaps]) != DVBV3_UNKNOWN) {
delsys = desired_system; delsys = fe->ops.delsys[ncaps];
break; break;
} }
ncaps++; ncaps++;
} }
if (delsys == SYS_UNDEFINED) { if (delsys == SYS_UNDEFINED) {
dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n", dev_dbg(fe->dvb->device,
__func__, desired_system); "%s: Couldn't find a delivery system that works with FE_SET_FRONTEND\n",
__func__);
return -EINVAL;
} }
return emulate_delivery_system(fe, type, delsys, desired_system); return emulate_delivery_system(fe, delsys);
} }
static int dtv_property_process_set(struct dvb_frontend *fe, static int dtv_property_process_set(struct dvb_frontend *fe,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册