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

[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
Loading
Loading
Loading
Loading
+165 −129
Original line number Diff line number Diff line
@@ -1509,81 +1509,78 @@ static bool is_dvbv3_delsys(u32 delsys)
	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;
	u32 delsys = SYS_UNDEFINED;
	int i;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	enum dvbv3_emulation_type type;

	c->delivery_system = delsys;

	/*
	 * It was reported that some old DVBv5 applications were
	 * filling delivery_system with SYS_UNDEFINED. If this happens,
	 * assume that the application wants to use the first supported
	 * delivery system.
	 * 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
	 */
	if (c->delivery_system == SYS_UNDEFINED)
	        c->delivery_system = fe->ops.delsys[0];
	dev_dbg(fe->dvb->device,
		"%s: Using delivery system %d emulated as if it were a %d\n",
		__func__, delsys, desired_system);

	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.
	 * For now, handles ISDB-T calls. More code may be needed here for the
	 * other emulated stuff
	 */
		if (is_dvbv3_delsys(c->delivery_system)) {
	if (type == DVBV3_OFDM) {
		if (c->delivery_system == SYS_ISDBT) {
			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",
					"%s: Using defaults for SYS_ISDBT\n",
					__func__);
			return -EINVAL;

			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;
			}
		/*
		 * 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);
	dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n",
			__func__, c->delivery_system);

	return 0;
}
	} else {

static int dvbv5_set_delivery_system(struct dvb_frontend *fe,
				     u32 desired_system)
{
	int ncaps;
	u32 delsys = SYS_UNDEFINED;
	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
	enum dvbv3_emulation_type type;

	/*
	 * It was reported that some old DVBv5 applications were
	 * filling delivery_system with SYS_UNDEFINED. If this happens,
	 * assume that the application wants to use the first supported
	 * delivery system.
	 */
	if (c->delivery_system == SYS_UNDEFINED)
		c->delivery_system = fe->ops.delsys[0];

	/*
	* This is a DVBv5 call. So, it likely knows the supported
	* delivery systems.
@@ -1601,6 +1598,11 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
		}
		ncaps++;
	}

	/*
	 * Need to emulate a delivery system
	 */

	type = dvbv3_type(desired_system);

	/*
@@ -1611,7 +1613,7 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
	*/
	if (!is_dvbv3_delsys(desired_system)) {
		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__);
		return -EINVAL;
	}
@@ -1634,54 +1636,88 @@ static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
				__func__);
		return -EINVAL;
	}

	return emulate_delivery_system(fe, type, delsys, desired_system);
}

	c->delivery_system = delsys;
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,
	 * 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
	 * 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.
	 */
	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
	 * Trivial case: just use the current one, if it already a DVBv3
	 * delivery system
	 */
	if (type == DVBV3_OFDM) {
		if (c->delivery_system == SYS_ISDBT) {
	if (is_dvbv3_delsys(c->delivery_system)) {
		dev_dbg(fe->dvb->device,
					"%s: Using defaults for SYS_ISDBT\n",
					__func__);
				"%s: Using delivery system to %d\n",
				__func__, c->delivery_system);
		return 0;
	}

			if (!c->bandwidth_hz)
				c->bandwidth_hz = 6000000;
	/* 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;
	}

			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;
	/*
	 * 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);
	}
	dev_dbg(fe->dvb->device, "%s: change delivery system on cache to %d\n",
			__func__, c->delivery_system);

	return 0;
	return emulate_delivery_system(fe, type, delsys, desired_system);
}

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;
		break;
	case DTV_DELIVERY_SYSTEM:
		r = set_delivery_system(fe, tvp->u.data);
		r = dvbv5_set_delivery_system(fe, tvp->u.data);
		break;
	case DTV_VOLTAGE:
		c->voltage = tvp->u.data;
@@ -2335,7 +2371,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
		break;

	case FE_SET_FRONTEND:
		err = set_delivery_system(fe, SYS_UNDEFINED);
		err = dvbv3_set_delivery_system(fe);
		if (err)
			break;