Commit be431b16 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

[media] dvb-frontend: split set_delivery_system()

This function is complex, and has different workflows, one for
DVBv3 calls, and another one for DVBv5 calls. Break it into 3
functions, in order to make easier to understand what each
block does.
No functional changes so far. A few comments got improved.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 7f6301d1
...@@ -1509,9 +1509,65 @@ static bool is_dvbv3_delsys(u32 delsys) ...@@ -1509,9 +1509,65 @@ static bool is_dvbv3_delsys(u32 delsys)
return status; return status;
} }
static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) static int emulate_delivery_system(struct dvb_frontend *fe,
enum dvbv3_emulation_type type,
u32 delsys, u32 desired_system)
{ {
int ncaps, i; int i;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
c->delivery_system = delsys;
/*
* The DVBv3 or DVBv5 call is requesting a different system. So,
* 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,
"%s: Using delivery system %d emulated as if it were a %d\n",
__func__, delsys, desired_system);
/*
* For now, handles ISDB-T calls. More code may be needed here for the
* other emulated stuff
*/
if (type == DVBV3_OFDM) {
if (c->delivery_system == SYS_ISDBT) {
dev_dbg(fe->dvb->device,
"%s: Using defaults for SYS_ISDBT\n",
__func__);
if (!c->bandwidth_hz)
c->bandwidth_hz = 6000000;
c->isdbt_partial_reception = 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",
__func__, c->delivery_system);
return 0;
}
static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
u32 desired_system)
{
int ncaps;
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; enum dvbv3_emulation_type type;
...@@ -1525,65 +1581,6 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) ...@@ -1525,65 +1581,6 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_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];
if (desired_system == SYS_UNDEFINED) {
/*
* 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 dies 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.
*/
if (is_dvbv3_delsys(c->delivery_system)) {
dev_dbg(fe->dvb->device,
"%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 = 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
* NOTE: in order for this to work with softwares like Kaffeine that
* 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;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
if (fe->ops.delsys[ncaps] == desired_system) {
delsys = desired_system;
break;
}
ncaps++;
}
if (delsys == SYS_UNDEFINED) {
dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n",
__func__, desired_system);
}
} else {
/* /*
* 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.
...@@ -1601,6 +1598,11 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) ...@@ -1601,6 +1598,11 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
} }
ncaps++; ncaps++;
} }
/*
* Need to emulate a delivery system
*/
type = dvbv3_type(desired_system); type = dvbv3_type(desired_system);
/* /*
...@@ -1611,7 +1613,7 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) ...@@ -1611,7 +1613,7 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
*/ */
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 on this frontend\n", "%s: can't use a DVBv3 FE_SET_FRONTEND call for this frontend\n",
__func__); __func__);
return -EINVAL; return -EINVAL;
} }
...@@ -1634,54 +1636,88 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system) ...@@ -1634,54 +1636,88 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
__func__); __func__);
return -EINVAL; return -EINVAL;
} }
}
c->delivery_system = delsys; return emulate_delivery_system(fe, type, delsys, desired_system);
}
static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
{
int ncaps;
u32 desired_system;
u32 delsys = SYS_UNDEFINED;
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 (c->delivery_system == SYS_UNDEFINED)
c->delivery_system = fe->ops.delsys[0];
/* /*
* The DVBv3 or DVBv5 call is requesting a different system. So, * A DVBv3 call doesn't know what's the desired system.
* emulation is needed. * Also, DVBv3 applications don't know that ops.info->type
* * could be changed, and they simply don't tune when it doesn't
* Emulate newer delivery systems like ISDBT, DVBT and DTMB * match.
* for older DVBv5 applications. The emulation will try to use * So, don't change the current delivery system, as it
* the auto mode for most things, and will assume that the desired * may be trying to do the wrong thing, like setting an
* delivery system is the last one at the ops.delsys[] array * ISDB-T frontend as DVB-T. Instead, find the closest
* DVBv3 system that matches the delivery system.
*/ */
dev_dbg(fe->dvb->device,
"%s: Using delivery system %d emulated as if it were a %d\n",
__func__, delsys, desired_system);
/* /*
* For now, handles ISDB-T calls. More code may be needed here for the * Trivial case: just use the current one, if it already a DVBv3
* other emulated stuff * delivery system
*/ */
if (type == DVBV3_OFDM) { if (is_dvbv3_delsys(c->delivery_system)) {
if (c->delivery_system == SYS_ISDBT) {
dev_dbg(fe->dvb->device, dev_dbg(fe->dvb->device,
"%s: Using defaults for SYS_ISDBT\n", "%s: Using delivery system to %d\n",
__func__); __func__, c->delivery_system);
return 0;
}
if (!c->bandwidth_hz) /* Convert from DVBv3 into DVBv5 namespace */
c->bandwidth_hz = 6000000; 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;
}
c->isdbt_partial_reception = 0; /*
c->isdbt_sb_mode = 0; * Get a delivery system that is compatible with DVBv3
c->isdbt_sb_subchannel = 0; * NOTE: in order for this to work with softwares like Kaffeine that
c->isdbt_sb_segment_idx = 0; * uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
c->isdbt_sb_segment_count = 0; * DVB-S, drivers that support both should put the SYS_DVBS entry
c->isdbt_layer_enabled = 0; * before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
for (i = 0; i < 3; i++) { * The real fix is that userspace applications should not use DVBv3
c->layer[i].fec = FEC_AUTO; * and not trust on calling FE_SET_FRONTEND to switch the delivery
c->layer[i].modulation = QAM_AUTO; * system.
c->layer[i].interleaving = 0; */
c->layer[i].segment_count = 0; ncaps = 0;
while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
if (fe->ops.delsys[ncaps] == desired_system) {
delsys = desired_system;
break;
} }
ncaps++;
} }
if (delsys == SYS_UNDEFINED) {
dev_dbg(fe->dvb->device, "%s: Couldn't find a delivery system that matches %d\n",
__func__, desired_system);
} }
dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n", return emulate_delivery_system(fe, type, delsys, desired_system);
__func__, c->delivery_system);
return 0;
} }
static int dtv_property_process_set(struct dvb_frontend *fe, static int dtv_property_process_set(struct dvb_frontend *fe,
...@@ -1742,7 +1778,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe, ...@@ -1742,7 +1778,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
c->rolloff = tvp->u.data; c->rolloff = tvp->u.data;
break; break;
case DTV_DELIVERY_SYSTEM: case DTV_DELIVERY_SYSTEM:
r = set_delivery_system(fe, tvp->u.data); r = dvbv5_set_delivery_system(fe, tvp->u.data);
break; break;
case DTV_VOLTAGE: case DTV_VOLTAGE:
c->voltage = tvp->u.data; c->voltage = tvp->u.data;
...@@ -2335,7 +2371,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, ...@@ -2335,7 +2371,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
break; break;
case FE_SET_FRONTEND: case FE_SET_FRONTEND:
err = set_delivery_system(fe, SYS_UNDEFINED); err = dvbv3_set_delivery_system(fe);
if (err) if (err)
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment